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

Generated by: LCOV version 1.14