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

Generated by: LCOV version 1.14