LCOV - code coverage report
Current view: top level - frmts/vrt - pixelfunctions.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 661 736 89.8 %
Date: 2025-03-29 15:49:56 Functions: 41 41 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Implementation of a set of GDALDerivedPixelFunc(s) to be used
       5             :  *           with source raster band of virtual GDAL datasets.
       6             :  * Author:   Antonio Valentino <antonio.valentino@tiscali.it>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2008-2014,2022 Antonio Valentino <antonio.valentino@tiscali.it>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  *****************************************************************************/
      13             : 
      14             : #include <cmath>
      15             : #include "gdal.h"
      16             : #include "vrtdataset.h"
      17             : #include "vrtexpression.h"
      18             : 
      19             : #include <limits>
      20             : 
      21             : template <typename T>
      22    26057400 : inline double GetSrcVal(const void *pSource, GDALDataType eSrcType, T ii)
      23             : {
      24    26057400 :     switch (eSrcType)
      25             :     {
      26           0 :         case GDT_Unknown:
      27           0 :             return 0;
      28       32950 :         case GDT_Byte:
      29       32950 :             return static_cast<const GByte *>(pSource)[ii];
      30           0 :         case GDT_Int8:
      31           0 :             return static_cast<const GInt8 *>(pSource)[ii];
      32           0 :         case GDT_UInt16:
      33           0 :             return static_cast<const GUInt16 *>(pSource)[ii];
      34           0 :         case GDT_Int16:
      35           0 :             return static_cast<const GInt16 *>(pSource)[ii];
      36           0 :         case GDT_UInt32:
      37           0 :             return static_cast<const GUInt32 *>(pSource)[ii];
      38         400 :         case GDT_Int32:
      39         400 :             return static_cast<const GInt32 *>(pSource)[ii];
      40             :         // Precision loss currently for int64/uint64
      41           0 :         case GDT_UInt64:
      42             :             return static_cast<double>(
      43           0 :                 static_cast<const uint64_t *>(pSource)[ii]);
      44           0 :         case GDT_Int64:
      45             :             return static_cast<double>(
      46           0 :                 static_cast<const int64_t *>(pSource)[ii]);
      47           0 :         case GDT_Float16:
      48           0 :             return static_cast<const GFloat16 *>(pSource)[ii];
      49        8636 :         case GDT_Float32:
      50        8636 :             return static_cast<const float *>(pSource)[ii];
      51    25977200 :         case GDT_Float64:
      52    25977200 :             return static_cast<const double *>(pSource)[ii];
      53         360 :         case GDT_CInt16:
      54         360 :             return static_cast<const GInt16 *>(pSource)[2 * ii];
      55           0 :         case GDT_CInt32:
      56           0 :             return static_cast<const GInt32 *>(pSource)[2 * ii];
      57           0 :         case GDT_CFloat16:
      58           0 :             return static_cast<const GFloat16 *>(pSource)[2 * ii];
      59        4660 :         case GDT_CFloat32:
      60        4660 :             return static_cast<const float *>(pSource)[2 * ii];
      61       33250 :         case GDT_CFloat64:
      62       33250 :             return static_cast<const double *>(pSource)[2 * ii];
      63           0 :         case GDT_TypeCount:
      64           0 :             break;
      65             :     }
      66           0 :     return 0;
      67             : }
      68             : 
      69          57 : static CPLErr FetchDoubleArg(CSLConstList papszArgs, const char *pszName,
      70             :                              double *pdfX, double *pdfDefault = nullptr)
      71             : {
      72          57 :     const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
      73             : 
      74          57 :     if (pszVal == nullptr)
      75             :     {
      76          15 :         if (pdfDefault == nullptr)
      77             :         {
      78           0 :             CPLError(CE_Failure, CPLE_AppDefined,
      79             :                      "Missing pixel function argument: %s", pszName);
      80           0 :             return CE_Failure;
      81             :         }
      82             :         else
      83             :         {
      84          15 :             *pdfX = *pdfDefault;
      85          15 :             return CE_None;
      86             :         }
      87             :     }
      88             : 
      89          42 :     char *pszEnd = nullptr;
      90          42 :     *pdfX = std::strtod(pszVal, &pszEnd);
      91          42 :     if (pszEnd == pszVal)
      92             :     {
      93           0 :         CPLError(CE_Failure, CPLE_AppDefined,
      94             :                  "Failed to parse pixel function argument: %s", pszName);
      95           0 :         return CE_Failure;
      96             :     }
      97             : 
      98          42 :     return CE_None;
      99             : }
     100             : 
     101           7 : static CPLErr RealPixelFunc(void **papoSources, int nSources, void *pData,
     102             :                             int nXSize, int nYSize, GDALDataType eSrcType,
     103             :                             GDALDataType eBufType, int nPixelSpace,
     104             :                             int nLineSpace)
     105             : {
     106             :     /* ---- Init ---- */
     107           7 :     if (nSources != 1)
     108           1 :         return CE_Failure;
     109             : 
     110           6 :     const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);
     111           6 :     const size_t nLineSpaceSrc = static_cast<size_t>(nPixelSpaceSrc) * nXSize;
     112             : 
     113             :     /* ---- Set pixels ---- */
     114          98 :     for (int iLine = 0; iLine < nYSize; ++iLine)
     115             :     {
     116          92 :         GDALCopyWords(static_cast<GByte *>(papoSources[0]) +
     117          92 :                           nLineSpaceSrc * iLine,
     118             :                       eSrcType, nPixelSpaceSrc,
     119             :                       static_cast<GByte *>(pData) +
     120          92 :                           static_cast<GSpacing>(nLineSpace) * iLine,
     121             :                       eBufType, nPixelSpace, nXSize);
     122             :     }
     123             : 
     124             :     /* ---- Return success ---- */
     125           6 :     return CE_None;
     126             : }  // RealPixelFunc
     127             : 
     128           8 : static CPLErr ImagPixelFunc(void **papoSources, int nSources, void *pData,
     129             :                             int nXSize, int nYSize, GDALDataType eSrcType,
     130             :                             GDALDataType eBufType, int nPixelSpace,
     131             :                             int nLineSpace)
     132             : {
     133             :     /* ---- Init ---- */
     134           8 :     if (nSources != 1)
     135           1 :         return CE_Failure;
     136             : 
     137           7 :     if (GDALDataTypeIsComplex(eSrcType))
     138             :     {
     139           6 :         const GDALDataType eSrcBaseType = GDALGetNonComplexDataType(eSrcType);
     140           6 :         const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);
     141           6 :         const size_t nLineSpaceSrc =
     142           6 :             static_cast<size_t>(nPixelSpaceSrc) * nXSize;
     143             : 
     144           6 :         const void *const pImag = static_cast<GByte *>(papoSources[0]) +
     145           6 :                                   GDALGetDataTypeSizeBytes(eSrcType) / 2;
     146             : 
     147             :         /* ---- Set pixels ---- */
     148          56 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     149             :         {
     150          50 :             GDALCopyWords(static_cast<const GByte *>(pImag) +
     151          50 :                               nLineSpaceSrc * iLine,
     152             :                           eSrcBaseType, nPixelSpaceSrc,
     153             :                           static_cast<GByte *>(pData) +
     154          50 :                               static_cast<GSpacing>(nLineSpace) * iLine,
     155             :                           eBufType, nPixelSpace, nXSize);
     156             :         }
     157             :     }
     158             :     else
     159             :     {
     160           1 :         const double dfImag = 0;
     161             : 
     162             :         /* ---- Set pixels ---- */
     163          21 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     164             :         {
     165             :             // Always copy from the same location.
     166          20 :             GDALCopyWords(&dfImag, eSrcType, 0,
     167             :                           static_cast<GByte *>(pData) +
     168          20 :                               static_cast<GSpacing>(nLineSpace) * iLine,
     169             :                           eBufType, nPixelSpace, nXSize);
     170             :         }
     171             :     }
     172             : 
     173             :     /* ---- Return success ---- */
     174           7 :     return CE_None;
     175             : }  // ImagPixelFunc
     176             : 
     177           6 : static CPLErr ComplexPixelFunc(void **papoSources, int nSources, void *pData,
     178             :                                int nXSize, int nYSize, GDALDataType eSrcType,
     179             :                                GDALDataType eBufType, int nPixelSpace,
     180             :                                int nLineSpace)
     181             : {
     182             :     /* ---- Init ---- */
     183           6 :     if (nSources != 2)
     184           1 :         return CE_Failure;
     185             : 
     186           5 :     const void *const pReal = papoSources[0];
     187           5 :     const void *const pImag = papoSources[1];
     188             : 
     189             :     /* ---- Set pixels ---- */
     190           5 :     size_t ii = 0;
     191         281 :     for (int iLine = 0; iLine < nYSize; ++iLine)
     192             :     {
     193       17060 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     194             :         {
     195             :             // Source raster pixels may be obtained with GetSrcVal macro.
     196             :             const double adfPixVal[2] = {
     197       16784 :                 GetSrcVal(pReal, eSrcType, ii),  // re
     198       33568 :                 GetSrcVal(pImag, eSrcType, ii)   // im
     199       16784 :             };
     200             : 
     201       16784 :             GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     202             :                           static_cast<GByte *>(pData) +
     203       16784 :                               static_cast<GSpacing>(nLineSpace) * iLine +
     204       16784 :                               iCol * nPixelSpace,
     205             :                           eBufType, nPixelSpace, 1);
     206             :         }
     207             :     }
     208             : 
     209             :     /* ---- Return success ---- */
     210           5 :     return CE_None;
     211             : }  // ComplexPixelFunc
     212             : 
     213             : typedef enum
     214             : {
     215             :     GAT_amplitude,
     216             :     GAT_intensity,
     217             :     GAT_dB
     218             : } PolarAmplitudeType;
     219             : 
     220             : static const char pszPolarPixelFuncMetadata[] =
     221             :     "<PixelFunctionArgumentsList>"
     222             :     "   <Argument name='amplitude_type' description='Amplitude Type' "
     223             :     "type='string-select' default='AMPLITUDE'>"
     224             :     "       <Value>INTENSITY</Value>"
     225             :     "       <Value>dB</Value>"
     226             :     "       <Value>AMPLITUDE</Value>"
     227             :     "   </Argument>"
     228             :     "</PixelFunctionArgumentsList>";
     229             : 
     230           4 : static CPLErr PolarPixelFunc(void **papoSources, int nSources, void *pData,
     231             :                              int nXSize, int nYSize, GDALDataType eSrcType,
     232             :                              GDALDataType eBufType, int nPixelSpace,
     233             :                              int nLineSpace, CSLConstList papszArgs)
     234             : {
     235             :     /* ---- Init ---- */
     236           4 :     if (nSources != 2)
     237           0 :         return CE_Failure;
     238             : 
     239           4 :     const char pszName[] = "amplitude_type";
     240           4 :     const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
     241           4 :     PolarAmplitudeType amplitudeType = GAT_amplitude;
     242           4 :     if (pszVal != nullptr)
     243             :     {
     244           3 :         if (strcmp(pszVal, "INTENSITY") == 0)
     245           1 :             amplitudeType = GAT_intensity;
     246           2 :         else if (strcmp(pszVal, "dB") == 0)
     247           1 :             amplitudeType = GAT_dB;
     248           1 :         else if (strcmp(pszVal, "AMPLITUDE") != 0)
     249             :         {
     250           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     251             :                      "Invalid value for pixel function argument '%s': %s",
     252             :                      pszName, pszVal);
     253           0 :             return CE_Failure;
     254             :         }
     255             :     }
     256             : 
     257           4 :     const void *const pAmp = papoSources[0];
     258           4 :     const void *const pPhase = papoSources[1];
     259             : 
     260             :     /* ---- Set pixels ---- */
     261           4 :     size_t ii = 0;
     262          84 :     for (int iLine = 0; iLine < nYSize; ++iLine)
     263             :     {
     264        1680 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     265             :         {
     266             :             // Source raster pixels may be obtained with GetSrcVal macro.
     267        1600 :             double dfAmp = GetSrcVal(pAmp, eSrcType, ii);
     268        1600 :             switch (amplitudeType)
     269             :             {
     270         400 :                 case GAT_intensity:
     271             :                     // clip to zero
     272         400 :                     dfAmp = dfAmp <= 0 ? 0 : std::sqrt(dfAmp);
     273         400 :                     break;
     274         400 :                 case GAT_dB:
     275         400 :                     dfAmp = dfAmp <= 0
     276         400 :                                 ? -std::numeric_limits<double>::infinity()
     277         400 :                                 : pow(10, dfAmp / 20.);
     278         400 :                     break;
     279         800 :                 case GAT_amplitude:
     280         800 :                     break;
     281             :             }
     282        1600 :             const double dfPhase = GetSrcVal(pPhase, eSrcType, ii);
     283             :             const double adfPixVal[2] = {
     284        1600 :                 dfAmp * std::cos(dfPhase),  // re
     285        1600 :                 dfAmp * std::sin(dfPhase)   // im
     286        1600 :             };
     287             : 
     288        1600 :             GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     289             :                           static_cast<GByte *>(pData) +
     290        1600 :                               static_cast<GSpacing>(nLineSpace) * iLine +
     291        1600 :                               iCol * nPixelSpace,
     292             :                           eBufType, nPixelSpace, 1);
     293             :         }
     294             :     }
     295             : 
     296             :     /* ---- Return success ---- */
     297           4 :     return CE_None;
     298             : }  // PolarPixelFunc
     299             : 
     300           4 : static CPLErr ModulePixelFunc(void **papoSources, int nSources, void *pData,
     301             :                               int nXSize, int nYSize, GDALDataType eSrcType,
     302             :                               GDALDataType eBufType, int nPixelSpace,
     303             :                               int nLineSpace)
     304             : {
     305             :     /* ---- Init ---- */
     306           4 :     if (nSources != 1)
     307           1 :         return CE_Failure;
     308             : 
     309           3 :     if (GDALDataTypeIsComplex(eSrcType))
     310             :     {
     311           2 :         const void *pReal = papoSources[0];
     312           2 :         const void *pImag = static_cast<GByte *>(papoSources[0]) +
     313           2 :                             GDALGetDataTypeSizeBytes(eSrcType) / 2;
     314             : 
     315             :         /* ---- Set pixels ---- */
     316           2 :         size_t ii = 0;
     317          14 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     318             :         {
     319          72 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     320             :             {
     321             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     322          60 :                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);
     323          60 :                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);
     324             : 
     325          60 :                 const double dfPixVal = sqrt(dfReal * dfReal + dfImag * dfImag);
     326             : 
     327          60 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     328             :                               static_cast<GByte *>(pData) +
     329          60 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     330          60 :                                   iCol * nPixelSpace,
     331             :                               eBufType, nPixelSpace, 1);
     332             :             }
     333             :         }
     334             :     }
     335             :     else
     336             :     {
     337             :         /* ---- Set pixels ---- */
     338           1 :         size_t ii = 0;
     339          21 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     340             :         {
     341         420 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     342             :             {
     343             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     344             :                 const double dfPixVal =
     345         400 :                     fabs(GetSrcVal(papoSources[0], eSrcType, ii));
     346             : 
     347         400 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     348             :                               static_cast<GByte *>(pData) +
     349         400 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     350         400 :                                   iCol * nPixelSpace,
     351             :                               eBufType, nPixelSpace, 1);
     352             :             }
     353             :         }
     354             :     }
     355             : 
     356             :     /* ---- Return success ---- */
     357           3 :     return CE_None;
     358             : }  // ModulePixelFunc
     359             : 
     360           5 : static CPLErr PhasePixelFunc(void **papoSources, int nSources, void *pData,
     361             :                              int nXSize, int nYSize, GDALDataType eSrcType,
     362             :                              GDALDataType eBufType, int nPixelSpace,
     363             :                              int nLineSpace)
     364             : {
     365             :     /* ---- Init ---- */
     366           5 :     if (nSources != 1)
     367           1 :         return CE_Failure;
     368             : 
     369           4 :     if (GDALDataTypeIsComplex(eSrcType))
     370             :     {
     371           2 :         const void *const pReal = papoSources[0];
     372           2 :         const void *const pImag = static_cast<GByte *>(papoSources[0]) +
     373           2 :                                   GDALGetDataTypeSizeBytes(eSrcType) / 2;
     374             : 
     375             :         /* ---- Set pixels ---- */
     376           2 :         size_t ii = 0;
     377          14 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     378             :         {
     379          72 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     380             :             {
     381             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     382          60 :                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);
     383          60 :                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);
     384             : 
     385          60 :                 const double dfPixVal = atan2(dfImag, dfReal);
     386             : 
     387          60 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     388             :                               static_cast<GByte *>(pData) +
     389          60 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     390          60 :                                   iCol * nPixelSpace,
     391             :                               eBufType, nPixelSpace, 1);
     392             :             }
     393             :         }
     394             :     }
     395           2 :     else if (GDALDataTypeIsInteger(eSrcType) && !GDALDataTypeIsSigned(eSrcType))
     396             :     {
     397           1 :         constexpr double dfZero = 0;
     398           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     399             :         {
     400           6 :             GDALCopyWords(&dfZero, GDT_Float64, 0,
     401             :                           static_cast<GByte *>(pData) +
     402           6 :                               static_cast<GSpacing>(nLineSpace) * iLine,
     403             :                           eBufType, nPixelSpace, nXSize);
     404             :         }
     405             :     }
     406             :     else
     407             :     {
     408             :         /* ---- Set pixels ---- */
     409           1 :         size_t ii = 0;
     410           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     411             :         {
     412          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     413             :             {
     414          30 :                 const void *const pReal = papoSources[0];
     415             : 
     416             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     417          30 :                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);
     418          30 :                 const double dfPixVal = (dfReal < 0) ? M_PI : 0.0;
     419             : 
     420          30 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     421             :                               static_cast<GByte *>(pData) +
     422          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     423          30 :                                   iCol * nPixelSpace,
     424             :                               eBufType, nPixelSpace, 1);
     425             :             }
     426             :         }
     427             :     }
     428             : 
     429             :     /* ---- Return success ---- */
     430           4 :     return CE_None;
     431             : }  // PhasePixelFunc
     432             : 
     433           4 : static CPLErr ConjPixelFunc(void **papoSources, int nSources, void *pData,
     434             :                             int nXSize, int nYSize, GDALDataType eSrcType,
     435             :                             GDALDataType eBufType, int nPixelSpace,
     436             :                             int nLineSpace)
     437             : {
     438             :     /* ---- Init ---- */
     439           4 :     if (nSources != 1)
     440           1 :         return CE_Failure;
     441             : 
     442           3 :     if (GDALDataTypeIsComplex(eSrcType) && GDALDataTypeIsComplex(eBufType))
     443             :     {
     444           2 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     445           2 :         const void *const pReal = papoSources[0];
     446           2 :         const void *const pImag =
     447           2 :             static_cast<GByte *>(papoSources[0]) + nOffset;
     448             : 
     449             :         /* ---- Set pixels ---- */
     450           2 :         size_t ii = 0;
     451          14 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     452             :         {
     453          72 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     454             :             {
     455             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     456             :                 const double adfPixVal[2] = {
     457          60 :                     +GetSrcVal(pReal, eSrcType, ii),  // re
     458         120 :                     -GetSrcVal(pImag, eSrcType, ii)   // im
     459          60 :                 };
     460             : 
     461          60 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     462             :                               static_cast<GByte *>(pData) +
     463          60 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     464          60 :                                   iCol * nPixelSpace,
     465             :                               eBufType, nPixelSpace, 1);
     466             :             }
     467             :         }
     468             :     }
     469             :     else
     470             :     {
     471             :         // No complex data type.
     472           1 :         return RealPixelFunc(papoSources, nSources, pData, nXSize, nYSize,
     473           1 :                              eSrcType, eBufType, nPixelSpace, nLineSpace);
     474             :     }
     475             : 
     476             :     /* ---- Return success ---- */
     477           2 :     return CE_None;
     478             : }  // ConjPixelFunc
     479             : 
     480             : static const char pszSumPixelFuncMetadata[] =
     481             :     "<PixelFunctionArgumentsList>"
     482             :     "   <Argument name='k' description='Optional constant term' type='double' "
     483             :     "default='0.0' />"
     484             :     "</PixelFunctionArgumentsList>";
     485             : 
     486           4 : static CPLErr SumPixelFunc(void **papoSources, int nSources, void *pData,
     487             :                            int nXSize, int nYSize, GDALDataType eSrcType,
     488             :                            GDALDataType eBufType, int nPixelSpace,
     489             :                            int nLineSpace, CSLConstList papszArgs)
     490             : {
     491             :     /* ---- Init ---- */
     492           4 :     if (nSources < 2)
     493           1 :         return CE_Failure;
     494             : 
     495           3 :     double dfK = 0.0;
     496           3 :     if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
     497           0 :         return CE_Failure;
     498             : 
     499             :     /* ---- Set pixels ---- */
     500           3 :     if (GDALDataTypeIsComplex(eSrcType))
     501             :     {
     502           1 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     503             : 
     504             :         /* ---- Set pixels ---- */
     505           1 :         size_t ii = 0;
     506           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     507             :         {
     508          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     509             :             {
     510          30 :                 double adfSum[2] = {dfK, 0.0};
     511             : 
     512         120 :                 for (int iSrc = 0; iSrc < nSources; ++iSrc)
     513             :                 {
     514          90 :                     const void *const pReal = papoSources[iSrc];
     515          90 :                     const void *const pImag =
     516          90 :                         static_cast<const GByte *>(pReal) + nOffset;
     517             : 
     518             :                     // Source raster pixels may be obtained with GetSrcVal
     519             :                     // macro.
     520          90 :                     adfSum[0] += GetSrcVal(pReal, eSrcType, ii);
     521          90 :                     adfSum[1] += GetSrcVal(pImag, eSrcType, ii);
     522             :                 }
     523             : 
     524          30 :                 GDALCopyWords(adfSum, GDT_CFloat64, 0,
     525             :                               static_cast<GByte *>(pData) +
     526          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     527          30 :                                   iCol * nPixelSpace,
     528             :                               eBufType, nPixelSpace, 1);
     529             :             }
     530             :         }
     531             :     }
     532             :     else
     533             :     {
     534             :         /* ---- Set pixels ---- */
     535           2 :         size_t ii = 0;
     536          42 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     537             :         {
     538         840 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     539             :             {
     540         800 :                 double dfSum = dfK;  // Not complex.
     541             : 
     542        3200 :                 for (int iSrc = 0; iSrc < nSources; ++iSrc)
     543             :                 {
     544             :                     // Source raster pixels may be obtained with GetSrcVal
     545             :                     // macro.
     546        2400 :                     dfSum += GetSrcVal(papoSources[iSrc], eSrcType, ii);
     547             :                 }
     548             : 
     549         800 :                 GDALCopyWords(&dfSum, GDT_Float64, 0,
     550             :                               static_cast<GByte *>(pData) +
     551         800 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     552         800 :                                   iCol * nPixelSpace,
     553             :                               eBufType, nPixelSpace, 1);
     554             :             }
     555             :         }
     556             :     }
     557             : 
     558             :     /* ---- Return success ---- */
     559           3 :     return CE_None;
     560             : } /* SumPixelFunc */
     561             : 
     562           3 : static CPLErr DiffPixelFunc(void **papoSources, int nSources, void *pData,
     563             :                             int nXSize, int nYSize, GDALDataType eSrcType,
     564             :                             GDALDataType eBufType, int nPixelSpace,
     565             :                             int nLineSpace)
     566             : {
     567             :     /* ---- Init ---- */
     568           3 :     if (nSources != 2)
     569           1 :         return CE_Failure;
     570             : 
     571           2 :     if (GDALDataTypeIsComplex(eSrcType))
     572             :     {
     573           1 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     574           1 :         const void *const pReal0 = papoSources[0];
     575           1 :         const void *const pImag0 =
     576           1 :             static_cast<GByte *>(papoSources[0]) + nOffset;
     577           1 :         const void *const pReal1 = papoSources[1];
     578           1 :         const void *const pImag1 =
     579           1 :             static_cast<GByte *>(papoSources[1]) + nOffset;
     580             : 
     581             :         /* ---- Set pixels ---- */
     582           1 :         size_t ii = 0;
     583           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     584             :         {
     585          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     586             :             {
     587             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     588          30 :                 double adfPixVal[2] = {GetSrcVal(pReal0, eSrcType, ii) -
     589          30 :                                            GetSrcVal(pReal1, eSrcType, ii),
     590          90 :                                        GetSrcVal(pImag0, eSrcType, ii) -
     591          30 :                                            GetSrcVal(pImag1, eSrcType, ii)};
     592             : 
     593          30 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     594             :                               static_cast<GByte *>(pData) +
     595          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     596          30 :                                   iCol * nPixelSpace,
     597             :                               eBufType, nPixelSpace, 1);
     598             :             }
     599             :         }
     600             :     }
     601             :     else
     602             :     {
     603             :         /* ---- Set pixels ---- */
     604           1 :         size_t ii = 0;
     605           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     606             :         {
     607          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     608             :             {
     609             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     610             :                 // Not complex.
     611             :                 const double dfPixVal =
     612          30 :                     GetSrcVal(papoSources[0], eSrcType, ii) -
     613          30 :                     GetSrcVal(papoSources[1], eSrcType, ii);
     614             : 
     615          30 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     616             :                               static_cast<GByte *>(pData) +
     617          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     618          30 :                                   iCol * nPixelSpace,
     619             :                               eBufType, nPixelSpace, 1);
     620             :             }
     621             :         }
     622             :     }
     623             : 
     624             :     /* ---- Return success ---- */
     625           2 :     return CE_None;
     626             : }  // DiffPixelFunc
     627             : 
     628             : static const char pszMulPixelFuncMetadata[] =
     629             :     "<PixelFunctionArgumentsList>"
     630             :     "   <Argument name='k' description='Optional constant factor' "
     631             :     "type='double' default='1.0' />"
     632             :     "</PixelFunctionArgumentsList>";
     633             : 
     634           4 : static CPLErr MulPixelFunc(void **papoSources, int nSources, void *pData,
     635             :                            int nXSize, int nYSize, GDALDataType eSrcType,
     636             :                            GDALDataType eBufType, int nPixelSpace,
     637             :                            int nLineSpace, CSLConstList papszArgs)
     638             : {
     639             :     /* ---- Init ---- */
     640           4 :     if (nSources < 2)
     641           1 :         return CE_Failure;
     642             : 
     643           3 :     double dfK = 1.0;
     644           3 :     if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
     645           0 :         return CE_Failure;
     646             : 
     647             :     /* ---- Set pixels ---- */
     648           3 :     if (GDALDataTypeIsComplex(eSrcType))
     649             :     {
     650           1 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     651             : 
     652             :         /* ---- Set pixels ---- */
     653           1 :         size_t ii = 0;
     654           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     655             :         {
     656          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     657             :             {
     658          30 :                 double adfPixVal[2] = {dfK, 0.0};
     659             : 
     660          90 :                 for (int iSrc = 0; iSrc < nSources; ++iSrc)
     661             :                 {
     662          60 :                     const void *const pReal = papoSources[iSrc];
     663          60 :                     const void *const pImag =
     664          60 :                         static_cast<const GByte *>(pReal) + nOffset;
     665             : 
     666          60 :                     const double dfOldR = adfPixVal[0];
     667          60 :                     const double dfOldI = adfPixVal[1];
     668             : 
     669             :                     // Source raster pixels may be obtained with GetSrcVal
     670             :                     // macro.
     671          60 :                     const double dfNewR = GetSrcVal(pReal, eSrcType, ii);
     672          60 :                     const double dfNewI = GetSrcVal(pImag, eSrcType, ii);
     673             : 
     674          60 :                     adfPixVal[0] = dfOldR * dfNewR - dfOldI * dfNewI;
     675          60 :                     adfPixVal[1] = dfOldR * dfNewI + dfOldI * dfNewR;
     676             :                 }
     677             : 
     678          30 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     679             :                               static_cast<GByte *>(pData) +
     680          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     681          30 :                                   iCol * nPixelSpace,
     682             :                               eBufType, nPixelSpace, 1);
     683             :             }
     684             :         }
     685             :     }
     686             :     else
     687             :     {
     688             :         /* ---- Set pixels ---- */
     689           2 :         size_t ii = 0;
     690          42 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     691             :         {
     692         840 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     693             :             {
     694         800 :                 double dfPixVal = dfK;  // Not complex.
     695             : 
     696        3200 :                 for (int iSrc = 0; iSrc < nSources; ++iSrc)
     697             :                 {
     698             :                     // Source raster pixels may be obtained with GetSrcVal
     699             :                     // macro.
     700        2400 :                     dfPixVal *= GetSrcVal(papoSources[iSrc], eSrcType, ii);
     701             :                 }
     702             : 
     703         800 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     704             :                               static_cast<GByte *>(pData) +
     705         800 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     706         800 :                                   iCol * nPixelSpace,
     707             :                               eBufType, nPixelSpace, 1);
     708             :             }
     709             :         }
     710             :     }
     711             : 
     712             :     /* ---- Return success ---- */
     713           3 :     return CE_None;
     714             : }  // MulPixelFunc
     715             : 
     716           2 : static CPLErr DivPixelFunc(void **papoSources, int nSources, void *pData,
     717             :                            int nXSize, int nYSize, GDALDataType eSrcType,
     718             :                            GDALDataType eBufType, int nPixelSpace,
     719             :                            int nLineSpace)
     720             : {
     721             :     /* ---- Init ---- */
     722           2 :     if (nSources != 2)
     723           0 :         return CE_Failure;
     724             : 
     725             :     /* ---- Set pixels ---- */
     726           2 :     if (GDALDataTypeIsComplex(eSrcType))
     727             :     {
     728           1 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     729           1 :         const void *const pReal0 = papoSources[0];
     730           1 :         const void *const pImag0 =
     731           1 :             static_cast<GByte *>(papoSources[0]) + nOffset;
     732           1 :         const void *const pReal1 = papoSources[1];
     733           1 :         const void *const pImag1 =
     734           1 :             static_cast<GByte *>(papoSources[1]) + nOffset;
     735             : 
     736             :         /* ---- Set pixels ---- */
     737           1 :         size_t ii = 0;
     738           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     739             :         {
     740          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     741             :             {
     742             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     743          30 :                 const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);
     744          30 :                 const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);
     745          30 :                 const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);
     746          30 :                 const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);
     747          30 :                 const double dfAux = dfReal1 * dfReal1 + dfImag1 * dfImag1;
     748             : 
     749             :                 const double adfPixVal[2] = {
     750             :                     dfAux == 0
     751          30 :                         ? std::numeric_limits<double>::infinity()
     752          30 :                         : dfReal0 * dfReal1 / dfAux + dfImag0 * dfImag1 / dfAux,
     753           0 :                     dfAux == 0 ? std::numeric_limits<double>::infinity()
     754          30 :                                : dfReal1 / dfAux * dfImag0 -
     755          30 :                                      dfReal0 * dfImag1 / dfAux};
     756             : 
     757          30 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     758             :                               static_cast<GByte *>(pData) +
     759          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     760          30 :                                   iCol * nPixelSpace,
     761             :                               eBufType, nPixelSpace, 1);
     762             :             }
     763             :         }
     764             :     }
     765             :     else
     766             :     {
     767             :         /* ---- Set pixels ---- */
     768           1 :         size_t ii = 0;
     769           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     770             :         {
     771          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     772             :             {
     773          30 :                 const double dfVal = GetSrcVal(papoSources[1], eSrcType, ii);
     774             :                 // coverity[divide_by_zero]
     775             :                 double dfPixVal =
     776             :                     dfVal == 0
     777          30 :                         ? std::numeric_limits<double>::infinity()
     778          30 :                         : GetSrcVal(papoSources[0], eSrcType, ii) / dfVal;
     779             : 
     780          30 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     781             :                               static_cast<GByte *>(pData) +
     782          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     783          30 :                                   iCol * nPixelSpace,
     784             :                               eBufType, nPixelSpace, 1);
     785             :             }
     786             :         }
     787             :     }
     788             : 
     789             :     /* ---- Return success ---- */
     790           2 :     return CE_None;
     791             : }  // DivPixelFunc
     792             : 
     793           3 : static CPLErr CMulPixelFunc(void **papoSources, int nSources, void *pData,
     794             :                             int nXSize, int nYSize, GDALDataType eSrcType,
     795             :                             GDALDataType eBufType, int nPixelSpace,
     796             :                             int nLineSpace)
     797             : {
     798             :     /* ---- Init ---- */
     799           3 :     if (nSources != 2)
     800           1 :         return CE_Failure;
     801             : 
     802             :     /* ---- Set pixels ---- */
     803           2 :     if (GDALDataTypeIsComplex(eSrcType))
     804             :     {
     805           1 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     806           1 :         const void *const pReal0 = papoSources[0];
     807           1 :         const void *const pImag0 =
     808           1 :             static_cast<GByte *>(papoSources[0]) + nOffset;
     809           1 :         const void *const pReal1 = papoSources[1];
     810           1 :         const void *const pImag1 =
     811           1 :             static_cast<GByte *>(papoSources[1]) + nOffset;
     812             : 
     813           1 :         size_t ii = 0;
     814           7 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     815             :         {
     816          36 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     817             :             {
     818             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     819          30 :                 const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);
     820          30 :                 const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);
     821          30 :                 const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);
     822          30 :                 const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);
     823             :                 const double adfPixVal[2] = {
     824          30 :                     dfReal0 * dfReal1 + dfImag0 * dfImag1,
     825          30 :                     dfReal1 * dfImag0 - dfReal0 * dfImag1};
     826             : 
     827          30 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     828             :                               static_cast<GByte *>(pData) +
     829          30 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     830          30 :                                   iCol * nPixelSpace,
     831             :                               eBufType, nPixelSpace, 1);
     832             :             }
     833             :         }
     834             :     }
     835             :     else
     836             :     {
     837           1 :         size_t ii = 0;
     838          21 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     839             :         {
     840         420 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     841             :             {
     842             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     843             :                 // Not complex.
     844         400 :                 const double adfPixVal[2] = {
     845         400 :                     GetSrcVal(papoSources[0], eSrcType, ii) *
     846         400 :                         GetSrcVal(papoSources[1], eSrcType, ii),
     847         400 :                     0.0};
     848             : 
     849         400 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     850             :                               static_cast<GByte *>(pData) +
     851         400 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     852         400 :                                   iCol * nPixelSpace,
     853             :                               eBufType, nPixelSpace, 1);
     854             :             }
     855             :         }
     856             :     }
     857             : 
     858             :     /* ---- Return success ---- */
     859           2 :     return CE_None;
     860             : }  // CMulPixelFunc
     861             : 
     862             : static const char pszInvPixelFuncMetadata[] =
     863             :     "<PixelFunctionArgumentsList>"
     864             :     "   <Argument name='k' description='Optional constant factor' "
     865             :     "type='double' default='1.0' />"
     866             :     "</PixelFunctionArgumentsList>";
     867             : 
     868           6 : static CPLErr InvPixelFunc(void **papoSources, int nSources, void *pData,
     869             :                            int nXSize, int nYSize, GDALDataType eSrcType,
     870             :                            GDALDataType eBufType, int nPixelSpace,
     871             :                            int nLineSpace, CSLConstList papszArgs)
     872             : {
     873             :     /* ---- Init ---- */
     874           6 :     if (nSources != 1)
     875           1 :         return CE_Failure;
     876             : 
     877           5 :     double dfK = 1.0;
     878           5 :     if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
     879           0 :         return CE_Failure;
     880             : 
     881             :     /* ---- Set pixels ---- */
     882           5 :     if (GDALDataTypeIsComplex(eSrcType))
     883             :     {
     884           2 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     885           2 :         const void *const pReal = papoSources[0];
     886           2 :         const void *const pImag =
     887           2 :             static_cast<GByte *>(papoSources[0]) + nOffset;
     888             : 
     889           2 :         size_t ii = 0;
     890           9 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     891             :         {
     892          38 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     893             :             {
     894             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     895          31 :                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);
     896          31 :                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);
     897          31 :                 const double dfAux = dfReal * dfReal + dfImag * dfImag;
     898             :                 const double adfPixVal[2] = {
     899          31 :                     dfAux == 0 ? std::numeric_limits<double>::infinity()
     900          30 :                                : dfK * dfReal / dfAux,
     901           1 :                     dfAux == 0 ? std::numeric_limits<double>::infinity()
     902          31 :                                : -dfK * dfImag / dfAux};
     903             : 
     904          31 :                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
     905             :                               static_cast<GByte *>(pData) +
     906          31 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     907          31 :                                   iCol * nPixelSpace,
     908             :                               eBufType, nPixelSpace, 1);
     909             :             }
     910             :         }
     911             :     }
     912             :     else
     913             :     {
     914             :         /* ---- Set pixels ---- */
     915           3 :         size_t ii = 0;
     916          44 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     917             :         {
     918         842 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     919             :             {
     920             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     921             :                 // Not complex.
     922         801 :                 const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
     923             :                 // coverity[divide_by_zero]
     924             :                 const double dfPixVal =
     925         801 :                     dfVal == 0 ? std::numeric_limits<double>::infinity()
     926         800 :                                : dfK / dfVal;
     927             : 
     928         801 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     929             :                               static_cast<GByte *>(pData) +
     930         801 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     931         801 :                                   iCol * nPixelSpace,
     932             :                               eBufType, nPixelSpace, 1);
     933             :             }
     934             :         }
     935             :     }
     936             : 
     937             :     /* ---- Return success ---- */
     938           5 :     return CE_None;
     939             : }  // InvPixelFunc
     940             : 
     941           4 : static CPLErr IntensityPixelFunc(void **papoSources, int nSources, void *pData,
     942             :                                  int nXSize, int nYSize, GDALDataType eSrcType,
     943             :                                  GDALDataType eBufType, int nPixelSpace,
     944             :                                  int nLineSpace)
     945             : {
     946             :     /* ---- Init ---- */
     947           4 :     if (nSources != 1)
     948           1 :         return CE_Failure;
     949             : 
     950           3 :     if (GDALDataTypeIsComplex(eSrcType))
     951             :     {
     952           2 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
     953           2 :         const void *const pReal = papoSources[0];
     954           2 :         const void *const pImag =
     955           2 :             static_cast<GByte *>(papoSources[0]) + nOffset;
     956             : 
     957             :         /* ---- Set pixels ---- */
     958           2 :         size_t ii = 0;
     959          14 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     960             :         {
     961          72 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     962             :             {
     963             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     964          60 :                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);
     965          60 :                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);
     966             : 
     967          60 :                 const double dfPixVal = dfReal * dfReal + dfImag * dfImag;
     968             : 
     969          60 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     970             :                               static_cast<GByte *>(pData) +
     971          60 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     972          60 :                                   iCol * nPixelSpace,
     973             :                               eBufType, nPixelSpace, 1);
     974             :             }
     975             :         }
     976             :     }
     977             :     else
     978             :     {
     979             :         /* ---- Set pixels ---- */
     980           1 :         size_t ii = 0;
     981          21 :         for (int iLine = 0; iLine < nYSize; ++iLine)
     982             :         {
     983         420 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
     984             :             {
     985             :                 // Source raster pixels may be obtained with GetSrcVal macro.
     986         400 :                 double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
     987         400 :                 dfPixVal *= dfPixVal;
     988             : 
     989         400 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
     990             :                               static_cast<GByte *>(pData) +
     991         400 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
     992         400 :                                   iCol * nPixelSpace,
     993             :                               eBufType, nPixelSpace, 1);
     994             :             }
     995             :         }
     996             :     }
     997             : 
     998             :     /* ---- Return success ---- */
     999           3 :     return CE_None;
    1000             : }  // IntensityPixelFunc
    1001             : 
    1002           2 : static CPLErr SqrtPixelFunc(void **papoSources, int nSources, void *pData,
    1003             :                             int nXSize, int nYSize, GDALDataType eSrcType,
    1004             :                             GDALDataType eBufType, int nPixelSpace,
    1005             :                             int nLineSpace)
    1006             : {
    1007             :     /* ---- Init ---- */
    1008           2 :     if (nSources != 1)
    1009           1 :         return CE_Failure;
    1010           1 :     if (GDALDataTypeIsComplex(eSrcType))
    1011           0 :         return CE_Failure;
    1012             : 
    1013             :     /* ---- Set pixels ---- */
    1014           1 :     size_t ii = 0;
    1015          21 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1016             :     {
    1017         420 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1018             :         {
    1019             :             // Source raster pixels may be obtained with GetSrcVal macro.
    1020             :             const double dfPixVal =
    1021         400 :                 sqrt(GetSrcVal(papoSources[0], eSrcType, ii));
    1022             : 
    1023         400 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1024             :                           static_cast<GByte *>(pData) +
    1025         400 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1026         400 :                               iCol * nPixelSpace,
    1027             :                           eBufType, nPixelSpace, 1);
    1028             :         }
    1029             :     }
    1030             : 
    1031             :     /* ---- Return success ---- */
    1032           1 :     return CE_None;
    1033             : }  // SqrtPixelFunc
    1034             : 
    1035          11 : static CPLErr Log10PixelFuncHelper(void **papoSources, int nSources,
    1036             :                                    void *pData, int nXSize, int nYSize,
    1037             :                                    GDALDataType eSrcType, GDALDataType eBufType,
    1038             :                                    int nPixelSpace, int nLineSpace, double fact)
    1039             : {
    1040             :     /* ---- Init ---- */
    1041          11 :     if (nSources != 1)
    1042           2 :         return CE_Failure;
    1043             : 
    1044           9 :     if (GDALDataTypeIsComplex(eSrcType))
    1045             :     {
    1046             :         // Complex input datatype.
    1047           5 :         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
    1048           5 :         const void *const pReal = papoSources[0];
    1049           5 :         const void *const pImag =
    1050           5 :             static_cast<GByte *>(papoSources[0]) + nOffset;
    1051             : 
    1052             :         /* We should compute fact * log10( sqrt( dfReal * dfReal + dfImag *
    1053             :          * dfImag ) ) */
    1054             :         /* Given that log10(sqrt(x)) = 0.5 * log10(x) */
    1055             :         /* we can remove the sqrt() by multiplying fact by 0.5 */
    1056           5 :         fact *= 0.5;
    1057             : 
    1058             :         /* ---- Set pixels ---- */
    1059           5 :         size_t ii = 0;
    1060          35 :         for (int iLine = 0; iLine < nYSize; ++iLine)
    1061             :         {
    1062         180 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1063             :             {
    1064             :                 // Source raster pixels may be obtained with GetSrcVal macro.
    1065         150 :                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);
    1066         150 :                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);
    1067             : 
    1068             :                 const double dfPixVal =
    1069         150 :                     fact * log10(dfReal * dfReal + dfImag * dfImag);
    1070             : 
    1071         150 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1072             :                               static_cast<GByte *>(pData) +
    1073         150 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
    1074         150 :                                   iCol * nPixelSpace,
    1075             :                               eBufType, nPixelSpace, 1);
    1076             :             }
    1077             :         }
    1078             :     }
    1079             :     else
    1080             :     {
    1081             :         /* ---- Set pixels ---- */
    1082           4 :         size_t ii = 0;
    1083          84 :         for (int iLine = 0; iLine < nYSize; ++iLine)
    1084             :         {
    1085        1680 :             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1086             :             {
    1087             :                 // Source raster pixels may be obtained with GetSrcVal macro.
    1088             :                 const double dfPixVal =
    1089        1600 :                     fact * log10(fabs(GetSrcVal(papoSources[0], eSrcType, ii)));
    1090             : 
    1091        1600 :                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1092             :                               static_cast<GByte *>(pData) +
    1093        1600 :                                   static_cast<GSpacing>(nLineSpace) * iLine +
    1094        1600 :                                   iCol * nPixelSpace,
    1095             :                               eBufType, nPixelSpace, 1);
    1096             :             }
    1097             :         }
    1098             :     }
    1099             : 
    1100             :     /* ---- Return success ---- */
    1101           9 :     return CE_None;
    1102             : }  // Log10PixelFuncHelper
    1103             : 
    1104           4 : static CPLErr Log10PixelFunc(void **papoSources, int nSources, void *pData,
    1105             :                              int nXSize, int nYSize, GDALDataType eSrcType,
    1106             :                              GDALDataType eBufType, int nPixelSpace,
    1107             :                              int nLineSpace)
    1108             : {
    1109           4 :     return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
    1110             :                                 eSrcType, eBufType, nPixelSpace, nLineSpace,
    1111           4 :                                 1.0);
    1112             : }  // Log10PixelFunc
    1113             : 
    1114             : static const char pszDBPixelFuncMetadata[] =
    1115             :     "<PixelFunctionArgumentsList>"
    1116             :     "   <Argument name='fact' description='Factor' type='double' "
    1117             :     "default='20.0' />"
    1118             :     "</PixelFunctionArgumentsList>";
    1119             : 
    1120           7 : static CPLErr DBPixelFunc(void **papoSources, int nSources, void *pData,
    1121             :                           int nXSize, int nYSize, GDALDataType eSrcType,
    1122             :                           GDALDataType eBufType, int nPixelSpace,
    1123             :                           int nLineSpace, CSLConstList papszArgs)
    1124             : {
    1125           7 :     double dfFact = 20.;
    1126           7 :     if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)
    1127           0 :         return CE_Failure;
    1128             : 
    1129           7 :     return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
    1130             :                                 eSrcType, eBufType, nPixelSpace, nLineSpace,
    1131           7 :                                 dfFact);
    1132             : }  // DBPixelFunc
    1133             : 
    1134           7 : static CPLErr ExpPixelFuncHelper(void **papoSources, int nSources, void *pData,
    1135             :                                  int nXSize, int nYSize, GDALDataType eSrcType,
    1136             :                                  GDALDataType eBufType, int nPixelSpace,
    1137             :                                  int nLineSpace, double base, double fact)
    1138             : {
    1139             :     /* ---- Init ---- */
    1140           7 :     if (nSources != 1)
    1141           2 :         return CE_Failure;
    1142           5 :     if (GDALDataTypeIsComplex(eSrcType))
    1143           0 :         return CE_Failure;
    1144             : 
    1145             :     /* ---- Set pixels ---- */
    1146           5 :     size_t ii = 0;
    1147         105 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1148             :     {
    1149        2100 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1150             :         {
    1151             :             // Source raster pixels may be obtained with GetSrcVal macro.
    1152             :             const double dfPixVal =
    1153        2000 :                 pow(base, GetSrcVal(papoSources[0], eSrcType, ii) * fact);
    1154             : 
    1155        2000 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1156             :                           static_cast<GByte *>(pData) +
    1157        2000 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1158        2000 :                               iCol * nPixelSpace,
    1159             :                           eBufType, nPixelSpace, 1);
    1160             :         }
    1161             :     }
    1162             : 
    1163             :     /* ---- Return success ---- */
    1164           5 :     return CE_None;
    1165             : }  // ExpPixelFuncHelper
    1166             : 
    1167             : static const char pszExpPixelFuncMetadata[] =
    1168             :     "<PixelFunctionArgumentsList>"
    1169             :     "   <Argument name='base' description='Base' type='double' "
    1170             :     "default='2.7182818284590452353602874713526624' />"
    1171             :     "   <Argument name='fact' description='Factor' type='double' default='1' />"
    1172             :     "</PixelFunctionArgumentsList>";
    1173             : 
    1174           3 : static CPLErr ExpPixelFunc(void **papoSources, int nSources, void *pData,
    1175             :                            int nXSize, int nYSize, GDALDataType eSrcType,
    1176             :                            GDALDataType eBufType, int nPixelSpace,
    1177             :                            int nLineSpace, CSLConstList papszArgs)
    1178             : {
    1179           3 :     double dfBase = 2.7182818284590452353602874713526624;
    1180           3 :     double dfFact = 1.;
    1181             : 
    1182           3 :     if (FetchDoubleArg(papszArgs, "base", &dfBase, &dfBase) != CE_None)
    1183           0 :         return CE_Failure;
    1184             : 
    1185           3 :     if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)
    1186           0 :         return CE_Failure;
    1187             : 
    1188           3 :     return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
    1189             :                               eSrcType, eBufType, nPixelSpace, nLineSpace,
    1190           3 :                               dfBase, dfFact);
    1191             : }  // ExpPixelFunc
    1192             : 
    1193           2 : static CPLErr dB2AmpPixelFunc(void **papoSources, int nSources, void *pData,
    1194             :                               int nXSize, int nYSize, GDALDataType eSrcType,
    1195             :                               GDALDataType eBufType, int nPixelSpace,
    1196             :                               int nLineSpace)
    1197             : {
    1198           2 :     return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
    1199             :                               eSrcType, eBufType, nPixelSpace, nLineSpace, 10.0,
    1200           2 :                               1. / 20);
    1201             : }  // dB2AmpPixelFunc
    1202             : 
    1203           2 : static CPLErr dB2PowPixelFunc(void **papoSources, int nSources, void *pData,
    1204             :                               int nXSize, int nYSize, GDALDataType eSrcType,
    1205             :                               GDALDataType eBufType, int nPixelSpace,
    1206             :                               int nLineSpace)
    1207             : {
    1208           2 :     return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
    1209             :                               eSrcType, eBufType, nPixelSpace, nLineSpace, 10.0,
    1210           2 :                               1. / 10);
    1211             : }  // dB2PowPixelFunc
    1212             : 
    1213             : static const char pszPowPixelFuncMetadata[] =
    1214             :     "<PixelFunctionArgumentsList>"
    1215             :     "   <Argument name='power' description='Exponent' type='double' "
    1216             :     "mandatory='1' />"
    1217             :     "</PixelFunctionArgumentsList>";
    1218             : 
    1219           1 : static CPLErr PowPixelFunc(void **papoSources, int nSources, void *pData,
    1220             :                            int nXSize, int nYSize, GDALDataType eSrcType,
    1221             :                            GDALDataType eBufType, int nPixelSpace,
    1222             :                            int nLineSpace, CSLConstList papszArgs)
    1223             : {
    1224             :     /* ---- Init ---- */
    1225           1 :     if (nSources != 1)
    1226           0 :         return CE_Failure;
    1227           1 :     if (GDALDataTypeIsComplex(eSrcType))
    1228           0 :         return CE_Failure;
    1229             : 
    1230             :     double power;
    1231           1 :     if (FetchDoubleArg(papszArgs, "power", &power) != CE_None)
    1232           0 :         return CE_Failure;
    1233             : 
    1234             :     /* ---- Set pixels ---- */
    1235           1 :     size_t ii = 0;
    1236          21 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1237             :     {
    1238         420 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1239             :         {
    1240             :             const double dfPixVal =
    1241         400 :                 std::pow(GetSrcVal(papoSources[0], eSrcType, ii), power);
    1242             : 
    1243         400 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1244             :                           static_cast<GByte *>(pData) +
    1245         400 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1246         400 :                               iCol * nPixelSpace,
    1247             :                           eBufType, nPixelSpace, 1);
    1248             :         }
    1249             :     }
    1250             : 
    1251             :     /* ---- Return success ---- */
    1252           1 :     return CE_None;
    1253             : }
    1254             : 
    1255             : // Given nt intervals spaced by dt and beginning at t0, return the index of
    1256             : // the lower bound of the interval that should be used to
    1257             : // interpolate/extrapolate a value for t.
    1258           7 : static std::size_t intervalLeft(double t0, double dt, std::size_t nt, double t)
    1259             : {
    1260           7 :     if (t < t0)
    1261             :     {
    1262           2 :         return 0;
    1263             :     }
    1264             : 
    1265           5 :     std::size_t n = static_cast<std::size_t>((t - t0) / dt);
    1266             : 
    1267           5 :     if (n >= nt - 1)
    1268             :     {
    1269           3 :         return nt - 2;
    1270             :     }
    1271             : 
    1272           2 :     return n;
    1273             : }
    1274             : 
    1275          16 : static double InterpolateLinear(double dfX0, double dfX1, double dfY0,
    1276             :                                 double dfY1, double dfX)
    1277             : {
    1278          16 :     return dfY0 + (dfX - dfX0) * (dfY1 - dfY0) / (dfX1 - dfX0);
    1279             : }
    1280             : 
    1281          12 : static double InterpolateExponential(double dfX0, double dfX1, double dfY0,
    1282             :                                      double dfY1, double dfX)
    1283             : {
    1284          12 :     const double r = std::log(dfY1 / dfY0) / (dfX1 - dfX0);
    1285          12 :     return dfY0 * std::exp(r * (dfX - dfX0));
    1286             : }
    1287             : 
    1288             : static const char pszInterpolatePixelFuncMetadata[] =
    1289             :     "<PixelFunctionArgumentsList>"
    1290             :     "   <Argument name='t0' description='t0' type='double' mandatory='1' />"
    1291             :     "   <Argument name='dt' description='dt' type='double' mandatory='1' />"
    1292             :     "   <Argument name='t' description='t' type='double' mandatory='1' />"
    1293             :     "</PixelFunctionArgumentsList>";
    1294             : 
    1295             : template <decltype(InterpolateLinear) InterpolationFunction>
    1296           7 : CPLErr InterpolatePixelFunc(void **papoSources, int nSources, void *pData,
    1297             :                             int nXSize, int nYSize, GDALDataType eSrcType,
    1298             :                             GDALDataType eBufType, int nPixelSpace,
    1299             :                             int nLineSpace, CSLConstList papszArgs)
    1300             : {
    1301             :     /* ---- Init ---- */
    1302           7 :     if (GDALDataTypeIsComplex(eSrcType))
    1303           0 :         return CE_Failure;
    1304             : 
    1305             :     double dfT0;
    1306           7 :     if (FetchDoubleArg(papszArgs, "t0", &dfT0) == CE_Failure)
    1307           0 :         return CE_Failure;
    1308             : 
    1309             :     double dfT;
    1310           7 :     if (FetchDoubleArg(papszArgs, "t", &dfT) == CE_Failure)
    1311           0 :         return CE_Failure;
    1312             : 
    1313             :     double dfDt;
    1314           7 :     if (FetchDoubleArg(papszArgs, "dt", &dfDt) == CE_Failure)
    1315           0 :         return CE_Failure;
    1316             : 
    1317           7 :     if (nSources < 2)
    1318             :     {
    1319           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1320             :                  "At least two sources required for interpolation.");
    1321           0 :         return CE_Failure;
    1322             :     }
    1323             : 
    1324           7 :     if (dfT == 0 || !std::isfinite(dfT))
    1325             :     {
    1326           0 :         CPLError(CE_Failure, CPLE_AppDefined, "dt must be finite and non-zero");
    1327           0 :         return CE_Failure;
    1328             :     }
    1329             : 
    1330           7 :     const auto i0 = intervalLeft(dfT0, dfDt, nSources, dfT);
    1331           7 :     const auto i1 = i0 + 1;
    1332           7 :     dfT0 = dfT0 + static_cast<double>(i0) * dfDt;
    1333           7 :     double dfX1 = dfT0 + dfDt;
    1334             : 
    1335             :     /* ---- Set pixels ---- */
    1336           7 :     size_t ii = 0;
    1337          21 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1338             :     {
    1339          42 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1340             :         {
    1341          28 :             const double dfY0 = GetSrcVal(papoSources[i0], eSrcType, ii);
    1342          28 :             const double dfY1 = GetSrcVal(papoSources[i1], eSrcType, ii);
    1343             : 
    1344          28 :             const double dfPixVal =
    1345          28 :                 InterpolationFunction(dfT0, dfX1, dfY0, dfY1, dfT);
    1346             : 
    1347          28 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1348             :                           static_cast<GByte *>(pData) +
    1349          28 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1350          28 :                               iCol * nPixelSpace,
    1351             :                           eBufType, nPixelSpace, 1);
    1352             :         }
    1353             :     }
    1354             : 
    1355             :     /* ---- Return success ---- */
    1356           7 :     return CE_None;
    1357             : }
    1358             : 
    1359             : static const char pszReplaceNoDataPixelFuncMetadata[] =
    1360             :     "<PixelFunctionArgumentsList>"
    1361             :     "   <Argument type='builtin' value='NoData' />"
    1362             :     "   <Argument name='to' type='double' description='New NoData value to be "
    1363             :     "replaced' default='nan' />"
    1364             :     "</PixelFunctionArgumentsList>";
    1365             : 
    1366           2 : static CPLErr ReplaceNoDataPixelFunc(void **papoSources, int nSources,
    1367             :                                      void *pData, int nXSize, int nYSize,
    1368             :                                      GDALDataType eSrcType,
    1369             :                                      GDALDataType eBufType, int nPixelSpace,
    1370             :                                      int nLineSpace, CSLConstList papszArgs)
    1371             : {
    1372             :     /* ---- Init ---- */
    1373           2 :     if (nSources != 1)
    1374           0 :         return CE_Failure;
    1375           2 :     if (GDALDataTypeIsComplex(eSrcType))
    1376             :     {
    1377           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1378             :                  "replace_nodata cannot convert complex data types");
    1379           0 :         return CE_Failure;
    1380             :     }
    1381             : 
    1382           2 :     double dfOldNoData, dfNewNoData = NAN;
    1383           2 :     if (FetchDoubleArg(papszArgs, "NoData", &dfOldNoData) != CE_None)
    1384           0 :         return CE_Failure;
    1385           2 :     if (FetchDoubleArg(papszArgs, "to", &dfNewNoData, &dfNewNoData) != CE_None)
    1386           0 :         return CE_Failure;
    1387             : 
    1388           2 :     if (!GDALDataTypeIsFloating(eBufType) && std::isnan(dfNewNoData))
    1389             :     {
    1390           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1391             :                  "Using nan requires a floating point type output buffer");
    1392           0 :         return CE_Failure;
    1393             :     }
    1394             : 
    1395             :     /* ---- Set pixels ---- */
    1396           2 :     size_t ii = 0;
    1397         102 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1398             :     {
    1399        5100 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1400             :         {
    1401        5000 :             double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
    1402        5000 :             if (dfPixVal == dfOldNoData || std::isnan(dfPixVal))
    1403        3200 :                 dfPixVal = dfNewNoData;
    1404             : 
    1405        5000 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1406             :                           static_cast<GByte *>(pData) +
    1407        5000 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1408        5000 :                               iCol * nPixelSpace,
    1409             :                           eBufType, nPixelSpace, 1);
    1410             :         }
    1411             :     }
    1412             : 
    1413             :     /* ---- Return success ---- */
    1414           2 :     return CE_None;
    1415             : }
    1416             : 
    1417             : static const char pszScalePixelFuncMetadata[] =
    1418             :     "<PixelFunctionArgumentsList>"
    1419             :     "   <Argument type='builtin' value='offset' />"
    1420             :     "   <Argument type='builtin' value='scale' />"
    1421             :     "</PixelFunctionArgumentsList>";
    1422             : 
    1423           1 : static CPLErr ScalePixelFunc(void **papoSources, int nSources, void *pData,
    1424             :                              int nXSize, int nYSize, GDALDataType eSrcType,
    1425             :                              GDALDataType eBufType, int nPixelSpace,
    1426             :                              int nLineSpace, CSLConstList papszArgs)
    1427             : {
    1428             :     /* ---- Init ---- */
    1429           1 :     if (nSources != 1)
    1430           0 :         return CE_Failure;
    1431           1 :     if (GDALDataTypeIsComplex(eSrcType))
    1432             :     {
    1433           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1434             :                  "scale cannot by applied to complex data types");
    1435           0 :         return CE_Failure;
    1436             :     }
    1437             : 
    1438             :     double dfScale, dfOffset;
    1439           1 :     if (FetchDoubleArg(papszArgs, "scale", &dfScale) != CE_None)
    1440           0 :         return CE_Failure;
    1441           1 :     if (FetchDoubleArg(papszArgs, "offset", &dfOffset) != CE_None)
    1442           0 :         return CE_Failure;
    1443             : 
    1444             :     /* ---- Set pixels ---- */
    1445           1 :     size_t ii = 0;
    1446          21 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1447             :     {
    1448         420 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1449             :         {
    1450             :             const double dfPixVal =
    1451         400 :                 GetSrcVal(papoSources[0], eSrcType, ii) * dfScale + dfOffset;
    1452             : 
    1453         400 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1454             :                           static_cast<GByte *>(pData) +
    1455         400 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1456         400 :                               iCol * nPixelSpace,
    1457             :                           eBufType, nPixelSpace, 1);
    1458             :         }
    1459             :     }
    1460             : 
    1461             :     /* ---- Return success ---- */
    1462           1 :     return CE_None;
    1463             : }
    1464             : 
    1465           1 : static CPLErr NormDiffPixelFunc(void **papoSources, int nSources, void *pData,
    1466             :                                 int nXSize, int nYSize, GDALDataType eSrcType,
    1467             :                                 GDALDataType eBufType, int nPixelSpace,
    1468             :                                 int nLineSpace)
    1469             : {
    1470             :     /* ---- Init ---- */
    1471           1 :     if (nSources != 2)
    1472           0 :         return CE_Failure;
    1473             : 
    1474           1 :     if (GDALDataTypeIsComplex(eSrcType))
    1475             :     {
    1476           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1477             :                  "norm_diff cannot by applied to complex data types");
    1478           0 :         return CE_Failure;
    1479             :     }
    1480             : 
    1481             :     /* ---- Set pixels ---- */
    1482           1 :     size_t ii = 0;
    1483           7 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1484             :     {
    1485          36 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1486             :         {
    1487          30 :             const double dfLeftVal = GetSrcVal(papoSources[0], eSrcType, ii);
    1488          30 :             const double dfRightVal = GetSrcVal(papoSources[1], eSrcType, ii);
    1489             : 
    1490          30 :             const double dfDenom = (dfLeftVal + dfRightVal);
    1491             : 
    1492             :             // coverity[divide_by_zero]
    1493             :             const double dfPixVal =
    1494          30 :                 dfDenom == 0 ? std::numeric_limits<double>::infinity()
    1495          30 :                              : (dfLeftVal - dfRightVal) / dfDenom;
    1496             : 
    1497          30 :             GDALCopyWords(&dfPixVal, GDT_Float64, 0,
    1498             :                           static_cast<GByte *>(pData) +
    1499          30 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1500          30 :                               iCol * nPixelSpace,
    1501             :                           eBufType, nPixelSpace, 1);
    1502             :         }
    1503             :     }
    1504             : 
    1505             :     /* ---- Return success ---- */
    1506           1 :     return CE_None;
    1507             : }  // NormDiffPixelFunc
    1508             : 
    1509             : /************************************************************************/
    1510             : /*                   pszMinMaxFuncMetadataNodata                        */
    1511             : /************************************************************************/
    1512             : 
    1513             : static const char pszMinMaxFuncMetadataNodata[] =
    1514             :     "<PixelFunctionArgumentsList>"
    1515             :     "   <Argument type='builtin' value='NoData' optional='true' />"
    1516             :     "   <Argument name='propagateNoData' description='Whether the output value "
    1517             :     "should be NoData as as soon as one source is NoData' type='boolean' "
    1518             :     "default='false' />"
    1519             :     "</PixelFunctionArgumentsList>";
    1520             : 
    1521             : template <class Comparator>
    1522           5 : static CPLErr MinOrMaxPixelFunc(void **papoSources, int nSources, void *pData,
    1523             :                                 int nXSize, int nYSize, GDALDataType eSrcType,
    1524             :                                 GDALDataType eBufType, int nPixelSpace,
    1525             :                                 int nLineSpace, CSLConstList papszArgs)
    1526             : {
    1527             :     /* ---- Init ---- */
    1528           5 :     if (nSources < 2)
    1529           0 :         return CE_Failure;
    1530             : 
    1531           5 :     if (GDALDataTypeIsComplex(eSrcType))
    1532             :     {
    1533           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1534             :                  "Complex data type not supported for min/max().");
    1535           0 :         return CE_Failure;
    1536             :     }
    1537             : 
    1538           5 :     double dfNoData = std::numeric_limits<double>::quiet_NaN();
    1539           5 :     if (FetchDoubleArg(papszArgs, "NoData", &dfNoData, &dfNoData) != CE_None)
    1540           0 :         return CE_Failure;
    1541           5 :     const bool bPropagateNoData = CPLTestBool(
    1542             :         CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
    1543             : 
    1544             :     /* ---- Set pixels ---- */
    1545           5 :     size_t ii = 0;
    1546         255 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1547             :     {
    1548       12750 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1549             :         {
    1550       12500 :             double dfRes = std::numeric_limits<double>::quiet_NaN();
    1551             : 
    1552       43400 :             for (int iSrc = 0; iSrc < nSources; ++iSrc)
    1553             :             {
    1554       32950 :                 const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
    1555             : 
    1556       32950 :                 if (std::isnan(dfVal) || dfVal == dfNoData)
    1557             :                 {
    1558       14350 :                     if (bPropagateNoData)
    1559             :                     {
    1560        2050 :                         dfRes = dfNoData;
    1561        2050 :                         break;
    1562             :                     }
    1563             :                 }
    1564       18600 :                 else if (Comparator::compare(dfVal, dfRes))
    1565             :                 {
    1566        9950 :                     dfRes = dfVal;
    1567             :                 }
    1568             :             }
    1569             : 
    1570       12500 :             if (!bPropagateNoData && std::isnan(dfRes))
    1571             :             {
    1572        3200 :                 dfRes = dfNoData;
    1573             :             }
    1574             : 
    1575       12500 :             GDALCopyWords(&dfRes, GDT_Float64, 0,
    1576             :                           static_cast<GByte *>(pData) +
    1577       12500 :                               static_cast<GSpacing>(nLineSpace) * iLine +
    1578       12500 :                               iCol * nPixelSpace,
    1579             :                           eBufType, nPixelSpace, 1);
    1580             :         }
    1581             :     }
    1582             : 
    1583             :     /* ---- Return success ---- */
    1584           5 :     return CE_None;
    1585             : } /* MinOrMaxPixelFunc */
    1586             : 
    1587           2 : static CPLErr MinPixelFunc(void **papoSources, int nSources, void *pData,
    1588             :                            int nXSize, int nYSize, GDALDataType eSrcType,
    1589             :                            GDALDataType eBufType, int nPixelSpace,
    1590             :                            int nLineSpace, CSLConstList papszArgs)
    1591             : {
    1592             :     struct Comparator
    1593             :     {
    1594        2700 :         static bool compare(double x, double resVal)
    1595             :         {
    1596             :             // Written this way to deal with resVal being NaN
    1597        2700 :             return !(x >= resVal);
    1598             :         }
    1599             :     };
    1600             : 
    1601           2 :     return MinOrMaxPixelFunc<Comparator>(papoSources, nSources, pData, nXSize,
    1602             :                                          nYSize, eSrcType, eBufType,
    1603           2 :                                          nPixelSpace, nLineSpace, papszArgs);
    1604             : }
    1605             : 
    1606           3 : static CPLErr MaxPixelFunc(void **papoSources, int nSources, void *pData,
    1607             :                            int nXSize, int nYSize, GDALDataType eSrcType,
    1608             :                            GDALDataType eBufType, int nPixelSpace,
    1609             :                            int nLineSpace, CSLConstList papszArgs)
    1610             : {
    1611             :     struct Comparator
    1612             :     {
    1613       15900 :         static bool compare(double x, double resVal)
    1614             :         {
    1615             :             // Written this way to deal with resVal being NaN
    1616       15900 :             return !(x <= resVal);
    1617             :         }
    1618             :     };
    1619             : 
    1620           3 :     return MinOrMaxPixelFunc<Comparator>(papoSources, nSources, pData, nXSize,
    1621             :                                          nYSize, eSrcType, eBufType,
    1622           3 :                                          nPixelSpace, nLineSpace, papszArgs);
    1623             : }
    1624             : 
    1625             : static const char pszExprPixelFuncMetadata[] =
    1626             :     "<PixelFunctionArgumentsList>"
    1627             :     "   <Argument name='expression' "
    1628             :     "             description='Expression to be evaluated' "
    1629             :     "             type='string'></Argument>"
    1630             :     "   <Argument name='dialect' "
    1631             :     "             description='Expression dialect' "
    1632             :     "             type='string-select'"
    1633             :     "             default='exprtk'>"
    1634             :     "       <Value>exprtk</Value>"
    1635             :     "       <Value>muparser</Value>"
    1636             :     "    </Argument>"
    1637             :     "</PixelFunctionArgumentsList>";
    1638             : 
    1639          70 : static CPLErr ExprPixelFunc(void **papoSources, int nSources, void *pData,
    1640             :                             int nXSize, int nYSize, GDALDataType eSrcType,
    1641             :                             GDALDataType eBufType, int nPixelSpace,
    1642             :                             int nLineSpace, CSLConstList papszArgs)
    1643             : {
    1644             :     /* ---- Init ---- */
    1645             : 
    1646          70 :     if (GDALDataTypeIsComplex(eSrcType))
    1647             :     {
    1648           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1649             :                  "expression cannot by applied to complex data types");
    1650           0 :         return CE_Failure;
    1651             :     }
    1652             : 
    1653          70 :     std::unique_ptr<gdal::MathExpression> poExpression;
    1654             : 
    1655          70 :     const char *pszExpression = CSLFetchNameValue(papszArgs, "expression");
    1656             : 
    1657          70 :     const char *pszSourceNames = CSLFetchNameValue(papszArgs, "SOURCE_NAMES");
    1658             :     const CPLStringList aosSourceNames(
    1659         140 :         CSLTokenizeString2(pszSourceNames, "|", 0));
    1660             : 
    1661         140 :     std::vector<double> adfValuesForPixel(nSources);
    1662             : 
    1663          70 :     const char *pszDialect = CSLFetchNameValue(papszArgs, "dialect");
    1664          70 :     if (!pszDialect)
    1665             :     {
    1666           0 :         pszDialect = "muparser";
    1667             :     }
    1668             : 
    1669          70 :     poExpression = gdal::MathExpression::Create(pszExpression, pszDialect);
    1670             : 
    1671             :     // cppcheck-suppress knownConditionTrueFalse
    1672          70 :     if (!poExpression)
    1673             :     {
    1674           0 :         return CE_Failure;
    1675             :     }
    1676             : 
    1677             :     {
    1678          70 :         int iSource = 0;
    1679         216 :         for (const auto &osName : aosSourceNames)
    1680             :         {
    1681         292 :             poExpression->RegisterVariable(osName,
    1682         146 :                                            &adfValuesForPixel[iSource++]);
    1683             :         }
    1684             :     }
    1685             : 
    1686          70 :     if (strstr(pszExpression, "BANDS"))
    1687             :     {
    1688           1 :         poExpression->RegisterVector("BANDS", &adfValuesForPixel);
    1689             :     }
    1690             : 
    1691             :     std::unique_ptr<double, VSIFreeReleaser> padfResults(
    1692         140 :         static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
    1693          70 :     if (!padfResults)
    1694           0 :         return CE_Failure;
    1695             : 
    1696             :     /* ---- Set pixels ---- */
    1697          70 :     size_t ii = 0;
    1698        4203 :     for (int iLine = 0; iLine < nYSize; ++iLine)
    1699             :     {
    1700    12982900 :         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
    1701             :         {
    1702    38947700 :             for (int iSrc = 0; iSrc < nSources; iSrc++)
    1703             :             {
    1704             :                 // cppcheck-suppress unreadVariable
    1705    25968900 :                 adfValuesForPixel[iSrc] =
    1706    25968900 :                     GetSrcVal(papoSources[iSrc], eSrcType, ii);
    1707             :             }
    1708             : 
    1709    12978700 :             if (auto eErr = poExpression->Evaluate(); eErr != CE_None)
    1710             :             {
    1711           2 :                 return CE_Failure;
    1712             :             }
    1713             :             else
    1714             :             {
    1715    12978700 :                 padfResults.get()[iCol] = poExpression->Results()[0];
    1716             :             }
    1717             :         }
    1718             : 
    1719        4133 :         GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
    1720             :                       static_cast<GByte *>(pData) +
    1721        4133 :                           static_cast<GSpacing>(nLineSpace) * iLine,
    1722             :                       eBufType, nPixelSpace, nXSize);
    1723             :     }
    1724             : 
    1725             :     /* ---- Return success ---- */
    1726          68 :     return CE_None;
    1727             : }  // ExprPixelFunc
    1728             : 
    1729             : /************************************************************************/
    1730             : /*                     GDALRegisterDefaultPixelFunc()                   */
    1731             : /************************************************************************/
    1732             : 
    1733             : /**
    1734             :  * This adds a default set of pixel functions to the global list of
    1735             :  * available pixel functions for derived bands:
    1736             :  *
    1737             :  * - "real": extract real part from a single raster band (just a copy if the
    1738             :  *           input is non-complex)
    1739             :  * - "imag": extract imaginary part from a single raster band (0 for
    1740             :  *           non-complex)
    1741             :  * - "complex": make a complex band merging two bands used as real and
    1742             :  *              imag values
    1743             :  * - "polar": make a complex band using input bands for amplitude and
    1744             :  *            phase values (b1 * exp( j * b2 ))
    1745             :  * - "mod": extract module from a single raster band (real or complex)
    1746             :  * - "phase": extract phase from a single raster band [-PI,PI] (0 or PI for
    1747             :               non-complex)
    1748             :  * - "conj": computes the complex conjugate of a single raster band (just a
    1749             :  *           copy if the input is non-complex)
    1750             :  * - "sum": sum 2 or more raster bands
    1751             :  * - "diff": computes the difference between 2 raster bands (b1 - b2)
    1752             :  * - "mul": multiply 2 or more raster bands
    1753             :  * - "div": divide one raster band by another (b1 / b2).
    1754             :  * - "min": minimum value of 2 or more raster bands
    1755             :  * - "max": maximum value of 2 or more raster bands
    1756             :  * - "norm_diff": computes the normalized difference between two raster bands:
    1757             :  *                ``(b1 - b2)/(b1 + b2)``.
    1758             :  * - "cmul": multiply the first band for the complex conjugate of the second
    1759             :  * - "inv": inverse (1./x).
    1760             :  * - "intensity": computes the intensity Re(x*conj(x)) of a single raster band
    1761             :  *                (real or complex)
    1762             :  * - "sqrt": perform the square root of a single raster band (real only)
    1763             :  * - "log10": compute the logarithm (base 10) of the abs of a single raster
    1764             :  *            band (real or complex): log10( abs( x ) )
    1765             :  * - "dB": perform conversion to dB of the abs of a single raster
    1766             :  *         band (real or complex): 20. * log10( abs( x ) ).
    1767             :  *         Note: the optional fact parameter can be set to 10. to get the
    1768             :  *         alternative formula: 10. * log10( abs( x ) )
    1769             :  * - "exp": computes the exponential of each element in the input band ``x``
    1770             :  *          (of real values): ``e ^ x``.
    1771             :  *          The function also accepts two optional parameters: ``base`` and
    1772             :  ``fact``
    1773             :  *          that allow to compute the generalized formula: ``base ^ ( fact *
    1774             :  x)``.
    1775             :  *          Note: this function is the recommended one to perform conversion
    1776             :  *          form logarithmic scale (dB): `` 10. ^ (x / 20.)``, in this case
    1777             :  *          ``base = 10.`` and ``fact = 1./20``
    1778             :  * - "dB2amp": perform scale conversion from logarithmic to linear
    1779             :  *             (amplitude) (i.e. 10 ^ ( x / 20 ) ) of a single raster
    1780             :  *             band (real only).
    1781             :  *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
    1782             :  with
    1783             :  *             ``base = 10.`` and ``fact = 0.05`` i.e. ``1./20``
    1784             :  * - "dB2pow": perform scale conversion from logarithmic to linear
    1785             :  *             (power) (i.e. 10 ^ ( x / 10 ) ) of a single raster
    1786             :  *             band (real only)
    1787             :  *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
    1788             :  with
    1789             :  *             ``base = 10.`` and ``fact = 0.1`` i.e. ``1./10``
    1790             :  * - "pow": raise a single raster band to a constant power
    1791             :  * - "interpolate_linear": interpolate values between two raster bands
    1792             :  *                         using linear interpolation
    1793             :  * - "interpolate_exp": interpolate values between two raster bands using
    1794             :  *                      exponential interpolation
    1795             :  * - "scale": Apply the RasterBand metadata values of "offset" and "scale"
    1796             :  * - "nan": Convert incoming NoData values to IEEE 754 nan
    1797             :  *
    1798             :  * @see GDALAddDerivedBandPixelFunc
    1799             :  *
    1800             :  * @return CE_None
    1801             :  */
    1802        1384 : CPLErr GDALRegisterDefaultPixelFunc()
    1803             : {
    1804        1384 :     GDALAddDerivedBandPixelFunc("real", RealPixelFunc);
    1805        1384 :     GDALAddDerivedBandPixelFunc("imag", ImagPixelFunc);
    1806        1384 :     GDALAddDerivedBandPixelFunc("complex", ComplexPixelFunc);
    1807        1384 :     GDALAddDerivedBandPixelFuncWithArgs("polar", PolarPixelFunc,
    1808             :                                         pszPolarPixelFuncMetadata);
    1809        1384 :     GDALAddDerivedBandPixelFunc("mod", ModulePixelFunc);
    1810        1384 :     GDALAddDerivedBandPixelFunc("phase", PhasePixelFunc);
    1811        1384 :     GDALAddDerivedBandPixelFunc("conj", ConjPixelFunc);
    1812        1384 :     GDALAddDerivedBandPixelFuncWithArgs("sum", SumPixelFunc,
    1813             :                                         pszSumPixelFuncMetadata);
    1814        1384 :     GDALAddDerivedBandPixelFunc("diff", DiffPixelFunc);
    1815        1384 :     GDALAddDerivedBandPixelFuncWithArgs("mul", MulPixelFunc,
    1816             :                                         pszMulPixelFuncMetadata);
    1817        1384 :     GDALAddDerivedBandPixelFunc("div", DivPixelFunc);
    1818        1384 :     GDALAddDerivedBandPixelFunc("cmul", CMulPixelFunc);
    1819        1384 :     GDALAddDerivedBandPixelFuncWithArgs("inv", InvPixelFunc,
    1820             :                                         pszInvPixelFuncMetadata);
    1821        1384 :     GDALAddDerivedBandPixelFunc("intensity", IntensityPixelFunc);
    1822        1384 :     GDALAddDerivedBandPixelFunc("sqrt", SqrtPixelFunc);
    1823        1384 :     GDALAddDerivedBandPixelFunc("log10", Log10PixelFunc);
    1824        1384 :     GDALAddDerivedBandPixelFuncWithArgs("dB", DBPixelFunc,
    1825             :                                         pszDBPixelFuncMetadata);
    1826        1384 :     GDALAddDerivedBandPixelFuncWithArgs("exp", ExpPixelFunc,
    1827             :                                         pszExpPixelFuncMetadata);
    1828        1384 :     GDALAddDerivedBandPixelFunc("dB2amp",
    1829             :                                 dB2AmpPixelFunc);  // deprecated in v3.5
    1830        1384 :     GDALAddDerivedBandPixelFunc("dB2pow",
    1831             :                                 dB2PowPixelFunc);  // deprecated in v3.5
    1832        1384 :     GDALAddDerivedBandPixelFuncWithArgs("pow", PowPixelFunc,
    1833             :                                         pszPowPixelFuncMetadata);
    1834        1384 :     GDALAddDerivedBandPixelFuncWithArgs("interpolate_linear",
    1835             :                                         InterpolatePixelFunc<InterpolateLinear>,
    1836             :                                         pszInterpolatePixelFuncMetadata);
    1837        1384 :     GDALAddDerivedBandPixelFuncWithArgs(
    1838             :         "interpolate_exp", InterpolatePixelFunc<InterpolateExponential>,
    1839             :         pszInterpolatePixelFuncMetadata);
    1840        1384 :     GDALAddDerivedBandPixelFuncWithArgs("replace_nodata",
    1841             :                                         ReplaceNoDataPixelFunc,
    1842             :                                         pszReplaceNoDataPixelFuncMetadata);
    1843        1384 :     GDALAddDerivedBandPixelFuncWithArgs("scale", ScalePixelFunc,
    1844             :                                         pszScalePixelFuncMetadata);
    1845        1384 :     GDALAddDerivedBandPixelFunc("norm_diff", NormDiffPixelFunc);
    1846        1384 :     GDALAddDerivedBandPixelFuncWithArgs("min", MinPixelFunc,
    1847             :                                         pszMinMaxFuncMetadataNodata);
    1848        1384 :     GDALAddDerivedBandPixelFuncWithArgs("max", MaxPixelFunc,
    1849             :                                         pszMinMaxFuncMetadataNodata);
    1850        1384 :     GDALAddDerivedBandPixelFuncWithArgs("expression", ExprPixelFunc,
    1851             :                                         pszExprPixelFuncMetadata);
    1852        1384 :     return CE_None;
    1853             : }

Generated by: LCOV version 1.14