/src/gdal/frmts/vrt/pixelfunctions.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | /******************************************************************************  | 
2  |  |  *  | 
3  |  |  * Project:  GDAL  | 
4  |  |  * Purpose:  Implementation of a set of GDALDerivedPixelFunc(s) to be used  | 
5  |  |  *           with source raster band of virtual GDAL datasets.  | 
6  |  |  * Author:   Antonio Valentino <antonio.valentino@tiscali.it>  | 
7  |  |  *  | 
8  |  |  ******************************************************************************  | 
9  |  |  * Copyright (c) 2008-2014,2022 Antonio Valentino <antonio.valentino@tiscali.it>  | 
10  |  |  *  | 
11  |  |  * SPDX-License-Identifier: MIT  | 
12  |  |  *****************************************************************************/  | 
13  |  |  | 
14  |  | #include <cmath>  | 
15  |  | #include "gdal.h"  | 
16  |  | #include "vrtdataset.h"  | 
17  |  | #include "vrtexpression.h"  | 
18  |  | #include "vrtreclassifier.h"  | 
19  |  | #include "cpl_float.h"  | 
20  |  |  | 
21  |  | #if defined(__x86_64) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)  | 
22  |  | #define USE_SSE2  | 
23  |  | #include "gdalsse_priv.h"  | 
24  |  | #endif  | 
25  |  |  | 
26  |  | #include "gdal_priv_templates.hpp"  | 
27  |  |  | 
28  |  | #include <limits>  | 
29  |  |  | 
30  |  | namespace gdal  | 
31  |  | { | 
32  | 0  | MathExpression::~MathExpression() = default;  | 
33  |  | }  | 
34  |  |  | 
35  |  | template <typename T>  | 
36  |  | inline double GetSrcVal(const void *pSource, GDALDataType eSrcType, T ii)  | 
37  | 0  | { | 
38  | 0  |     switch (eSrcType)  | 
39  | 0  |     { | 
40  | 0  |         case GDT_Unknown:  | 
41  | 0  |             return 0;  | 
42  | 0  |         case GDT_Byte:  | 
43  | 0  |             return static_cast<const GByte *>(pSource)[ii];  | 
44  | 0  |         case GDT_Int8:  | 
45  | 0  |             return static_cast<const GInt8 *>(pSource)[ii];  | 
46  | 0  |         case GDT_UInt16:  | 
47  | 0  |             return static_cast<const GUInt16 *>(pSource)[ii];  | 
48  | 0  |         case GDT_Int16:  | 
49  | 0  |             return static_cast<const GInt16 *>(pSource)[ii];  | 
50  | 0  |         case GDT_UInt32:  | 
51  | 0  |             return static_cast<const GUInt32 *>(pSource)[ii];  | 
52  | 0  |         case GDT_Int32:  | 
53  | 0  |             return static_cast<const GInt32 *>(pSource)[ii];  | 
54  |  |         // Precision loss currently for int64/uint64  | 
55  | 0  |         case GDT_UInt64:  | 
56  | 0  |             return static_cast<double>(  | 
57  | 0  |                 static_cast<const uint64_t *>(pSource)[ii]);  | 
58  | 0  |         case GDT_Int64:  | 
59  | 0  |             return static_cast<double>(  | 
60  | 0  |                 static_cast<const int64_t *>(pSource)[ii]);  | 
61  | 0  |         case GDT_Float16:  | 
62  | 0  |             return static_cast<const GFloat16 *>(pSource)[ii];  | 
63  | 0  |         case GDT_Float32:  | 
64  | 0  |             return static_cast<const float *>(pSource)[ii];  | 
65  | 0  |         case GDT_Float64:  | 
66  | 0  |             return static_cast<const double *>(pSource)[ii];  | 
67  | 0  |         case GDT_CInt16:  | 
68  | 0  |             return static_cast<const GInt16 *>(pSource)[2 * ii];  | 
69  | 0  |         case GDT_CInt32:  | 
70  | 0  |             return static_cast<const GInt32 *>(pSource)[2 * ii];  | 
71  | 0  |         case GDT_CFloat16:  | 
72  | 0  |             return static_cast<const GFloat16 *>(pSource)[2 * ii];  | 
73  | 0  |         case GDT_CFloat32:  | 
74  | 0  |             return static_cast<const float *>(pSource)[2 * ii];  | 
75  | 0  |         case GDT_CFloat64:  | 
76  | 0  |             return static_cast<const double *>(pSource)[2 * ii];  | 
77  | 0  |         case GDT_TypeCount:  | 
78  | 0  |             break;  | 
79  | 0  |     }  | 
80  | 0  |     return 0;  | 
81  | 0  | }  | 
82  |  |  | 
83  |  | static bool IsNoData(double dfVal, double dfNoData)  | 
84  | 0  | { | 
85  | 0  |     return dfVal == dfNoData || (std::isnan(dfVal) && std::isnan(dfNoData));  | 
86  | 0  | }  | 
87  |  |  | 
88  |  | static CPLErr FetchDoubleArg(CSLConstList papszArgs, const char *pszName,  | 
89  |  |                              double *pdfX, double *pdfDefault = nullptr)  | 
90  | 0  | { | 
91  | 0  |     const char *pszVal = CSLFetchNameValue(papszArgs, pszName);  | 
92  |  | 
  | 
93  | 0  |     if (pszVal == nullptr)  | 
94  | 0  |     { | 
95  | 0  |         if (pdfDefault == nullptr)  | 
96  | 0  |         { | 
97  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
98  | 0  |                      "Missing pixel function argument: %s", pszName);  | 
99  | 0  |             return CE_Failure;  | 
100  | 0  |         }  | 
101  | 0  |         else  | 
102  | 0  |         { | 
103  | 0  |             *pdfX = *pdfDefault;  | 
104  | 0  |             return CE_None;  | 
105  | 0  |         }  | 
106  | 0  |     }  | 
107  |  |  | 
108  | 0  |     char *pszEnd = nullptr;  | 
109  | 0  |     *pdfX = std::strtod(pszVal, &pszEnd);  | 
110  | 0  |     if (pszEnd == pszVal)  | 
111  | 0  |     { | 
112  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
113  | 0  |                  "Failed to parse pixel function argument: %s", pszName);  | 
114  | 0  |         return CE_Failure;  | 
115  | 0  |     }  | 
116  |  |  | 
117  | 0  |     return CE_None;  | 
118  | 0  | }  | 
119  |  |  | 
120  |  | static CPLErr RealPixelFunc(void **papoSources, int nSources, void *pData,  | 
121  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
122  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
123  |  |                             int nLineSpace)  | 
124  | 0  | { | 
125  |  |     /* ---- Init ---- */  | 
126  | 0  |     if (nSources != 1)  | 
127  | 0  |         return CE_Failure;  | 
128  |  |  | 
129  | 0  |     const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);  | 
130  | 0  |     const size_t nLineSpaceSrc = static_cast<size_t>(nPixelSpaceSrc) * nXSize;  | 
131  |  |  | 
132  |  |     /* ---- Set pixels ---- */  | 
133  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
134  | 0  |     { | 
135  | 0  |         GDALCopyWords(static_cast<GByte *>(papoSources[0]) +  | 
136  | 0  |                           nLineSpaceSrc * iLine,  | 
137  | 0  |                       eSrcType, nPixelSpaceSrc,  | 
138  | 0  |                       static_cast<GByte *>(pData) +  | 
139  | 0  |                           static_cast<GSpacing>(nLineSpace) * iLine,  | 
140  | 0  |                       eBufType, nPixelSpace, nXSize);  | 
141  | 0  |     }  | 
142  |  |  | 
143  |  |     /* ---- Return success ---- */  | 
144  | 0  |     return CE_None;  | 
145  | 0  | }  // RealPixelFunc  | 
146  |  |  | 
147  |  | static CPLErr ImagPixelFunc(void **papoSources, int nSources, void *pData,  | 
148  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
149  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
150  |  |                             int nLineSpace)  | 
151  | 0  | { | 
152  |  |     /* ---- Init ---- */  | 
153  | 0  |     if (nSources != 1)  | 
154  | 0  |         return CE_Failure;  | 
155  |  |  | 
156  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
157  | 0  |     { | 
158  | 0  |         const GDALDataType eSrcBaseType = GDALGetNonComplexDataType(eSrcType);  | 
159  | 0  |         const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);  | 
160  | 0  |         const size_t nLineSpaceSrc =  | 
161  | 0  |             static_cast<size_t>(nPixelSpaceSrc) * nXSize;  | 
162  |  | 
  | 
163  | 0  |         const void *const pImag = static_cast<GByte *>(papoSources[0]) +  | 
164  | 0  |                                   GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
165  |  |  | 
166  |  |         /* ---- Set pixels ---- */  | 
167  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
168  | 0  |         { | 
169  | 0  |             GDALCopyWords(static_cast<const GByte *>(pImag) +  | 
170  | 0  |                               nLineSpaceSrc * iLine,  | 
171  | 0  |                           eSrcBaseType, nPixelSpaceSrc,  | 
172  | 0  |                           static_cast<GByte *>(pData) +  | 
173  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine,  | 
174  | 0  |                           eBufType, nPixelSpace, nXSize);  | 
175  | 0  |         }  | 
176  | 0  |     }  | 
177  | 0  |     else  | 
178  | 0  |     { | 
179  | 0  |         const double dfImag = 0;  | 
180  |  |  | 
181  |  |         /* ---- Set pixels ---- */  | 
182  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
183  | 0  |         { | 
184  |  |             // Always copy from the same location.  | 
185  | 0  |             GDALCopyWords(&dfImag, eSrcType, 0,  | 
186  | 0  |                           static_cast<GByte *>(pData) +  | 
187  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine,  | 
188  | 0  |                           eBufType, nPixelSpace, nXSize);  | 
189  | 0  |         }  | 
190  | 0  |     }  | 
191  |  |  | 
192  |  |     /* ---- Return success ---- */  | 
193  | 0  |     return CE_None;  | 
194  | 0  | }  // ImagPixelFunc  | 
195  |  |  | 
196  |  | static CPLErr ComplexPixelFunc(void **papoSources, int nSources, void *pData,  | 
197  |  |                                int nXSize, int nYSize, GDALDataType eSrcType,  | 
198  |  |                                GDALDataType eBufType, int nPixelSpace,  | 
199  |  |                                int nLineSpace)  | 
200  | 0  | { | 
201  |  |     /* ---- Init ---- */  | 
202  | 0  |     if (nSources != 2)  | 
203  | 0  |         return CE_Failure;  | 
204  |  |  | 
205  | 0  |     const void *const pReal = papoSources[0];  | 
206  | 0  |     const void *const pImag = papoSources[1];  | 
207  |  |  | 
208  |  |     /* ---- Set pixels ---- */  | 
209  | 0  |     size_t ii = 0;  | 
210  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
211  | 0  |     { | 
212  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
213  | 0  |         { | 
214  |  |             // Source raster pixels may be obtained with GetSrcVal macro.  | 
215  | 0  |             const double adfPixVal[2] = { | 
216  | 0  |                 GetSrcVal(pReal, eSrcType, ii),  // re  | 
217  | 0  |                 GetSrcVal(pImag, eSrcType, ii)   // im  | 
218  | 0  |             };  | 
219  |  | 
  | 
220  | 0  |             GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
221  | 0  |                           static_cast<GByte *>(pData) +  | 
222  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
223  | 0  |                               iCol * nPixelSpace,  | 
224  | 0  |                           eBufType, nPixelSpace, 1);  | 
225  | 0  |         }  | 
226  | 0  |     }  | 
227  |  |  | 
228  |  |     /* ---- Return success ---- */  | 
229  | 0  |     return CE_None;  | 
230  | 0  | }  // ComplexPixelFunc  | 
231  |  |  | 
232  |  | typedef enum  | 
233  |  | { | 
234  |  |     GAT_amplitude,  | 
235  |  |     GAT_intensity,  | 
236  |  |     GAT_dB  | 
237  |  | } PolarAmplitudeType;  | 
238  |  |  | 
239  |  | static const char pszPolarPixelFuncMetadata[] =  | 
240  |  |     "<PixelFunctionArgumentsList>"  | 
241  |  |     "   <Argument name='amplitude_type' description='Amplitude Type' "  | 
242  |  |     "type='string-select' default='AMPLITUDE'>"  | 
243  |  |     "       <Value>INTENSITY</Value>"  | 
244  |  |     "       <Value>dB</Value>"  | 
245  |  |     "       <Value>AMPLITUDE</Value>"  | 
246  |  |     "   </Argument>"  | 
247  |  |     "</PixelFunctionArgumentsList>";  | 
248  |  |  | 
249  |  | static CPLErr PolarPixelFunc(void **papoSources, int nSources, void *pData,  | 
250  |  |                              int nXSize, int nYSize, GDALDataType eSrcType,  | 
251  |  |                              GDALDataType eBufType, int nPixelSpace,  | 
252  |  |                              int nLineSpace, CSLConstList papszArgs)  | 
253  | 0  | { | 
254  |  |     /* ---- Init ---- */  | 
255  | 0  |     if (nSources != 2)  | 
256  | 0  |         return CE_Failure;  | 
257  |  |  | 
258  | 0  |     const char pszName[] = "amplitude_type";  | 
259  | 0  |     const char *pszVal = CSLFetchNameValue(papszArgs, pszName);  | 
260  | 0  |     PolarAmplitudeType amplitudeType = GAT_amplitude;  | 
261  | 0  |     if (pszVal != nullptr)  | 
262  | 0  |     { | 
263  | 0  |         if (strcmp(pszVal, "INTENSITY") == 0)  | 
264  | 0  |             amplitudeType = GAT_intensity;  | 
265  | 0  |         else if (strcmp(pszVal, "dB") == 0)  | 
266  | 0  |             amplitudeType = GAT_dB;  | 
267  | 0  |         else if (strcmp(pszVal, "AMPLITUDE") != 0)  | 
268  | 0  |         { | 
269  | 0  |             CPLError(CE_Failure, CPLE_AppDefined,  | 
270  | 0  |                      "Invalid value for pixel function argument '%s': %s",  | 
271  | 0  |                      pszName, pszVal);  | 
272  | 0  |             return CE_Failure;  | 
273  | 0  |         }  | 
274  | 0  |     }  | 
275  |  |  | 
276  | 0  |     const void *const pAmp = papoSources[0];  | 
277  | 0  |     const void *const pPhase = papoSources[1];  | 
278  |  |  | 
279  |  |     /* ---- Set pixels ---- */  | 
280  | 0  |     size_t ii = 0;  | 
281  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
282  | 0  |     { | 
283  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
284  | 0  |         { | 
285  |  |             // Source raster pixels may be obtained with GetSrcVal macro.  | 
286  | 0  |             double dfAmp = GetSrcVal(pAmp, eSrcType, ii);  | 
287  | 0  |             switch (amplitudeType)  | 
288  | 0  |             { | 
289  | 0  |                 case GAT_intensity:  | 
290  |  |                     // clip to zero  | 
291  | 0  |                     dfAmp = dfAmp <= 0 ? 0 : std::sqrt(dfAmp);  | 
292  | 0  |                     break;  | 
293  | 0  |                 case GAT_dB:  | 
294  | 0  |                     dfAmp = dfAmp <= 0  | 
295  | 0  |                                 ? -std::numeric_limits<double>::infinity()  | 
296  | 0  |                                 : pow(10, dfAmp / 20.);  | 
297  | 0  |                     break;  | 
298  | 0  |                 case GAT_amplitude:  | 
299  | 0  |                     break;  | 
300  | 0  |             }  | 
301  | 0  |             const double dfPhase = GetSrcVal(pPhase, eSrcType, ii);  | 
302  | 0  |             const double adfPixVal[2] = { | 
303  | 0  |                 dfAmp * std::cos(dfPhase),  // re  | 
304  | 0  |                 dfAmp * std::sin(dfPhase)   // im  | 
305  | 0  |             };  | 
306  |  | 
  | 
307  | 0  |             GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
308  | 0  |                           static_cast<GByte *>(pData) +  | 
309  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
310  | 0  |                               iCol * nPixelSpace,  | 
311  | 0  |                           eBufType, nPixelSpace, 1);  | 
312  | 0  |         }  | 
313  | 0  |     }  | 
314  |  |  | 
315  |  |     /* ---- Return success ---- */  | 
316  | 0  |     return CE_None;  | 
317  | 0  | }  // PolarPixelFunc  | 
318  |  |  | 
319  |  | static CPLErr ModulePixelFunc(void **papoSources, int nSources, void *pData,  | 
320  |  |                               int nXSize, int nYSize, GDALDataType eSrcType,  | 
321  |  |                               GDALDataType eBufType, int nPixelSpace,  | 
322  |  |                               int nLineSpace)  | 
323  | 0  | { | 
324  |  |     /* ---- Init ---- */  | 
325  | 0  |     if (nSources != 1)  | 
326  | 0  |         return CE_Failure;  | 
327  |  |  | 
328  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
329  | 0  |     { | 
330  | 0  |         const void *pReal = papoSources[0];  | 
331  | 0  |         const void *pImag = static_cast<GByte *>(papoSources[0]) +  | 
332  | 0  |                             GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
333  |  |  | 
334  |  |         /* ---- Set pixels ---- */  | 
335  | 0  |         size_t ii = 0;  | 
336  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
337  | 0  |         { | 
338  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
339  | 0  |             { | 
340  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
341  | 0  |                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);  | 
342  | 0  |                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);  | 
343  |  | 
  | 
344  | 0  |                 const double dfPixVal = sqrt(dfReal * dfReal + dfImag * dfImag);  | 
345  |  | 
  | 
346  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
347  | 0  |                               static_cast<GByte *>(pData) +  | 
348  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
349  | 0  |                                   iCol * nPixelSpace,  | 
350  | 0  |                               eBufType, nPixelSpace, 1);  | 
351  | 0  |             }  | 
352  | 0  |         }  | 
353  | 0  |     }  | 
354  | 0  |     else  | 
355  | 0  |     { | 
356  |  |         /* ---- Set pixels ---- */  | 
357  | 0  |         size_t ii = 0;  | 
358  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
359  | 0  |         { | 
360  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
361  | 0  |             { | 
362  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
363  | 0  |                 const double dfPixVal =  | 
364  | 0  |                     fabs(GetSrcVal(papoSources[0], eSrcType, ii));  | 
365  |  | 
  | 
366  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
367  | 0  |                               static_cast<GByte *>(pData) +  | 
368  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
369  | 0  |                                   iCol * nPixelSpace,  | 
370  | 0  |                               eBufType, nPixelSpace, 1);  | 
371  | 0  |             }  | 
372  | 0  |         }  | 
373  | 0  |     }  | 
374  |  |  | 
375  |  |     /* ---- Return success ---- */  | 
376  | 0  |     return CE_None;  | 
377  | 0  | }  // ModulePixelFunc  | 
378  |  |  | 
379  |  | static CPLErr PhasePixelFunc(void **papoSources, int nSources, void *pData,  | 
380  |  |                              int nXSize, int nYSize, GDALDataType eSrcType,  | 
381  |  |                              GDALDataType eBufType, int nPixelSpace,  | 
382  |  |                              int nLineSpace)  | 
383  | 0  | { | 
384  |  |     /* ---- Init ---- */  | 
385  | 0  |     if (nSources != 1)  | 
386  | 0  |         return CE_Failure;  | 
387  |  |  | 
388  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
389  | 0  |     { | 
390  | 0  |         const void *const pReal = papoSources[0];  | 
391  | 0  |         const void *const pImag = static_cast<GByte *>(papoSources[0]) +  | 
392  | 0  |                                   GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
393  |  |  | 
394  |  |         /* ---- Set pixels ---- */  | 
395  | 0  |         size_t ii = 0;  | 
396  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
397  | 0  |         { | 
398  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
399  | 0  |             { | 
400  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
401  | 0  |                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);  | 
402  | 0  |                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);  | 
403  |  | 
  | 
404  | 0  |                 const double dfPixVal = atan2(dfImag, dfReal);  | 
405  |  | 
  | 
406  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
407  | 0  |                               static_cast<GByte *>(pData) +  | 
408  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
409  | 0  |                                   iCol * nPixelSpace,  | 
410  | 0  |                               eBufType, nPixelSpace, 1);  | 
411  | 0  |             }  | 
412  | 0  |         }  | 
413  | 0  |     }  | 
414  | 0  |     else if (GDALDataTypeIsInteger(eSrcType) && !GDALDataTypeIsSigned(eSrcType))  | 
415  | 0  |     { | 
416  | 0  |         constexpr double dfZero = 0;  | 
417  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
418  | 0  |         { | 
419  | 0  |             GDALCopyWords(&dfZero, GDT_Float64, 0,  | 
420  | 0  |                           static_cast<GByte *>(pData) +  | 
421  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine,  | 
422  | 0  |                           eBufType, nPixelSpace, nXSize);  | 
423  | 0  |         }  | 
424  | 0  |     }  | 
425  | 0  |     else  | 
426  | 0  |     { | 
427  |  |         /* ---- Set pixels ---- */  | 
428  | 0  |         size_t ii = 0;  | 
429  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
430  | 0  |         { | 
431  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
432  | 0  |             { | 
433  | 0  |                 const void *const pReal = papoSources[0];  | 
434  |  |  | 
435  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
436  | 0  |                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);  | 
437  | 0  |                 const double dfPixVal = (dfReal < 0) ? M_PI : 0.0;  | 
438  |  | 
  | 
439  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
440  | 0  |                               static_cast<GByte *>(pData) +  | 
441  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
442  | 0  |                                   iCol * nPixelSpace,  | 
443  | 0  |                               eBufType, nPixelSpace, 1);  | 
444  | 0  |             }  | 
445  | 0  |         }  | 
446  | 0  |     }  | 
447  |  |  | 
448  |  |     /* ---- Return success ---- */  | 
449  | 0  |     return CE_None;  | 
450  | 0  | }  // PhasePixelFunc  | 
451  |  |  | 
452  |  | static CPLErr ConjPixelFunc(void **papoSources, int nSources, void *pData,  | 
453  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
454  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
455  |  |                             int nLineSpace)  | 
456  | 0  | { | 
457  |  |     /* ---- Init ---- */  | 
458  | 0  |     if (nSources != 1)  | 
459  | 0  |         return CE_Failure;  | 
460  |  |  | 
461  | 0  |     if (GDALDataTypeIsComplex(eSrcType) && GDALDataTypeIsComplex(eBufType))  | 
462  | 0  |     { | 
463  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
464  | 0  |         const void *const pReal = papoSources[0];  | 
465  | 0  |         const void *const pImag =  | 
466  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
467  |  |  | 
468  |  |         /* ---- Set pixels ---- */  | 
469  | 0  |         size_t ii = 0;  | 
470  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
471  | 0  |         { | 
472  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
473  | 0  |             { | 
474  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
475  | 0  |                 const double adfPixVal[2] = { | 
476  | 0  |                     +GetSrcVal(pReal, eSrcType, ii),  // re  | 
477  | 0  |                     -GetSrcVal(pImag, eSrcType, ii)   // im  | 
478  | 0  |                 };  | 
479  |  | 
  | 
480  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
481  | 0  |                               static_cast<GByte *>(pData) +  | 
482  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
483  | 0  |                                   iCol * nPixelSpace,  | 
484  | 0  |                               eBufType, nPixelSpace, 1);  | 
485  | 0  |             }  | 
486  | 0  |         }  | 
487  | 0  |     }  | 
488  | 0  |     else  | 
489  | 0  |     { | 
490  |  |         // No complex data type.  | 
491  | 0  |         return RealPixelFunc(papoSources, nSources, pData, nXSize, nYSize,  | 
492  | 0  |                              eSrcType, eBufType, nPixelSpace, nLineSpace);  | 
493  | 0  |     }  | 
494  |  |  | 
495  |  |     /* ---- Return success ---- */  | 
496  | 0  |     return CE_None;  | 
497  | 0  | }  // ConjPixelFunc  | 
498  |  |  | 
499  |  | #ifdef USE_SSE2  | 
500  |  |  | 
501  |  | /************************************************************************/  | 
502  |  | /*                        OptimizedSumToFloat_SSE2()                    */  | 
503  |  | /************************************************************************/  | 
504  |  |  | 
505  |  | template <typename Tsrc>  | 
506  |  | static void OptimizedSumToFloat_SSE2(double dfK, void *pOutBuffer,  | 
507  |  |                                      int nLineSpace, int nXSize, int nYSize,  | 
508  |  |                                      int nSources,  | 
509  |  |                                      const void *const *papoSources)  | 
510  | 0  | { | 
511  | 0  |     const XMMReg4Float cst = XMMReg4Float::Set1(static_cast<float>(dfK));  | 
512  |  | 
  | 
513  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
514  | 0  |     { | 
515  | 0  |         float *CPL_RESTRICT const pDest = reinterpret_cast<float *>(  | 
516  | 0  |             static_cast<GByte *>(pOutBuffer) +  | 
517  | 0  |             static_cast<GSpacing>(nLineSpace) * iLine);  | 
518  | 0  |         const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;  | 
519  |  | 
  | 
520  | 0  |         constexpr int VALUES_PER_REG = 4;  | 
521  | 0  |         constexpr int UNROLLING = 4 * VALUES_PER_REG;  | 
522  | 0  |         int iCol = 0;  | 
523  | 0  |         for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)  | 
524  | 0  |         { | 
525  | 0  |             XMMReg4Float d0(cst);  | 
526  | 0  |             XMMReg4Float d1(cst);  | 
527  | 0  |             XMMReg4Float d2(cst);  | 
528  | 0  |             XMMReg4Float d3(cst);  | 
529  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
530  | 0  |             { | 
531  | 0  |                 XMMReg4Float t0, t1, t2, t3;  | 
532  | 0  |                 XMMReg4Float::Load16Val(  | 
533  | 0  |                     static_cast<const Tsrc * CPL_RESTRICT>(papoSources[iSrc]) +  | 
534  | 0  |                         iOffsetLine + iCol,  | 
535  | 0  |                     t0, t1, t2, t3);  | 
536  | 0  |                 d0 += t0;  | 
537  | 0  |                 d1 += t1;  | 
538  | 0  |                 d2 += t2;  | 
539  | 0  |                 d3 += t3;  | 
540  | 0  |             }  | 
541  | 0  |             d0.Store4Val(pDest + iCol + VALUES_PER_REG * 0);  | 
542  | 0  |             d1.Store4Val(pDest + iCol + VALUES_PER_REG * 1);  | 
543  | 0  |             d2.Store4Val(pDest + iCol + VALUES_PER_REG * 2);  | 
544  | 0  |             d3.Store4Val(pDest + iCol + VALUES_PER_REG * 3);  | 
545  | 0  |         }  | 
546  |  | 
  | 
547  | 0  |         for (; iCol < nXSize; iCol++)  | 
548  | 0  |         { | 
549  | 0  |             float d = static_cast<float>(dfK);  | 
550  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
551  | 0  |             { | 
552  | 0  |                 d += static_cast<const Tsrc * CPL_RESTRICT>(  | 
553  | 0  |                     papoSources[iSrc])[iOffsetLine + iCol];  | 
554  | 0  |             }  | 
555  | 0  |             pDest[iCol] = d;  | 
556  | 0  |         }  | 
557  | 0  |     }  | 
558  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<unsigned char>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<unsigned short>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<short>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<int>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToFloat_SSE2<float>(double, void*, int, int, int, int, void const* const*)  | 
559  |  |  | 
560  |  | /************************************************************************/  | 
561  |  | /*                       OptimizedSumToDouble_SSE2()                    */  | 
562  |  | /************************************************************************/  | 
563  |  |  | 
564  |  | template <typename Tsrc>  | 
565  |  | static void OptimizedSumToDouble_SSE2(double dfK, void *pOutBuffer,  | 
566  |  |                                       int nLineSpace, int nXSize, int nYSize,  | 
567  |  |                                       int nSources,  | 
568  |  |                                       const void *const *papoSources)  | 
569  | 0  | { | 
570  | 0  |     const XMMReg4Double cst = XMMReg4Double::Set1(dfK);  | 
571  |  | 
  | 
572  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
573  | 0  |     { | 
574  | 0  |         double *CPL_RESTRICT const pDest = reinterpret_cast<double *>(  | 
575  | 0  |             static_cast<GByte *>(pOutBuffer) +  | 
576  | 0  |             static_cast<GSpacing>(nLineSpace) * iLine);  | 
577  | 0  |         const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;  | 
578  |  | 
  | 
579  | 0  |         constexpr int VALUES_PER_REG = 4;  | 
580  | 0  |         constexpr int UNROLLING = 2 * VALUES_PER_REG;  | 
581  | 0  |         int iCol = 0;  | 
582  | 0  |         for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)  | 
583  | 0  |         { | 
584  | 0  |             XMMReg4Double d0(cst);  | 
585  | 0  |             XMMReg4Double d1(cst);  | 
586  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
587  | 0  |             { | 
588  | 0  |                 XMMReg4Double t0, t1;  | 
589  | 0  |                 XMMReg4Double::Load8Val(  | 
590  | 0  |                     static_cast<const Tsrc * CPL_RESTRICT>(papoSources[iSrc]) +  | 
591  | 0  |                         iOffsetLine + iCol,  | 
592  | 0  |                     t0, t1);  | 
593  | 0  |                 d0 += t0;  | 
594  | 0  |                 d1 += t1;  | 
595  | 0  |             }  | 
596  | 0  |             d0.Store4Val(pDest + iCol + VALUES_PER_REG * 0);  | 
597  | 0  |             d1.Store4Val(pDest + iCol + VALUES_PER_REG * 1);  | 
598  | 0  |         }  | 
599  |  | 
  | 
600  | 0  |         for (; iCol < nXSize; iCol++)  | 
601  | 0  |         { | 
602  | 0  |             double d = dfK;  | 
603  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
604  | 0  |             { | 
605  | 0  |                 d += static_cast<const Tsrc * CPL_RESTRICT>(  | 
606  | 0  |                     papoSources[iSrc])[iOffsetLine + iCol];  | 
607  | 0  |             }  | 
608  | 0  |             pDest[iCol] = d;  | 
609  | 0  |         }  | 
610  | 0  |     }  | 
611  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<unsigned char>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<unsigned short>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<short>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<int>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumToDouble_SSE2<double>(double, void*, int, int, int, int, void const* const*)  | 
612  |  |  | 
613  |  | #endif  // USE_SSE2  | 
614  |  |  | 
615  |  | /************************************************************************/  | 
616  |  | /*                       OptimizedSumPackedOutput()                     */  | 
617  |  | /************************************************************************/  | 
618  |  |  | 
619  |  | template <typename Tsrc, typename Tdest>  | 
620  |  | static void OptimizedSumPackedOutput(double dfK, void *pOutBuffer,  | 
621  |  |                                      int nLineSpace, int nXSize, int nYSize,  | 
622  |  |                                      int nSources,  | 
623  |  |                                      const void *const *papoSources)  | 
624  | 0  | { | 
625  | 0  | #ifdef USE_SSE2  | 
626  |  |     if constexpr (std::is_same_v<Tdest, float> && !std::is_same_v<Tsrc, double>)  | 
627  | 0  |     { | 
628  | 0  |         OptimizedSumToFloat_SSE2<Tsrc>(dfK, pOutBuffer, nLineSpace, nXSize,  | 
629  | 0  |                                        nYSize, nSources, papoSources);  | 
630  |  |     }  | 
631  |  |     else if constexpr (std::is_same_v<Tdest, double>)  | 
632  | 0  |     { | 
633  | 0  |         OptimizedSumToDouble_SSE2<Tsrc>(dfK, pOutBuffer, nLineSpace, nXSize,  | 
634  | 0  |                                         nYSize, nSources, papoSources);  | 
635  |  |     }  | 
636  |  |     else  | 
637  |  | #endif  // USE_SSE2  | 
638  | 0  |     { | 
639  | 0  |         const Tdest nCst = static_cast<Tdest>(dfK);  | 
640  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
641  | 0  |         { | 
642  | 0  |             Tdest *CPL_RESTRICT const pDest = reinterpret_cast<Tdest *>(  | 
643  | 0  |                 static_cast<GByte *>(pOutBuffer) +  | 
644  | 0  |                 static_cast<GSpacing>(nLineSpace) * iLine);  | 
645  | 0  |             const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;  | 
646  |  | 
  | 
647  | 0  | #define LOAD_SRCVAL(iSrc_, j_)                                                 \  | 
648  | 0  |     static_cast<Tdest>(static_cast<const Tsrc * CPL_RESTRICT>(                 \  | 
649  | 0  |         papoSources[(iSrc_)])[iOffsetLine + iCol + (j_)])  | 
650  |  | 
  | 
651  | 0  |             constexpr int UNROLLING = 4;  | 
652  | 0  |             int iCol = 0;  | 
653  | 0  |             for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)  | 
654  | 0  |             { | 
655  | 0  |                 Tdest d[4] = {nCst, nCst, nCst, nCst}; | 
656  | 0  |                 for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
657  | 0  |                 { | 
658  | 0  |                     d[0] += LOAD_SRCVAL(iSrc, 0);  | 
659  | 0  |                     d[1] += LOAD_SRCVAL(iSrc, 1);  | 
660  | 0  |                     d[2] += LOAD_SRCVAL(iSrc, 2);  | 
661  | 0  |                     d[3] += LOAD_SRCVAL(iSrc, 3);  | 
662  | 0  |                 }  | 
663  | 0  |                 pDest[iCol + 0] = d[0];  | 
664  | 0  |                 pDest[iCol + 1] = d[1];  | 
665  | 0  |                 pDest[iCol + 2] = d[2];  | 
666  | 0  |                 pDest[iCol + 3] = d[3];  | 
667  | 0  |             }  | 
668  | 0  |             for (; iCol < nXSize; iCol++)  | 
669  | 0  |             { | 
670  | 0  |                 Tdest d0 = nCst;  | 
671  | 0  |                 for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
672  | 0  |                 { | 
673  | 0  |                     d0 += LOAD_SRCVAL(iSrc, 0);  | 
674  | 0  |                 }  | 
675  | 0  |                 pDest[iCol] = d0;  | 
676  | 0  |             }  | 
677  | 0  | #undef LOAD_SRCVAL  | 
678  | 0  |         }  | 
679  | 0  |     }  | 
680  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned char, float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned short, float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<short, float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<int, float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<float, float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<double, float>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned char, double>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned short, double>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<short, double>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<int, double>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<float, double>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<double, double>(double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumPackedOutput<unsigned char, int>(double, void*, int, int, int, int, void const* const*)  | 
681  |  |  | 
682  |  | /************************************************************************/  | 
683  |  | /*                       OptimizedSumPackedOutput()                     */  | 
684  |  | /************************************************************************/  | 
685  |  |  | 
686  |  | template <typename Tdest>  | 
687  |  | static bool OptimizedSumPackedOutput(GDALDataType eSrcType, double dfK,  | 
688  |  |                                      void *pOutBuffer, int nLineSpace,  | 
689  |  |                                      int nXSize, int nYSize, int nSources,  | 
690  |  |                                      const void *const *papoSources)  | 
691  | 0  | { | 
692  | 0  |     switch (eSrcType)  | 
693  | 0  |     { | 
694  | 0  |         case GDT_Byte:  | 
695  | 0  |             OptimizedSumPackedOutput<uint8_t, Tdest>(dfK, pOutBuffer,  | 
696  | 0  |                                                      nLineSpace, nXSize, nYSize,  | 
697  | 0  |                                                      nSources, papoSources);  | 
698  | 0  |             return true;  | 
699  |  |  | 
700  | 0  |         case GDT_UInt16:  | 
701  | 0  |             OptimizedSumPackedOutput<uint16_t, Tdest>(  | 
702  | 0  |                 dfK, pOutBuffer, nLineSpace, nXSize, nYSize, nSources,  | 
703  | 0  |                 papoSources);  | 
704  | 0  |             return true;  | 
705  |  |  | 
706  | 0  |         case GDT_Int16:  | 
707  | 0  |             OptimizedSumPackedOutput<int16_t, Tdest>(dfK, pOutBuffer,  | 
708  | 0  |                                                      nLineSpace, nXSize, nYSize,  | 
709  | 0  |                                                      nSources, papoSources);  | 
710  | 0  |             return true;  | 
711  |  |  | 
712  | 0  |         case GDT_Int32:  | 
713  | 0  |             OptimizedSumPackedOutput<int32_t, Tdest>(dfK, pOutBuffer,  | 
714  | 0  |                                                      nLineSpace, nXSize, nYSize,  | 
715  | 0  |                                                      nSources, papoSources);  | 
716  | 0  |             return true;  | 
717  |  |  | 
718  | 0  |         case GDT_Float32:  | 
719  | 0  |             OptimizedSumPackedOutput<float, Tdest>(dfK, pOutBuffer, nLineSpace,  | 
720  | 0  |                                                    nXSize, nYSize, nSources,  | 
721  | 0  |                                                    papoSources);  | 
722  | 0  |             return true;  | 
723  |  |  | 
724  | 0  |         case GDT_Float64:  | 
725  | 0  |             OptimizedSumPackedOutput<double, Tdest>(dfK, pOutBuffer, nLineSpace,  | 
726  | 0  |                                                     nXSize, nYSize, nSources,  | 
727  | 0  |                                                     papoSources);  | 
728  | 0  |             return true;  | 
729  |  |  | 
730  | 0  |         default:  | 
731  | 0  |             break;  | 
732  | 0  |     }  | 
733  | 0  |     return false;  | 
734  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumPackedOutput<float>(GDALDataType, double, void*, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumPackedOutput<double>(GDALDataType, double, void*, int, int, int, int, void const* const*)  | 
735  |  |  | 
736  |  | /************************************************************************/  | 
737  |  | /*                    OptimizedSumThroughLargerType()                   */  | 
738  |  | /************************************************************************/  | 
739  |  |  | 
740  |  | namespace  | 
741  |  | { | 
742  |  | template <typename Tsrc, typename Tdest, typename Enable = void>  | 
743  |  | struct TintermediateS  | 
744  |  | { | 
745  |  |     using type = double;  | 
746  |  | };  | 
747  |  |  | 
748  |  | template <typename Tsrc, typename Tdest>  | 
749  |  | struct TintermediateS<  | 
750  |  |     Tsrc, Tdest,  | 
751  |  |     std::enable_if_t<  | 
752  |  |         (std::is_same_v<Tsrc, uint8_t> || std::is_same_v<Tsrc, int16_t> ||  | 
753  |  |          std::is_same_v<Tsrc, uint16_t>)&&(std::is_same_v<Tdest, uint8_t> ||  | 
754  |  |                                            std::is_same_v<Tdest, int16_t> ||  | 
755  |  |                                            std::is_same_v<Tdest, uint16_t>),  | 
756  |  |         bool>>  | 
757  |  | { | 
758  |  |     using type = int32_t;  | 
759  |  | };  | 
760  |  |  | 
761  |  | }  // namespace  | 
762  |  |  | 
763  |  | template <typename Tsrc, typename Tdest>  | 
764  |  | static bool OptimizedSumThroughLargerType(double dfK, void *pOutBuffer,  | 
765  |  |                                           int nPixelSpace, int nLineSpace,  | 
766  |  |                                           int nXSize, int nYSize, int nSources,  | 
767  |  |                                           const void *const *papoSources)  | 
768  | 0  | { | 
769  | 0  |     using Tintermediate = typename TintermediateS<Tsrc, Tdest>::type;  | 
770  | 0  |     const Tintermediate k = static_cast<Tintermediate>(dfK);  | 
771  |  | 
  | 
772  | 0  |     size_t ii = 0;  | 
773  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
774  | 0  |     { | 
775  | 0  |         GByte *CPL_RESTRICT pDest = static_cast<GByte *>(pOutBuffer) +  | 
776  | 0  |                                     static_cast<GSpacing>(nLineSpace) * iLine;  | 
777  |  | 
  | 
778  | 0  |         constexpr int UNROLLING = 4;  | 
779  | 0  |         int iCol = 0;  | 
780  | 0  |         for (; iCol < nXSize - (UNROLLING - 1);  | 
781  | 0  |              iCol += UNROLLING, ii += UNROLLING)  | 
782  | 0  |         { | 
783  | 0  |             Tintermediate aSum[4] = {k, k, k, k}; | 
784  |  | 
  | 
785  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
786  | 0  |             { | 
787  | 0  |                 aSum[0] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 0];  | 
788  | 0  |                 aSum[1] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 1];  | 
789  | 0  |                 aSum[2] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 2];  | 
790  | 0  |                 aSum[3] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 3];  | 
791  | 0  |             }  | 
792  |  | 
  | 
793  | 0  |             GDALCopyWord(aSum[0], *reinterpret_cast<Tdest *>(pDest));  | 
794  | 0  |             pDest += nPixelSpace;  | 
795  | 0  |             GDALCopyWord(aSum[1], *reinterpret_cast<Tdest *>(pDest));  | 
796  | 0  |             pDest += nPixelSpace;  | 
797  | 0  |             GDALCopyWord(aSum[2], *reinterpret_cast<Tdest *>(pDest));  | 
798  | 0  |             pDest += nPixelSpace;  | 
799  | 0  |             GDALCopyWord(aSum[3], *reinterpret_cast<Tdest *>(pDest));  | 
800  | 0  |             pDest += nPixelSpace;  | 
801  | 0  |         }  | 
802  | 0  |         for (; iCol < nXSize; ++iCol, ++ii, pDest += nPixelSpace)  | 
803  | 0  |         { | 
804  | 0  |             Tintermediate sum = k;  | 
805  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
806  | 0  |             { | 
807  | 0  |                 sum += static_cast<const Tsrc *>(papoSources[iSrc])[ii];  | 
808  | 0  |             }  | 
809  |  | 
  | 
810  | 0  |             auto pDst = reinterpret_cast<Tdest *>(pDest);  | 
811  | 0  |             GDALCopyWord(sum, *pDst);  | 
812  | 0  |         }  | 
813  | 0  |     }  | 
814  | 0  |     return true;  | 
815  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, unsigned char>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, unsigned short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char, int>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, unsigned char>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, unsigned short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short, int>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, unsigned char>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, unsigned short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short, int>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, unsigned char>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, unsigned short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int, int>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, unsigned char>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, unsigned short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float, int>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, unsigned char>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, unsigned short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, short>(double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double, int>(double, void*, int, int, int, int, int, void const* const*)  | 
816  |  |  | 
817  |  | /************************************************************************/  | 
818  |  | /*                     OptimizedSumThroughLargerType()                  */  | 
819  |  | /************************************************************************/  | 
820  |  |  | 
821  |  | template <typename Tsrc>  | 
822  |  | static bool OptimizedSumThroughLargerType(GDALDataType eBufType, double dfK,  | 
823  |  |                                           void *pOutBuffer, int nPixelSpace,  | 
824  |  |                                           int nLineSpace, int nXSize,  | 
825  |  |                                           int nYSize, int nSources,  | 
826  |  |                                           const void *const *papoSources)  | 
827  | 0  | { | 
828  | 0  |     switch (eBufType)  | 
829  | 0  |     { | 
830  | 0  |         case GDT_Byte:  | 
831  | 0  |             return OptimizedSumThroughLargerType<Tsrc, uint8_t>(  | 
832  | 0  |                 dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,  | 
833  | 0  |                 nSources, papoSources);  | 
834  |  |  | 
835  | 0  |         case GDT_UInt16:  | 
836  | 0  |             return OptimizedSumThroughLargerType<Tsrc, uint16_t>(  | 
837  | 0  |                 dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,  | 
838  | 0  |                 nSources, papoSources);  | 
839  |  |  | 
840  | 0  |         case GDT_Int16:  | 
841  | 0  |             return OptimizedSumThroughLargerType<Tsrc, int16_t>(  | 
842  | 0  |                 dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,  | 
843  | 0  |                 nSources, papoSources);  | 
844  |  |  | 
845  | 0  |         case GDT_Int32:  | 
846  | 0  |             return OptimizedSumThroughLargerType<Tsrc, int32_t>(  | 
847  | 0  |                 dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,  | 
848  | 0  |                 nSources, papoSources);  | 
849  |  |  | 
850  |  |         // Float32 and Float64 already covered by OptimizedSum() for packed case  | 
851  | 0  |         default:  | 
852  | 0  |             break;  | 
853  | 0  |     }  | 
854  | 0  |     return false;  | 
855  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned char>(GDALDataType, double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<unsigned short>(GDALDataType, double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<short>(GDALDataType, double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<int>(GDALDataType, double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<float>(GDALDataType, double, void*, int, int, int, int, int, void const* const*) Unexecuted instantiation: pixelfunctions.cpp:bool OptimizedSumThroughLargerType<double>(GDALDataType, double, void*, int, int, int, int, int, void const* const*)  | 
856  |  |  | 
857  |  | /************************************************************************/  | 
858  |  | /*                    OptimizedSumThroughLargerType()                   */  | 
859  |  | /************************************************************************/  | 
860  |  |  | 
861  |  | static bool OptimizedSumThroughLargerType(GDALDataType eSrcType,  | 
862  |  |                                           GDALDataType eBufType, double dfK,  | 
863  |  |                                           void *pOutBuffer, int nPixelSpace,  | 
864  |  |                                           int nLineSpace, int nXSize,  | 
865  |  |                                           int nYSize, int nSources,  | 
866  |  |                                           const void *const *papoSources)  | 
867  | 0  | { | 
868  | 0  |     switch (eSrcType)  | 
869  | 0  |     { | 
870  | 0  |         case GDT_Byte:  | 
871  | 0  |             return OptimizedSumThroughLargerType<uint8_t>(  | 
872  | 0  |                 eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,  | 
873  | 0  |                 nYSize, nSources, papoSources);  | 
874  |  |  | 
875  | 0  |         case GDT_UInt16:  | 
876  | 0  |             return OptimizedSumThroughLargerType<uint16_t>(  | 
877  | 0  |                 eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,  | 
878  | 0  |                 nYSize, nSources, papoSources);  | 
879  |  |  | 
880  | 0  |         case GDT_Int16:  | 
881  | 0  |             return OptimizedSumThroughLargerType<int16_t>(  | 
882  | 0  |                 eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,  | 
883  | 0  |                 nYSize, nSources, papoSources);  | 
884  |  |  | 
885  | 0  |         case GDT_Int32:  | 
886  | 0  |             return OptimizedSumThroughLargerType<int32_t>(  | 
887  | 0  |                 eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,  | 
888  | 0  |                 nYSize, nSources, papoSources);  | 
889  |  |  | 
890  | 0  |         case GDT_Float32:  | 
891  | 0  |             return OptimizedSumThroughLargerType<float>(  | 
892  | 0  |                 eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,  | 
893  | 0  |                 nYSize, nSources, papoSources);  | 
894  |  |  | 
895  | 0  |         case GDT_Float64:  | 
896  | 0  |             return OptimizedSumThroughLargerType<double>(  | 
897  | 0  |                 eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,  | 
898  | 0  |                 nYSize, nSources, papoSources);  | 
899  |  |  | 
900  | 0  |         default:  | 
901  | 0  |             break;  | 
902  | 0  |     }  | 
903  |  |  | 
904  | 0  |     return false;  | 
905  | 0  | }  | 
906  |  |  | 
907  |  | /************************************************************************/  | 
908  |  | /*                            SumPixelFunc()                            */  | 
909  |  | /************************************************************************/  | 
910  |  |  | 
911  |  | static const char pszSumPixelFuncMetadata[] =  | 
912  |  |     "<PixelFunctionArgumentsList>"  | 
913  |  |     "   <Argument name='k' description='Optional constant term' type='double' "  | 
914  |  |     "default='0.0' />"  | 
915  |  |     "   <Argument name='propagateNoData' description='Whether the output value "  | 
916  |  |     "should be NoData as as soon as one source is NoData' type='boolean' "  | 
917  |  |     "default='false' />"  | 
918  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
919  |  |     "</PixelFunctionArgumentsList>";  | 
920  |  |  | 
921  |  | static CPLErr SumPixelFunc(void **papoSources, int nSources, void *pData,  | 
922  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
923  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
924  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
925  | 0  | { | 
926  |  |     /* ---- Init ---- */  | 
927  | 0  |     if (nSources < 1)  | 
928  | 0  |     { | 
929  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
930  | 0  |                  "sum requires at least one source");  | 
931  | 0  |         return CE_Failure;  | 
932  | 0  |     }  | 
933  |  |  | 
934  | 0  |     double dfK = 0.0;  | 
935  | 0  |     if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)  | 
936  | 0  |         return CE_Failure;  | 
937  |  |  | 
938  | 0  |     double dfNoData{0}; | 
939  | 0  |     bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
940  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
941  | 0  |         return CE_Failure;  | 
942  |  |  | 
943  | 0  |     const bool bPropagateNoData = CPLTestBool(  | 
944  | 0  |         CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));  | 
945  |  | 
  | 
946  | 0  |     if (dfNoData == 0 && !bPropagateNoData)  | 
947  | 0  |         bHasNoData = false;  | 
948  |  |  | 
949  |  |     /* ---- Set pixels ---- */  | 
950  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
951  | 0  |     { | 
952  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
953  |  |  | 
954  |  |         /* ---- Set pixels ---- */  | 
955  | 0  |         size_t ii = 0;  | 
956  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
957  | 0  |         { | 
958  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
959  | 0  |             { | 
960  | 0  |                 double adfSum[2] = {dfK, 0.0}; | 
961  |  | 
  | 
962  | 0  |                 for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
963  | 0  |                 { | 
964  | 0  |                     const void *const pReal = papoSources[iSrc];  | 
965  | 0  |                     const void *const pImag =  | 
966  | 0  |                         static_cast<const GByte *>(pReal) + nOffset;  | 
967  |  |  | 
968  |  |                     // Source raster pixels may be obtained with GetSrcVal  | 
969  |  |                     // macro.  | 
970  | 0  |                     adfSum[0] += GetSrcVal(pReal, eSrcType, ii);  | 
971  | 0  |                     adfSum[1] += GetSrcVal(pImag, eSrcType, ii);  | 
972  | 0  |                 }  | 
973  |  | 
  | 
974  | 0  |                 GDALCopyWords(adfSum, GDT_CFloat64, 0,  | 
975  | 0  |                               static_cast<GByte *>(pData) +  | 
976  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
977  | 0  |                                   iCol * nPixelSpace,  | 
978  | 0  |                               eBufType, nPixelSpace, 1);  | 
979  | 0  |             }  | 
980  | 0  |         }  | 
981  | 0  |     }  | 
982  | 0  |     else  | 
983  | 0  |     { | 
984  |  |         /* ---- Set pixels ---- */  | 
985  | 0  |         bool bGeneralCase = true;  | 
986  | 0  |         if (dfNoData == 0 && !bPropagateNoData)  | 
987  | 0  |         { | 
988  | 0  |             if (eBufType == GDT_Float32 && nPixelSpace == sizeof(float))  | 
989  | 0  |             { | 
990  | 0  |                 bGeneralCase = !OptimizedSumPackedOutput<float>(  | 
991  | 0  |                     eSrcType, dfK, pData, nLineSpace, nXSize, nYSize, nSources,  | 
992  | 0  |                     papoSources);  | 
993  | 0  |             }  | 
994  | 0  |             else if (eBufType == GDT_Float64 && nPixelSpace == sizeof(double))  | 
995  | 0  |             { | 
996  | 0  |                 bGeneralCase = !OptimizedSumPackedOutput<double>(  | 
997  | 0  |                     eSrcType, dfK, pData, nLineSpace, nXSize, nYSize, nSources,  | 
998  | 0  |                     papoSources);  | 
999  | 0  |             }  | 
1000  | 0  |             else if (  | 
1001  | 0  |                 dfK >= 0 && dfK <= INT_MAX && eBufType == GDT_Int32 &&  | 
1002  | 0  |                 nPixelSpace == sizeof(int32_t) && eSrcType == GDT_Byte &&  | 
1003  |  |                 // Limitation to avoid overflow of int32 if all source values are at the max of their data type  | 
1004  | 0  |                 nSources <=  | 
1005  | 0  |                     (INT_MAX - dfK) / std::numeric_limits<uint8_t>::max())  | 
1006  | 0  |             { | 
1007  | 0  |                 bGeneralCase = false;  | 
1008  | 0  |                 OptimizedSumPackedOutput<uint8_t, int32_t>(  | 
1009  | 0  |                     dfK, pData, nLineSpace, nXSize, nYSize, nSources,  | 
1010  | 0  |                     papoSources);  | 
1011  | 0  |             }  | 
1012  |  | 
  | 
1013  | 0  |             if (bGeneralCase && dfK >= 0 && dfK <= INT_MAX &&  | 
1014  | 0  |                 nSources <=  | 
1015  | 0  |                     (INT_MAX - dfK) / std::numeric_limits<uint16_t>::max())  | 
1016  | 0  |             { | 
1017  | 0  |                 bGeneralCase = !OptimizedSumThroughLargerType(  | 
1018  | 0  |                     eSrcType, eBufType, dfK, pData, nPixelSpace, nLineSpace,  | 
1019  | 0  |                     nXSize, nYSize, nSources, papoSources);  | 
1020  | 0  |             }  | 
1021  | 0  |         }  | 
1022  |  | 
  | 
1023  | 0  |         if (bGeneralCase)  | 
1024  | 0  |         { | 
1025  | 0  |             size_t ii = 0;  | 
1026  | 0  |             for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1027  | 0  |             { | 
1028  | 0  |                 for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1029  | 0  |                 { | 
1030  | 0  |                     double dfSum = dfK;  | 
1031  | 0  |                     for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
1032  | 0  |                     { | 
1033  | 0  |                         const double dfVal =  | 
1034  | 0  |                             GetSrcVal(papoSources[iSrc], eSrcType, ii);  | 
1035  |  | 
  | 
1036  | 0  |                         if (bHasNoData && IsNoData(dfVal, dfNoData))  | 
1037  | 0  |                         { | 
1038  | 0  |                             if (bPropagateNoData)  | 
1039  | 0  |                             { | 
1040  | 0  |                                 dfSum = dfNoData;  | 
1041  | 0  |                                 break;  | 
1042  | 0  |                             }  | 
1043  | 0  |                         }  | 
1044  | 0  |                         else  | 
1045  | 0  |                         { | 
1046  | 0  |                             dfSum += dfVal;  | 
1047  | 0  |                         }  | 
1048  | 0  |                     }  | 
1049  |  | 
  | 
1050  | 0  |                     GDALCopyWords(&dfSum, GDT_Float64, 0,  | 
1051  | 0  |                                   static_cast<GByte *>(pData) +  | 
1052  | 0  |                                       static_cast<GSpacing>(nLineSpace) *  | 
1053  | 0  |                                           iLine +  | 
1054  | 0  |                                       iCol * nPixelSpace,  | 
1055  | 0  |                                   eBufType, nPixelSpace, 1);  | 
1056  | 0  |                 }  | 
1057  | 0  |             }  | 
1058  | 0  |         }  | 
1059  | 0  |     }  | 
1060  |  |  | 
1061  |  |     /* ---- Return success ---- */  | 
1062  | 0  |     return CE_None;  | 
1063  | 0  | } /* SumPixelFunc */  | 
1064  |  |  | 
1065  |  | static const char pszDiffPixelFuncMetadata[] =  | 
1066  |  |     "<PixelFunctionArgumentsList>"  | 
1067  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
1068  |  |     "</PixelFunctionArgumentsList>";  | 
1069  |  |  | 
1070  |  | static CPLErr DiffPixelFunc(void **papoSources, int nSources, void *pData,  | 
1071  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
1072  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
1073  |  |                             int nLineSpace, CSLConstList papszArgs)  | 
1074  | 0  | { | 
1075  |  |     /* ---- Init ---- */  | 
1076  | 0  |     if (nSources != 2)  | 
1077  | 0  |         return CE_Failure;  | 
1078  |  |  | 
1079  | 0  |     double dfNoData{0}; | 
1080  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1081  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1082  | 0  |         return CE_Failure;  | 
1083  |  |  | 
1084  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1085  | 0  |     { | 
1086  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1087  | 0  |         const void *const pReal0 = papoSources[0];  | 
1088  | 0  |         const void *const pImag0 =  | 
1089  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
1090  | 0  |         const void *const pReal1 = papoSources[1];  | 
1091  | 0  |         const void *const pImag1 =  | 
1092  | 0  |             static_cast<GByte *>(papoSources[1]) + nOffset;  | 
1093  |  |  | 
1094  |  |         /* ---- Set pixels ---- */  | 
1095  | 0  |         size_t ii = 0;  | 
1096  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1097  | 0  |         { | 
1098  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1099  | 0  |             { | 
1100  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1101  | 0  |                 double adfPixVal[2] = {GetSrcVal(pReal0, eSrcType, ii) - | 
1102  | 0  |                                            GetSrcVal(pReal1, eSrcType, ii),  | 
1103  | 0  |                                        GetSrcVal(pImag0, eSrcType, ii) -  | 
1104  | 0  |                                            GetSrcVal(pImag1, eSrcType, ii)};  | 
1105  |  | 
  | 
1106  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
1107  | 0  |                               static_cast<GByte *>(pData) +  | 
1108  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1109  | 0  |                                   iCol * nPixelSpace,  | 
1110  | 0  |                               eBufType, nPixelSpace, 1);  | 
1111  | 0  |             }  | 
1112  | 0  |         }  | 
1113  | 0  |     }  | 
1114  | 0  |     else  | 
1115  | 0  |     { | 
1116  |  |         /* ---- Set pixels ---- */  | 
1117  | 0  |         size_t ii = 0;  | 
1118  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1119  | 0  |         { | 
1120  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1121  | 0  |             { | 
1122  | 0  |                 const double dfA = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1123  | 0  |                 const double dfB = GetSrcVal(papoSources[1], eSrcType, ii);  | 
1124  |  | 
  | 
1125  | 0  |                 const double dfPixVal =  | 
1126  | 0  |                     bHasNoData &&  | 
1127  | 0  |                             (IsNoData(dfA, dfNoData) || IsNoData(dfB, dfNoData))  | 
1128  | 0  |                         ? dfNoData  | 
1129  | 0  |                         : dfA - dfB;  | 
1130  |  | 
  | 
1131  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1132  | 0  |                               static_cast<GByte *>(pData) +  | 
1133  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1134  | 0  |                                   iCol * nPixelSpace,  | 
1135  | 0  |                               eBufType, nPixelSpace, 1);  | 
1136  | 0  |             }  | 
1137  | 0  |         }  | 
1138  | 0  |     }  | 
1139  |  |  | 
1140  |  |     /* ---- Return success ---- */  | 
1141  | 0  |     return CE_None;  | 
1142  | 0  | }  // DiffPixelFunc  | 
1143  |  |  | 
1144  |  | static const char pszMulPixelFuncMetadata[] =  | 
1145  |  |     "<PixelFunctionArgumentsList>"  | 
1146  |  |     "   <Argument name='k' description='Optional constant factor' "  | 
1147  |  |     "type='double' default='1.0' />"  | 
1148  |  |     "   <Argument name='propagateNoData' description='Whether the output value "  | 
1149  |  |     "should be NoData as as soon as one source is NoData' type='boolean' "  | 
1150  |  |     "default='false' />"  | 
1151  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
1152  |  |     "</PixelFunctionArgumentsList>";  | 
1153  |  |  | 
1154  |  | static CPLErr MulPixelFunc(void **papoSources, int nSources, void *pData,  | 
1155  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
1156  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
1157  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
1158  | 0  | { | 
1159  |  |     /* ---- Init ---- */  | 
1160  | 0  |     if (nSources < 2 && CSLFetchNameValue(papszArgs, "k") == nullptr)  | 
1161  | 0  |     { | 
1162  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
1163  | 0  |                  "mul requires at least two sources or a specified constant k");  | 
1164  | 0  |         return CE_Failure;  | 
1165  | 0  |     }  | 
1166  |  |  | 
1167  | 0  |     double dfK = 1.0;  | 
1168  | 0  |     if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)  | 
1169  | 0  |         return CE_Failure;  | 
1170  |  |  | 
1171  | 0  |     double dfNoData{0}; | 
1172  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1173  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1174  | 0  |         return CE_Failure;  | 
1175  |  |  | 
1176  | 0  |     const bool bPropagateNoData = CPLTestBool(  | 
1177  | 0  |         CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));  | 
1178  |  |  | 
1179  |  |     /* ---- Set pixels ---- */  | 
1180  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1181  | 0  |     { | 
1182  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1183  |  |  | 
1184  |  |         /* ---- Set pixels ---- */  | 
1185  | 0  |         size_t ii = 0;  | 
1186  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1187  | 0  |         { | 
1188  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1189  | 0  |             { | 
1190  | 0  |                 double adfPixVal[2] = {dfK, 0.0}; | 
1191  |  | 
  | 
1192  | 0  |                 for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
1193  | 0  |                 { | 
1194  | 0  |                     const void *const pReal = papoSources[iSrc];  | 
1195  | 0  |                     const void *const pImag =  | 
1196  | 0  |                         static_cast<const GByte *>(pReal) + nOffset;  | 
1197  |  | 
  | 
1198  | 0  |                     const double dfOldR = adfPixVal[0];  | 
1199  | 0  |                     const double dfOldI = adfPixVal[1];  | 
1200  |  |  | 
1201  |  |                     // Source raster pixels may be obtained with GetSrcVal  | 
1202  |  |                     // macro.  | 
1203  | 0  |                     const double dfNewR = GetSrcVal(pReal, eSrcType, ii);  | 
1204  | 0  |                     const double dfNewI = GetSrcVal(pImag, eSrcType, ii);  | 
1205  |  | 
  | 
1206  | 0  |                     adfPixVal[0] = dfOldR * dfNewR - dfOldI * dfNewI;  | 
1207  | 0  |                     adfPixVal[1] = dfOldR * dfNewI + dfOldI * dfNewR;  | 
1208  | 0  |                 }  | 
1209  |  | 
  | 
1210  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
1211  | 0  |                               static_cast<GByte *>(pData) +  | 
1212  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1213  | 0  |                                   iCol * nPixelSpace,  | 
1214  | 0  |                               eBufType, nPixelSpace, 1);  | 
1215  | 0  |             }  | 
1216  | 0  |         }  | 
1217  | 0  |     }  | 
1218  | 0  |     else  | 
1219  | 0  |     { | 
1220  |  |         /* ---- Set pixels ---- */  | 
1221  | 0  |         size_t ii = 0;  | 
1222  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1223  | 0  |         { | 
1224  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1225  | 0  |             { | 
1226  | 0  |                 double dfPixVal = dfK;  // Not complex.  | 
1227  |  | 
  | 
1228  | 0  |                 for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
1229  | 0  |                 { | 
1230  | 0  |                     const double dfVal =  | 
1231  | 0  |                         GetSrcVal(papoSources[iSrc], eSrcType, ii);  | 
1232  |  | 
  | 
1233  | 0  |                     if (bHasNoData && IsNoData(dfVal, dfNoData))  | 
1234  | 0  |                     { | 
1235  | 0  |                         if (bPropagateNoData)  | 
1236  | 0  |                         { | 
1237  | 0  |                             dfPixVal = dfNoData;  | 
1238  | 0  |                             break;  | 
1239  | 0  |                         }  | 
1240  | 0  |                     }  | 
1241  | 0  |                     else  | 
1242  | 0  |                     { | 
1243  | 0  |                         dfPixVal *= dfVal;  | 
1244  | 0  |                     }  | 
1245  | 0  |                 }  | 
1246  |  | 
  | 
1247  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1248  | 0  |                               static_cast<GByte *>(pData) +  | 
1249  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1250  | 0  |                                   iCol * nPixelSpace,  | 
1251  | 0  |                               eBufType, nPixelSpace, 1);  | 
1252  | 0  |             }  | 
1253  | 0  |         }  | 
1254  | 0  |     }  | 
1255  |  |  | 
1256  |  |     /* ---- Return success ---- */  | 
1257  | 0  |     return CE_None;  | 
1258  | 0  | }  // MulPixelFunc  | 
1259  |  |  | 
1260  |  | static const char pszDivPixelFuncMetadata[] =  | 
1261  |  |     "<PixelFunctionArgumentsList>"  | 
1262  |  |     "   "  | 
1263  |  |     "<Argument type='builtin' value='NoData' optional='true' />"  | 
1264  |  |     "</PixelFunctionArgumentsList>";  | 
1265  |  |  | 
1266  |  | static CPLErr DivPixelFunc(void **papoSources, int nSources, void *pData,  | 
1267  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
1268  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
1269  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
1270  | 0  | { | 
1271  |  |     /* ---- Init ---- */  | 
1272  | 0  |     if (nSources != 2)  | 
1273  | 0  |         return CE_Failure;  | 
1274  |  |  | 
1275  | 0  |     double dfNoData{0}; | 
1276  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1277  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1278  | 0  |         return CE_Failure;  | 
1279  |  |  | 
1280  |  |     /* ---- Set pixels ---- */  | 
1281  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1282  | 0  |     { | 
1283  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1284  | 0  |         const void *const pReal0 = papoSources[0];  | 
1285  | 0  |         const void *const pImag0 =  | 
1286  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
1287  | 0  |         const void *const pReal1 = papoSources[1];  | 
1288  | 0  |         const void *const pImag1 =  | 
1289  | 0  |             static_cast<GByte *>(papoSources[1]) + nOffset;  | 
1290  |  |  | 
1291  |  |         /* ---- Set pixels ---- */  | 
1292  | 0  |         size_t ii = 0;  | 
1293  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1294  | 0  |         { | 
1295  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1296  | 0  |             { | 
1297  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1298  | 0  |                 const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);  | 
1299  | 0  |                 const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);  | 
1300  | 0  |                 const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);  | 
1301  | 0  |                 const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);  | 
1302  | 0  |                 const double dfAux = dfReal1 * dfReal1 + dfImag1 * dfImag1;  | 
1303  |  | 
  | 
1304  | 0  |                 const double adfPixVal[2] = { | 
1305  | 0  |                     dfAux == 0  | 
1306  | 0  |                         ? std::numeric_limits<double>::infinity()  | 
1307  | 0  |                         : dfReal0 * dfReal1 / dfAux + dfImag0 * dfImag1 / dfAux,  | 
1308  | 0  |                     dfAux == 0 ? std::numeric_limits<double>::infinity()  | 
1309  | 0  |                                : dfReal1 / dfAux * dfImag0 -  | 
1310  | 0  |                                      dfReal0 * dfImag1 / dfAux};  | 
1311  |  | 
  | 
1312  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
1313  | 0  |                               static_cast<GByte *>(pData) +  | 
1314  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1315  | 0  |                                   iCol * nPixelSpace,  | 
1316  | 0  |                               eBufType, nPixelSpace, 1);  | 
1317  | 0  |             }  | 
1318  | 0  |         }  | 
1319  | 0  |     }  | 
1320  | 0  |     else  | 
1321  | 0  |     { | 
1322  |  |         /* ---- Set pixels ---- */  | 
1323  | 0  |         size_t ii = 0;  | 
1324  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1325  | 0  |         { | 
1326  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1327  | 0  |             { | 
1328  | 0  |                 const double dfNum = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1329  | 0  |                 const double dfDenom = GetSrcVal(papoSources[1], eSrcType, ii);  | 
1330  |  | 
  | 
1331  | 0  |                 double dfPixVal = dfNoData;  | 
1332  | 0  |                 if (!bHasNoData || (!IsNoData(dfNum, dfNoData) &&  | 
1333  | 0  |                                     !IsNoData(dfDenom, dfNoData)))  | 
1334  | 0  |                 { | 
1335  |  |                     // coverity[divide_by_zero]  | 
1336  | 0  |                     dfPixVal = dfDenom == 0  | 
1337  | 0  |                                    ? std::numeric_limits<double>::infinity()  | 
1338  | 0  |                                    : dfNum / dfDenom;  | 
1339  | 0  |                 }  | 
1340  |  | 
  | 
1341  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1342  | 0  |                               static_cast<GByte *>(pData) +  | 
1343  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1344  | 0  |                                   iCol * nPixelSpace,  | 
1345  | 0  |                               eBufType, nPixelSpace, 1);  | 
1346  | 0  |             }  | 
1347  | 0  |         }  | 
1348  | 0  |     }  | 
1349  |  |  | 
1350  |  |     /* ---- Return success ---- */  | 
1351  | 0  |     return CE_None;  | 
1352  | 0  | }  // DivPixelFunc  | 
1353  |  |  | 
1354  |  | static CPLErr CMulPixelFunc(void **papoSources, int nSources, void *pData,  | 
1355  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
1356  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
1357  |  |                             int nLineSpace)  | 
1358  | 0  | { | 
1359  |  |     /* ---- Init ---- */  | 
1360  | 0  |     if (nSources != 2)  | 
1361  | 0  |         return CE_Failure;  | 
1362  |  |  | 
1363  |  |     /* ---- Set pixels ---- */  | 
1364  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1365  | 0  |     { | 
1366  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1367  | 0  |         const void *const pReal0 = papoSources[0];  | 
1368  | 0  |         const void *const pImag0 =  | 
1369  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
1370  | 0  |         const void *const pReal1 = papoSources[1];  | 
1371  | 0  |         const void *const pImag1 =  | 
1372  | 0  |             static_cast<GByte *>(papoSources[1]) + nOffset;  | 
1373  |  | 
  | 
1374  | 0  |         size_t ii = 0;  | 
1375  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1376  | 0  |         { | 
1377  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1378  | 0  |             { | 
1379  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1380  | 0  |                 const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);  | 
1381  | 0  |                 const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);  | 
1382  | 0  |                 const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);  | 
1383  | 0  |                 const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);  | 
1384  | 0  |                 const double adfPixVal[2] = { | 
1385  | 0  |                     dfReal0 * dfReal1 + dfImag0 * dfImag1,  | 
1386  | 0  |                     dfReal1 * dfImag0 - dfReal0 * dfImag1};  | 
1387  |  | 
  | 
1388  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
1389  | 0  |                               static_cast<GByte *>(pData) +  | 
1390  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1391  | 0  |                                   iCol * nPixelSpace,  | 
1392  | 0  |                               eBufType, nPixelSpace, 1);  | 
1393  | 0  |             }  | 
1394  | 0  |         }  | 
1395  | 0  |     }  | 
1396  | 0  |     else  | 
1397  | 0  |     { | 
1398  | 0  |         size_t ii = 0;  | 
1399  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1400  | 0  |         { | 
1401  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1402  | 0  |             { | 
1403  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1404  |  |                 // Not complex.  | 
1405  | 0  |                 const double adfPixVal[2] = { | 
1406  | 0  |                     GetSrcVal(papoSources[0], eSrcType, ii) *  | 
1407  | 0  |                         GetSrcVal(papoSources[1], eSrcType, ii),  | 
1408  | 0  |                     0.0};  | 
1409  |  | 
  | 
1410  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
1411  | 0  |                               static_cast<GByte *>(pData) +  | 
1412  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1413  | 0  |                                   iCol * nPixelSpace,  | 
1414  | 0  |                               eBufType, nPixelSpace, 1);  | 
1415  | 0  |             }  | 
1416  | 0  |         }  | 
1417  | 0  |     }  | 
1418  |  |  | 
1419  |  |     /* ---- Return success ---- */  | 
1420  | 0  |     return CE_None;  | 
1421  | 0  | }  // CMulPixelFunc  | 
1422  |  |  | 
1423  |  | static const char pszInvPixelFuncMetadata[] =  | 
1424  |  |     "<PixelFunctionArgumentsList>"  | 
1425  |  |     "   <Argument name='k' description='Optional constant factor' "  | 
1426  |  |     "type='double' default='1.0' />"  | 
1427  |  |     "   "  | 
1428  |  |     "<Argument type='builtin' value='NoData' optional='true' />"  | 
1429  |  |     "</PixelFunctionArgumentsList>";  | 
1430  |  |  | 
1431  |  | static CPLErr InvPixelFunc(void **papoSources, int nSources, void *pData,  | 
1432  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
1433  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
1434  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
1435  | 0  | { | 
1436  |  |     /* ---- Init ---- */  | 
1437  | 0  |     if (nSources != 1)  | 
1438  | 0  |         return CE_Failure;  | 
1439  |  |  | 
1440  | 0  |     double dfK = 1.0;  | 
1441  | 0  |     if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)  | 
1442  | 0  |         return CE_Failure;  | 
1443  |  |  | 
1444  | 0  |     double dfNoData{0}; | 
1445  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1446  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1447  | 0  |         return CE_Failure;  | 
1448  |  |  | 
1449  |  |     /* ---- Set pixels ---- */  | 
1450  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1451  | 0  |     { | 
1452  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1453  | 0  |         const void *const pReal = papoSources[0];  | 
1454  | 0  |         const void *const pImag =  | 
1455  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
1456  |  | 
  | 
1457  | 0  |         size_t ii = 0;  | 
1458  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1459  | 0  |         { | 
1460  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1461  | 0  |             { | 
1462  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1463  | 0  |                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);  | 
1464  | 0  |                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);  | 
1465  | 0  |                 const double dfAux = dfReal * dfReal + dfImag * dfImag;  | 
1466  | 0  |                 const double adfPixVal[2] = { | 
1467  | 0  |                     dfAux == 0 ? std::numeric_limits<double>::infinity()  | 
1468  | 0  |                                : dfK * dfReal / dfAux,  | 
1469  | 0  |                     dfAux == 0 ? std::numeric_limits<double>::infinity()  | 
1470  | 0  |                                : -dfK * dfImag / dfAux};  | 
1471  |  | 
  | 
1472  | 0  |                 GDALCopyWords(adfPixVal, GDT_CFloat64, 0,  | 
1473  | 0  |                               static_cast<GByte *>(pData) +  | 
1474  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1475  | 0  |                                   iCol * nPixelSpace,  | 
1476  | 0  |                               eBufType, nPixelSpace, 1);  | 
1477  | 0  |             }  | 
1478  | 0  |         }  | 
1479  | 0  |     }  | 
1480  | 0  |     else  | 
1481  | 0  |     { | 
1482  |  |         /* ---- Set pixels ---- */  | 
1483  | 0  |         size_t ii = 0;  | 
1484  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1485  | 0  |         { | 
1486  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1487  | 0  |             { | 
1488  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1489  |  |                 // Not complex.  | 
1490  | 0  |                 const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1491  | 0  |                 double dfPixVal = dfNoData;  | 
1492  |  | 
  | 
1493  | 0  |                 if (!bHasNoData || !IsNoData(dfVal, dfNoData))  | 
1494  | 0  |                 { | 
1495  | 0  |                     dfPixVal = dfVal == 0  | 
1496  | 0  |                                    ? std::numeric_limits<double>::infinity()  | 
1497  | 0  |                                    : dfK / dfVal;  | 
1498  | 0  |                 }  | 
1499  |  | 
  | 
1500  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1501  | 0  |                               static_cast<GByte *>(pData) +  | 
1502  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1503  | 0  |                                   iCol * nPixelSpace,  | 
1504  | 0  |                               eBufType, nPixelSpace, 1);  | 
1505  | 0  |             }  | 
1506  | 0  |         }  | 
1507  | 0  |     }  | 
1508  |  |  | 
1509  |  |     /* ---- Return success ---- */  | 
1510  | 0  |     return CE_None;  | 
1511  | 0  | }  // InvPixelFunc  | 
1512  |  |  | 
1513  |  | static CPLErr IntensityPixelFunc(void **papoSources, int nSources, void *pData,  | 
1514  |  |                                  int nXSize, int nYSize, GDALDataType eSrcType,  | 
1515  |  |                                  GDALDataType eBufType, int nPixelSpace,  | 
1516  |  |                                  int nLineSpace)  | 
1517  | 0  | { | 
1518  |  |     /* ---- Init ---- */  | 
1519  | 0  |     if (nSources != 1)  | 
1520  | 0  |         return CE_Failure;  | 
1521  |  |  | 
1522  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1523  | 0  |     { | 
1524  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1525  | 0  |         const void *const pReal = papoSources[0];  | 
1526  | 0  |         const void *const pImag =  | 
1527  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
1528  |  |  | 
1529  |  |         /* ---- Set pixels ---- */  | 
1530  | 0  |         size_t ii = 0;  | 
1531  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1532  | 0  |         { | 
1533  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1534  | 0  |             { | 
1535  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1536  | 0  |                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);  | 
1537  | 0  |                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);  | 
1538  |  | 
  | 
1539  | 0  |                 const double dfPixVal = dfReal * dfReal + dfImag * dfImag;  | 
1540  |  | 
  | 
1541  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1542  | 0  |                               static_cast<GByte *>(pData) +  | 
1543  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1544  | 0  |                                   iCol * nPixelSpace,  | 
1545  | 0  |                               eBufType, nPixelSpace, 1);  | 
1546  | 0  |             }  | 
1547  | 0  |         }  | 
1548  | 0  |     }  | 
1549  | 0  |     else  | 
1550  | 0  |     { | 
1551  |  |         /* ---- Set pixels ---- */  | 
1552  | 0  |         size_t ii = 0;  | 
1553  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1554  | 0  |         { | 
1555  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1556  | 0  |             { | 
1557  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1558  | 0  |                 double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1559  | 0  |                 dfPixVal *= dfPixVal;  | 
1560  |  | 
  | 
1561  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1562  | 0  |                               static_cast<GByte *>(pData) +  | 
1563  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1564  | 0  |                                   iCol * nPixelSpace,  | 
1565  | 0  |                               eBufType, nPixelSpace, 1);  | 
1566  | 0  |             }  | 
1567  | 0  |         }  | 
1568  | 0  |     }  | 
1569  |  |  | 
1570  |  |     /* ---- Return success ---- */  | 
1571  | 0  |     return CE_None;  | 
1572  | 0  | }  // IntensityPixelFunc  | 
1573  |  |  | 
1574  |  | static const char pszSqrtPixelFuncMetadata[] =  | 
1575  |  |     "<PixelFunctionArgumentsList>"  | 
1576  |  |     "   <Argument type='builtin' value='NoData' optional='true'/>"  | 
1577  |  |     "</PixelFunctionArgumentsList>";  | 
1578  |  |  | 
1579  |  | static CPLErr SqrtPixelFunc(void **papoSources, int nSources, void *pData,  | 
1580  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
1581  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
1582  |  |                             int nLineSpace, CSLConstList papszArgs)  | 
1583  | 0  | { | 
1584  |  |     /* ---- Init ---- */  | 
1585  | 0  |     if (nSources != 1)  | 
1586  | 0  |         return CE_Failure;  | 
1587  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1588  | 0  |         return CE_Failure;  | 
1589  |  |  | 
1590  | 0  |     double dfNoData{0}; | 
1591  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1592  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1593  | 0  |         return CE_Failure;  | 
1594  |  |  | 
1595  |  |     /* ---- Set pixels ---- */  | 
1596  | 0  |     size_t ii = 0;  | 
1597  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1598  | 0  |     { | 
1599  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1600  | 0  |         { | 
1601  |  |             // Source raster pixels may be obtained with GetSrcVal macro.  | 
1602  | 0  |             double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1603  |  | 
  | 
1604  | 0  |             if (bHasNoData && IsNoData(dfPixVal, dfNoData))  | 
1605  | 0  |             { | 
1606  | 0  |                 dfPixVal = dfNoData;  | 
1607  | 0  |             }  | 
1608  | 0  |             else  | 
1609  | 0  |             { | 
1610  | 0  |                 dfPixVal = std::sqrt(dfPixVal);  | 
1611  | 0  |             }  | 
1612  |  | 
  | 
1613  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1614  | 0  |                           static_cast<GByte *>(pData) +  | 
1615  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
1616  | 0  |                               iCol * nPixelSpace,  | 
1617  | 0  |                           eBufType, nPixelSpace, 1);  | 
1618  | 0  |         }  | 
1619  | 0  |     }  | 
1620  |  |  | 
1621  |  |     /* ---- Return success ---- */  | 
1622  | 0  |     return CE_None;  | 
1623  | 0  | }  // SqrtPixelFunc  | 
1624  |  |  | 
1625  |  | static CPLErr Log10PixelFuncHelper(void **papoSources, int nSources,  | 
1626  |  |                                    void *pData, int nXSize, int nYSize,  | 
1627  |  |                                    GDALDataType eSrcType, GDALDataType eBufType,  | 
1628  |  |                                    int nPixelSpace, int nLineSpace,  | 
1629  |  |                                    CSLConstList papszArgs, double fact)  | 
1630  | 0  | { | 
1631  |  |     /* ---- Init ---- */  | 
1632  | 0  |     if (nSources != 1)  | 
1633  | 0  |         return CE_Failure;  | 
1634  |  |  | 
1635  | 0  |     double dfNoData{0}; | 
1636  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1637  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1638  | 0  |         return CE_Failure;  | 
1639  |  |  | 
1640  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1641  | 0  |     { | 
1642  |  |         // Complex input datatype.  | 
1643  | 0  |         const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;  | 
1644  | 0  |         const void *const pReal = papoSources[0];  | 
1645  | 0  |         const void *const pImag =  | 
1646  | 0  |             static_cast<GByte *>(papoSources[0]) + nOffset;  | 
1647  |  |  | 
1648  |  |         /* We should compute fact * log10( sqrt( dfReal * dfReal + dfImag *  | 
1649  |  |          * dfImag ) ) */  | 
1650  |  |         /* Given that log10(sqrt(x)) = 0.5 * log10(x) */  | 
1651  |  |         /* we can remove the sqrt() by multiplying fact by 0.5 */  | 
1652  | 0  |         fact *= 0.5;  | 
1653  |  |  | 
1654  |  |         /* ---- Set pixels ---- */  | 
1655  | 0  |         size_t ii = 0;  | 
1656  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1657  | 0  |         { | 
1658  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1659  | 0  |             { | 
1660  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1661  | 0  |                 const double dfReal = GetSrcVal(pReal, eSrcType, ii);  | 
1662  | 0  |                 const double dfImag = GetSrcVal(pImag, eSrcType, ii);  | 
1663  |  | 
  | 
1664  | 0  |                 const double dfPixVal =  | 
1665  | 0  |                     fact * log10(dfReal * dfReal + dfImag * dfImag);  | 
1666  |  | 
  | 
1667  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1668  | 0  |                               static_cast<GByte *>(pData) +  | 
1669  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1670  | 0  |                                   iCol * nPixelSpace,  | 
1671  | 0  |                               eBufType, nPixelSpace, 1);  | 
1672  | 0  |             }  | 
1673  | 0  |         }  | 
1674  | 0  |     }  | 
1675  | 0  |     else  | 
1676  | 0  |     { | 
1677  |  |         /* ---- Set pixels ---- */  | 
1678  | 0  |         size_t ii = 0;  | 
1679  | 0  |         for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1680  | 0  |         { | 
1681  | 0  |             for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1682  | 0  |             { | 
1683  |  |                 // Source raster pixels may be obtained with GetSrcVal macro.  | 
1684  | 0  |                 const double dfSrcVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1685  | 0  |                 const double dfPixVal =  | 
1686  | 0  |                     bHasNoData && IsNoData(dfSrcVal, dfNoData)  | 
1687  | 0  |                         ? dfNoData  | 
1688  | 0  |                         : fact * std::log10(std::abs(dfSrcVal));  | 
1689  |  | 
  | 
1690  | 0  |                 GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1691  | 0  |                               static_cast<GByte *>(pData) +  | 
1692  | 0  |                                   static_cast<GSpacing>(nLineSpace) * iLine +  | 
1693  | 0  |                                   iCol * nPixelSpace,  | 
1694  | 0  |                               eBufType, nPixelSpace, 1);  | 
1695  | 0  |             }  | 
1696  | 0  |         }  | 
1697  | 0  |     }  | 
1698  |  |  | 
1699  |  |     /* ---- Return success ---- */  | 
1700  | 0  |     return CE_None;  | 
1701  | 0  | }  // Log10PixelFuncHelper  | 
1702  |  |  | 
1703  |  | static const char pszLog10PixelFuncMetadata[] =  | 
1704  |  |     "<PixelFunctionArgumentsList>"  | 
1705  |  |     "   <Argument type='builtin' value='NoData' optional='true'/>"  | 
1706  |  |     "</PixelFunctionArgumentsList>";  | 
1707  |  |  | 
1708  |  | static CPLErr Log10PixelFunc(void **papoSources, int nSources, void *pData,  | 
1709  |  |                              int nXSize, int nYSize, GDALDataType eSrcType,  | 
1710  |  |                              GDALDataType eBufType, int nPixelSpace,  | 
1711  |  |                              int nLineSpace, CSLConstList papszArgs)  | 
1712  | 0  | { | 
1713  | 0  |     return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,  | 
1714  | 0  |                                 eSrcType, eBufType, nPixelSpace, nLineSpace,  | 
1715  | 0  |                                 papszArgs, 1.0);  | 
1716  | 0  | }  // Log10PixelFunc  | 
1717  |  |  | 
1718  |  | static const char pszDBPixelFuncMetadata[] =  | 
1719  |  |     "<PixelFunctionArgumentsList>"  | 
1720  |  |     "   <Argument name='fact' description='Factor' type='double' "  | 
1721  |  |     "default='20.0' />"  | 
1722  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
1723  |  |     "</PixelFunctionArgumentsList>";  | 
1724  |  |  | 
1725  |  | static CPLErr DBPixelFunc(void **papoSources, int nSources, void *pData,  | 
1726  |  |                           int nXSize, int nYSize, GDALDataType eSrcType,  | 
1727  |  |                           GDALDataType eBufType, int nPixelSpace,  | 
1728  |  |                           int nLineSpace, CSLConstList papszArgs)  | 
1729  | 0  | { | 
1730  | 0  |     double dfFact = 20.;  | 
1731  | 0  |     if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)  | 
1732  | 0  |         return CE_Failure;  | 
1733  |  |  | 
1734  | 0  |     return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,  | 
1735  | 0  |                                 eSrcType, eBufType, nPixelSpace, nLineSpace,  | 
1736  | 0  |                                 papszArgs, dfFact);  | 
1737  | 0  | }  // DBPixelFunc  | 
1738  |  |  | 
1739  |  | static CPLErr ExpPixelFuncHelper(void **papoSources, int nSources, void *pData,  | 
1740  |  |                                  int nXSize, int nYSize, GDALDataType eSrcType,  | 
1741  |  |                                  GDALDataType eBufType, int nPixelSpace,  | 
1742  |  |                                  int nLineSpace, CSLConstList papszArgs,  | 
1743  |  |                                  double base, double fact)  | 
1744  | 0  | { | 
1745  |  |     /* ---- Init ---- */  | 
1746  | 0  |     if (nSources != 1)  | 
1747  | 0  |         return CE_Failure;  | 
1748  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1749  | 0  |         return CE_Failure;  | 
1750  |  |  | 
1751  | 0  |     double dfNoData{0}; | 
1752  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1753  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1754  | 0  |         return CE_Failure;  | 
1755  |  |  | 
1756  |  |     /* ---- Set pixels ---- */  | 
1757  | 0  |     size_t ii = 0;  | 
1758  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1759  | 0  |     { | 
1760  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1761  | 0  |         { | 
1762  |  |             // Source raster pixels may be obtained with GetSrcVal macro.  | 
1763  | 0  |             const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1764  | 0  |             const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)  | 
1765  | 0  |                                         ? dfNoData  | 
1766  | 0  |                                         : pow(base, dfVal * fact);  | 
1767  |  | 
  | 
1768  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1769  | 0  |                           static_cast<GByte *>(pData) +  | 
1770  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
1771  | 0  |                               iCol * nPixelSpace,  | 
1772  | 0  |                           eBufType, nPixelSpace, 1);  | 
1773  | 0  |         }  | 
1774  | 0  |     }  | 
1775  |  |  | 
1776  |  |     /* ---- Return success ---- */  | 
1777  | 0  |     return CE_None;  | 
1778  | 0  | }  // ExpPixelFuncHelper  | 
1779  |  |  | 
1780  |  | static const char pszExpPixelFuncMetadata[] =  | 
1781  |  |     "<PixelFunctionArgumentsList>"  | 
1782  |  |     "   <Argument name='base' description='Base' type='double' "  | 
1783  |  |     "default='2.7182818284590452353602874713526624' />"  | 
1784  |  |     "   <Argument name='fact' description='Factor' type='double' default='1' />"  | 
1785  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
1786  |  |     "</PixelFunctionArgumentsList>";  | 
1787  |  |  | 
1788  |  | static CPLErr ExpPixelFunc(void **papoSources, int nSources, void *pData,  | 
1789  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
1790  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
1791  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
1792  | 0  | { | 
1793  | 0  |     double dfBase = 2.7182818284590452353602874713526624;  | 
1794  | 0  |     double dfFact = 1.;  | 
1795  |  | 
  | 
1796  | 0  |     if (FetchDoubleArg(papszArgs, "base", &dfBase, &dfBase) != CE_None)  | 
1797  | 0  |         return CE_Failure;  | 
1798  |  |  | 
1799  | 0  |     if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)  | 
1800  | 0  |         return CE_Failure;  | 
1801  |  |  | 
1802  | 0  |     return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,  | 
1803  | 0  |                               eSrcType, eBufType, nPixelSpace, nLineSpace,  | 
1804  | 0  |                               papszArgs, dfBase, dfFact);  | 
1805  | 0  | }  // ExpPixelFunc  | 
1806  |  |  | 
1807  |  | static CPLErr dB2AmpPixelFunc(void **papoSources, int nSources, void *pData,  | 
1808  |  |                               int nXSize, int nYSize, GDALDataType eSrcType,  | 
1809  |  |                               GDALDataType eBufType, int nPixelSpace,  | 
1810  |  |                               int nLineSpace)  | 
1811  | 0  | { | 
1812  | 0  |     return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,  | 
1813  | 0  |                               eSrcType, eBufType, nPixelSpace, nLineSpace,  | 
1814  | 0  |                               nullptr, 10.0, 1. / 20);  | 
1815  | 0  | }  // dB2AmpPixelFunc  | 
1816  |  |  | 
1817  |  | static CPLErr dB2PowPixelFunc(void **papoSources, int nSources, void *pData,  | 
1818  |  |                               int nXSize, int nYSize, GDALDataType eSrcType,  | 
1819  |  |                               GDALDataType eBufType, int nPixelSpace,  | 
1820  |  |                               int nLineSpace)  | 
1821  | 0  | { | 
1822  | 0  |     return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,  | 
1823  | 0  |                               eSrcType, eBufType, nPixelSpace, nLineSpace,  | 
1824  | 0  |                               nullptr, 10.0, 1. / 10);  | 
1825  | 0  | }  // dB2PowPixelFunc  | 
1826  |  |  | 
1827  |  | static const char pszPowPixelFuncMetadata[] =  | 
1828  |  |     "<PixelFunctionArgumentsList>"  | 
1829  |  |     "   <Argument name='power' description='Exponent' type='double' "  | 
1830  |  |     "mandatory='1' />"  | 
1831  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
1832  |  |     "</PixelFunctionArgumentsList>";  | 
1833  |  |  | 
1834  |  | static CPLErr PowPixelFunc(void **papoSources, int nSources, void *pData,  | 
1835  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
1836  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
1837  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
1838  | 0  | { | 
1839  |  |     /* ---- Init ---- */  | 
1840  | 0  |     if (nSources != 1)  | 
1841  | 0  |         return CE_Failure;  | 
1842  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1843  | 0  |         return CE_Failure;  | 
1844  |  |  | 
1845  | 0  |     double power;  | 
1846  | 0  |     if (FetchDoubleArg(papszArgs, "power", &power) != CE_None)  | 
1847  | 0  |         return CE_Failure;  | 
1848  |  |  | 
1849  | 0  |     double dfNoData{0}; | 
1850  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1851  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1852  | 0  |         return CE_Failure;  | 
1853  |  |  | 
1854  |  |     /* ---- Set pixels ---- */  | 
1855  | 0  |     size_t ii = 0;  | 
1856  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1857  | 0  |     { | 
1858  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1859  | 0  |         { | 
1860  | 0  |             const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
1861  |  | 
  | 
1862  | 0  |             const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)  | 
1863  | 0  |                                         ? dfNoData  | 
1864  | 0  |                                         : std::pow(dfVal, power);  | 
1865  |  | 
  | 
1866  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1867  | 0  |                           static_cast<GByte *>(pData) +  | 
1868  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
1869  | 0  |                               iCol * nPixelSpace,  | 
1870  | 0  |                           eBufType, nPixelSpace, 1);  | 
1871  | 0  |         }  | 
1872  | 0  |     }  | 
1873  |  |  | 
1874  |  |     /* ---- Return success ---- */  | 
1875  | 0  |     return CE_None;  | 
1876  | 0  | }  | 
1877  |  |  | 
1878  |  | // Given nt intervals spaced by dt and beginning at t0, return the index of  | 
1879  |  | // the lower bound of the interval that should be used to  | 
1880  |  | // interpolate/extrapolate a value for t.  | 
1881  |  | static std::size_t intervalLeft(double t0, double dt, std::size_t nt, double t)  | 
1882  | 0  | { | 
1883  | 0  |     if (t < t0)  | 
1884  | 0  |     { | 
1885  | 0  |         return 0;  | 
1886  | 0  |     }  | 
1887  |  |  | 
1888  | 0  |     std::size_t n = static_cast<std::size_t>((t - t0) / dt);  | 
1889  |  | 
  | 
1890  | 0  |     if (n >= nt - 1)  | 
1891  | 0  |     { | 
1892  | 0  |         return nt - 2;  | 
1893  | 0  |     }  | 
1894  |  |  | 
1895  | 0  |     return n;  | 
1896  | 0  | }  | 
1897  |  |  | 
1898  |  | static double InterpolateLinear(double dfX0, double dfX1, double dfY0,  | 
1899  |  |                                 double dfY1, double dfX)  | 
1900  | 0  | { | 
1901  | 0  |     return dfY0 + (dfX - dfX0) * (dfY1 - dfY0) / (dfX1 - dfX0);  | 
1902  | 0  | }  | 
1903  |  |  | 
1904  |  | static double InterpolateExponential(double dfX0, double dfX1, double dfY0,  | 
1905  |  |                                      double dfY1, double dfX)  | 
1906  | 0  | { | 
1907  | 0  |     const double r = std::log(dfY1 / dfY0) / (dfX1 - dfX0);  | 
1908  | 0  |     return dfY0 * std::exp(r * (dfX - dfX0));  | 
1909  | 0  | }  | 
1910  |  |  | 
1911  |  | static const char pszInterpolatePixelFuncMetadata[] =  | 
1912  |  |     "<PixelFunctionArgumentsList>"  | 
1913  |  |     "   <Argument name='t0' description='t0' type='double' mandatory='1' />"  | 
1914  |  |     "   <Argument name='dt' description='dt' type='double' mandatory='1' />"  | 
1915  |  |     "   <Argument name='t' description='t' type='double' mandatory='1' />"  | 
1916  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
1917  |  |     "</PixelFunctionArgumentsList>";  | 
1918  |  |  | 
1919  |  | template <decltype(InterpolateLinear) InterpolationFunction>  | 
1920  |  | CPLErr InterpolatePixelFunc(void **papoSources, int nSources, void *pData,  | 
1921  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
1922  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
1923  |  |                             int nLineSpace, CSLConstList papszArgs)  | 
1924  | 0  | { | 
1925  |  |     /* ---- Init ---- */  | 
1926  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
1927  | 0  |         return CE_Failure;  | 
1928  |  |  | 
1929  | 0  |     double dfT0;  | 
1930  | 0  |     if (FetchDoubleArg(papszArgs, "t0", &dfT0) == CE_Failure)  | 
1931  | 0  |         return CE_Failure;  | 
1932  |  |  | 
1933  | 0  |     double dfT;  | 
1934  | 0  |     if (FetchDoubleArg(papszArgs, "t", &dfT) == CE_Failure)  | 
1935  | 0  |         return CE_Failure;  | 
1936  |  |  | 
1937  | 0  |     double dfDt;  | 
1938  | 0  |     if (FetchDoubleArg(papszArgs, "dt", &dfDt) == CE_Failure)  | 
1939  | 0  |         return CE_Failure;  | 
1940  |  |  | 
1941  | 0  |     double dfNoData{0}; | 
1942  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
1943  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
1944  | 0  |         return CE_Failure;  | 
1945  |  |  | 
1946  | 0  |     if (nSources < 2)  | 
1947  | 0  |     { | 
1948  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
1949  | 0  |                  "At least two sources required for interpolation.");  | 
1950  | 0  |         return CE_Failure;  | 
1951  | 0  |     }  | 
1952  |  |  | 
1953  | 0  |     if (dfT == 0 || !std::isfinite(dfT))  | 
1954  | 0  |     { | 
1955  | 0  |         CPLError(CE_Failure, CPLE_AppDefined, "dt must be finite and non-zero");  | 
1956  | 0  |         return CE_Failure;  | 
1957  | 0  |     }  | 
1958  |  |  | 
1959  | 0  |     const auto i0 = intervalLeft(dfT0, dfDt, nSources, dfT);  | 
1960  | 0  |     const auto i1 = i0 + 1;  | 
1961  | 0  |     const double dfX0 = dfT0 + static_cast<double>(i0) * dfDt;  | 
1962  | 0  |     const double dfX1 = dfT0 + static_cast<double>(i0 + 1) * dfDt;  | 
1963  |  |  | 
1964  |  |     /* ---- Set pixels ---- */  | 
1965  | 0  |     size_t ii = 0;  | 
1966  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
1967  | 0  |     { | 
1968  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
1969  | 0  |         { | 
1970  | 0  |             const double dfY0 = GetSrcVal(papoSources[i0], eSrcType, ii);  | 
1971  | 0  |             const double dfY1 = GetSrcVal(papoSources[i1], eSrcType, ii);  | 
1972  |  | 
  | 
1973  | 0  |             double dfPixVal = dfNoData;  | 
1974  | 0  |             if (dfT == dfX0)  | 
1975  | 0  |                 dfPixVal = dfY0;  | 
1976  | 0  |             else if (dfT == dfX1)  | 
1977  | 0  |                 dfPixVal = dfY1;  | 
1978  | 0  |             else if (!bHasNoData ||  | 
1979  | 0  |                      (!IsNoData(dfY0, dfNoData) && !IsNoData(dfY1, dfNoData)))  | 
1980  | 0  |                 dfPixVal = InterpolationFunction(dfX0, dfX1, dfY0, dfY1, dfT);  | 
1981  |  | 
  | 
1982  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
1983  | 0  |                           static_cast<GByte *>(pData) +  | 
1984  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
1985  | 0  |                               iCol * nPixelSpace,  | 
1986  | 0  |                           eBufType, nPixelSpace, 1);  | 
1987  | 0  |         }  | 
1988  | 0  |     }  | 
1989  |  |  | 
1990  |  |     /* ---- Return success ---- */  | 
1991  | 0  |     return CE_None;  | 
1992  | 0  | } Unexecuted instantiation: pixelfunctions.cpp:CPLErr InterpolatePixelFunc<&(InterpolateLinear(double, double, double, double, double))>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*) Unexecuted instantiation: pixelfunctions.cpp:CPLErr InterpolatePixelFunc<&(InterpolateExponential(double, double, double, double, double))>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)  | 
1993  |  |  | 
1994  |  | static const char pszReplaceNoDataPixelFuncMetadata[] =  | 
1995  |  |     "<PixelFunctionArgumentsList>"  | 
1996  |  |     "   <Argument type='builtin' value='NoData' />"  | 
1997  |  |     "   <Argument name='to' type='double' description='New NoData value to be "  | 
1998  |  |     "replaced' default='nan' />"  | 
1999  |  |     "</PixelFunctionArgumentsList>";  | 
2000  |  |  | 
2001  |  | static CPLErr ReplaceNoDataPixelFunc(void **papoSources, int nSources,  | 
2002  |  |                                      void *pData, int nXSize, int nYSize,  | 
2003  |  |                                      GDALDataType eSrcType,  | 
2004  |  |                                      GDALDataType eBufType, int nPixelSpace,  | 
2005  |  |                                      int nLineSpace, CSLConstList papszArgs)  | 
2006  | 0  | { | 
2007  |  |     /* ---- Init ---- */  | 
2008  | 0  |     if (nSources != 1)  | 
2009  | 0  |         return CE_Failure;  | 
2010  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2011  | 0  |     { | 
2012  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2013  | 0  |                  "replace_nodata cannot convert complex data types");  | 
2014  | 0  |         return CE_Failure;  | 
2015  | 0  |     }  | 
2016  |  |  | 
2017  | 0  |     double dfOldNoData, dfNewNoData = NAN;  | 
2018  | 0  |     if (FetchDoubleArg(papszArgs, "NoData", &dfOldNoData) != CE_None)  | 
2019  | 0  |         return CE_Failure;  | 
2020  | 0  |     if (FetchDoubleArg(papszArgs, "to", &dfNewNoData, &dfNewNoData) != CE_None)  | 
2021  | 0  |         return CE_Failure;  | 
2022  |  |  | 
2023  | 0  |     if (!GDALDataTypeIsFloating(eBufType) && std::isnan(dfNewNoData))  | 
2024  | 0  |     { | 
2025  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2026  | 0  |                  "Using nan requires a floating point type output buffer");  | 
2027  | 0  |         return CE_Failure;  | 
2028  | 0  |     }  | 
2029  |  |  | 
2030  |  |     /* ---- Set pixels ---- */  | 
2031  | 0  |     size_t ii = 0;  | 
2032  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2033  | 0  |     { | 
2034  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2035  | 0  |         { | 
2036  | 0  |             double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
2037  | 0  |             if (dfPixVal == dfOldNoData || std::isnan(dfPixVal))  | 
2038  | 0  |                 dfPixVal = dfNewNoData;  | 
2039  |  | 
  | 
2040  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
2041  | 0  |                           static_cast<GByte *>(pData) +  | 
2042  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
2043  | 0  |                               iCol * nPixelSpace,  | 
2044  | 0  |                           eBufType, nPixelSpace, 1);  | 
2045  | 0  |         }  | 
2046  | 0  |     }  | 
2047  |  |  | 
2048  |  |     /* ---- Return success ---- */  | 
2049  | 0  |     return CE_None;  | 
2050  | 0  | }  | 
2051  |  |  | 
2052  |  | static const char pszScalePixelFuncMetadata[] =  | 
2053  |  |     "<PixelFunctionArgumentsList>"  | 
2054  |  |     "   <Argument type='builtin' value='offset' />"  | 
2055  |  |     "   <Argument type='builtin' value='scale' />"  | 
2056  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
2057  |  |     "</PixelFunctionArgumentsList>";  | 
2058  |  |  | 
2059  |  | static CPLErr ScalePixelFunc(void **papoSources, int nSources, void *pData,  | 
2060  |  |                              int nXSize, int nYSize, GDALDataType eSrcType,  | 
2061  |  |                              GDALDataType eBufType, int nPixelSpace,  | 
2062  |  |                              int nLineSpace, CSLConstList papszArgs)  | 
2063  | 0  | { | 
2064  |  |     /* ---- Init ---- */  | 
2065  | 0  |     if (nSources != 1)  | 
2066  | 0  |         return CE_Failure;  | 
2067  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2068  | 0  |     { | 
2069  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2070  | 0  |                  "scale cannot by applied to complex data types");  | 
2071  | 0  |         return CE_Failure;  | 
2072  | 0  |     }  | 
2073  |  |  | 
2074  | 0  |     double dfNoData{0}; | 
2075  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
2076  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
2077  | 0  |         return CE_Failure;  | 
2078  |  |  | 
2079  | 0  |     double dfScale, dfOffset;  | 
2080  | 0  |     if (FetchDoubleArg(papszArgs, "scale", &dfScale) != CE_None)  | 
2081  | 0  |         return CE_Failure;  | 
2082  | 0  |     if (FetchDoubleArg(papszArgs, "offset", &dfOffset) != CE_None)  | 
2083  | 0  |         return CE_Failure;  | 
2084  |  |  | 
2085  |  |     /* ---- Set pixels ---- */  | 
2086  | 0  |     size_t ii = 0;  | 
2087  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2088  | 0  |     { | 
2089  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2090  | 0  |         { | 
2091  | 0  |             const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
2092  |  | 
  | 
2093  | 0  |             const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)  | 
2094  | 0  |                                         ? dfNoData  | 
2095  | 0  |                                         : dfVal * dfScale + dfOffset;  | 
2096  |  | 
  | 
2097  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
2098  | 0  |                           static_cast<GByte *>(pData) +  | 
2099  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
2100  | 0  |                               iCol * nPixelSpace,  | 
2101  | 0  |                           eBufType, nPixelSpace, 1);  | 
2102  | 0  |         }  | 
2103  | 0  |     }  | 
2104  |  |  | 
2105  |  |     /* ---- Return success ---- */  | 
2106  | 0  |     return CE_None;  | 
2107  | 0  | }  | 
2108  |  |  | 
2109  |  | static const char pszNormDiffPixelFuncMetadata[] =  | 
2110  |  |     "<PixelFunctionArgumentsList>"  | 
2111  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
2112  |  |     "</PixelFunctionArgumentsList>";  | 
2113  |  |  | 
2114  |  | static CPLErr NormDiffPixelFunc(void **papoSources, int nSources, void *pData,  | 
2115  |  |                                 int nXSize, int nYSize, GDALDataType eSrcType,  | 
2116  |  |                                 GDALDataType eBufType, int nPixelSpace,  | 
2117  |  |                                 int nLineSpace, CSLConstList papszArgs)  | 
2118  | 0  | { | 
2119  |  |     /* ---- Init ---- */  | 
2120  | 0  |     if (nSources != 2)  | 
2121  | 0  |         return CE_Failure;  | 
2122  |  |  | 
2123  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2124  | 0  |     { | 
2125  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2126  | 0  |                  "norm_diff cannot by applied to complex data types");  | 
2127  | 0  |         return CE_Failure;  | 
2128  | 0  |     }  | 
2129  |  |  | 
2130  | 0  |     double dfNoData{0}; | 
2131  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
2132  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
2133  | 0  |         return CE_Failure;  | 
2134  |  |  | 
2135  |  |     /* ---- Set pixels ---- */  | 
2136  | 0  |     size_t ii = 0;  | 
2137  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2138  | 0  |     { | 
2139  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2140  | 0  |         { | 
2141  | 0  |             const double dfLeftVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
2142  | 0  |             const double dfRightVal = GetSrcVal(papoSources[1], eSrcType, ii);  | 
2143  |  | 
  | 
2144  | 0  |             double dfPixVal = dfNoData;  | 
2145  |  | 
  | 
2146  | 0  |             if (!bHasNoData || (!IsNoData(dfLeftVal, dfNoData) &&  | 
2147  | 0  |                                 !IsNoData(dfRightVal, dfNoData)))  | 
2148  | 0  |             { | 
2149  | 0  |                 const double dfDenom = (dfLeftVal + dfRightVal);  | 
2150  |  |                 // coverity[divide_by_zero]  | 
2151  | 0  |                 dfPixVal = dfDenom == 0  | 
2152  | 0  |                                ? std::numeric_limits<double>::infinity()  | 
2153  | 0  |                                : (dfLeftVal - dfRightVal) / dfDenom;  | 
2154  | 0  |             }  | 
2155  |  | 
  | 
2156  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
2157  | 0  |                           static_cast<GByte *>(pData) +  | 
2158  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
2159  | 0  |                               iCol * nPixelSpace,  | 
2160  | 0  |                           eBufType, nPixelSpace, 1);  | 
2161  | 0  |         }  | 
2162  | 0  |     }  | 
2163  |  |  | 
2164  |  |     /* ---- Return success ---- */  | 
2165  | 0  |     return CE_None;  | 
2166  | 0  | }  // NormDiffPixelFunc  | 
2167  |  |  | 
2168  |  | /************************************************************************/  | 
2169  |  | /*                   pszMinMaxFuncMetadataNodata                        */  | 
2170  |  | /************************************************************************/  | 
2171  |  |  | 
2172  |  | static const char pszMinMaxFuncMetadataNodata[] =  | 
2173  |  |     "<PixelFunctionArgumentsList>"  | 
2174  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
2175  |  |     "   <Argument name='propagateNoData' description='Whether the output value "  | 
2176  |  |     "should be NoData as as soon as one source is NoData' type='boolean' "  | 
2177  |  |     "default='false' />"  | 
2178  |  |     "</PixelFunctionArgumentsList>";  | 
2179  |  |  | 
2180  |  | template <class Comparator>  | 
2181  |  | static CPLErr MinOrMaxPixelFunc(void **papoSources, int nSources, void *pData,  | 
2182  |  |                                 int nXSize, int nYSize, GDALDataType eSrcType,  | 
2183  |  |                                 GDALDataType eBufType, int nPixelSpace,  | 
2184  |  |                                 int nLineSpace, CSLConstList papszArgs)  | 
2185  | 0  | { | 
2186  |  |     /* ---- Init ---- */  | 
2187  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2188  | 0  |     { | 
2189  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2190  | 0  |                  "Complex data type not supported for min/max().");  | 
2191  | 0  |         return CE_Failure;  | 
2192  | 0  |     }  | 
2193  |  |  | 
2194  | 0  |     double dfNoData = std::numeric_limits<double>::quiet_NaN();  | 
2195  | 0  |     if (FetchDoubleArg(papszArgs, "NoData", &dfNoData, &dfNoData) != CE_None)  | 
2196  | 0  |         return CE_Failure;  | 
2197  | 0  |     const bool bPropagateNoData = CPLTestBool(  | 
2198  | 0  |         CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));  | 
2199  |  |  | 
2200  |  |     /* ---- Set pixels ---- */  | 
2201  | 0  |     size_t ii = 0;  | 
2202  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2203  | 0  |     { | 
2204  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2205  | 0  |         { | 
2206  | 0  |             double dfRes = std::numeric_limits<double>::quiet_NaN();  | 
2207  |  | 
  | 
2208  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
2209  | 0  |             { | 
2210  | 0  |                 const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);  | 
2211  |  | 
  | 
2212  | 0  |                 if (std::isnan(dfVal) || dfVal == dfNoData)  | 
2213  | 0  |                 { | 
2214  | 0  |                     if (bPropagateNoData)  | 
2215  | 0  |                     { | 
2216  | 0  |                         dfRes = dfNoData;  | 
2217  | 0  |                         break;  | 
2218  | 0  |                     }  | 
2219  | 0  |                 }  | 
2220  | 0  |                 else if (Comparator::compare(dfVal, dfRes))  | 
2221  | 0  |                 { | 
2222  | 0  |                     dfRes = dfVal;  | 
2223  | 0  |                 }  | 
2224  | 0  |             }  | 
2225  |  | 
  | 
2226  | 0  |             if (!bPropagateNoData && std::isnan(dfRes))  | 
2227  | 0  |             { | 
2228  | 0  |                 dfRes = dfNoData;  | 
2229  | 0  |             }  | 
2230  |  | 
  | 
2231  | 0  |             GDALCopyWords(&dfRes, GDT_Float64, 0,  | 
2232  | 0  |                           static_cast<GByte *>(pData) +  | 
2233  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
2234  | 0  |                               iCol * nPixelSpace,  | 
2235  | 0  |                           eBufType, nPixelSpace, 1);  | 
2236  | 0  |         }  | 
2237  | 0  |     }  | 
2238  |  |  | 
2239  |  |     /* ---- Return success ---- */  | 
2240  | 0  |     return CE_None;  | 
2241  | 0  | } /* MinOrMaxPixelFunc */ Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MinPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*) Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MaxPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)  | 
2242  |  |  | 
2243  |  | static CPLErr MinPixelFunc(void **papoSources, int nSources, void *pData,  | 
2244  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
2245  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
2246  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
2247  | 0  | { | 
2248  | 0  |     struct Comparator  | 
2249  | 0  |     { | 
2250  | 0  |         static bool compare(double x, double resVal)  | 
2251  | 0  |         { | 
2252  |  |             // Written this way to deal with resVal being NaN  | 
2253  | 0  |             return !(x >= resVal);  | 
2254  | 0  |         }  | 
2255  | 0  |     };  | 
2256  |  | 
  | 
2257  | 0  |     return MinOrMaxPixelFunc<Comparator>(papoSources, nSources, pData, nXSize,  | 
2258  | 0  |                                          nYSize, eSrcType, eBufType,  | 
2259  | 0  |                                          nPixelSpace, nLineSpace, papszArgs);  | 
2260  | 0  | }  | 
2261  |  |  | 
2262  |  | static CPLErr MaxPixelFunc(void **papoSources, int nSources, void *pData,  | 
2263  |  |                            int nXSize, int nYSize, GDALDataType eSrcType,  | 
2264  |  |                            GDALDataType eBufType, int nPixelSpace,  | 
2265  |  |                            int nLineSpace, CSLConstList papszArgs)  | 
2266  | 0  | { | 
2267  | 0  |     struct Comparator  | 
2268  | 0  |     { | 
2269  | 0  |         static bool compare(double x, double resVal)  | 
2270  | 0  |         { | 
2271  |  |             // Written this way to deal with resVal being NaN  | 
2272  | 0  |             return !(x <= resVal);  | 
2273  | 0  |         }  | 
2274  | 0  |     };  | 
2275  |  | 
  | 
2276  | 0  |     return MinOrMaxPixelFunc<Comparator>(papoSources, nSources, pData, nXSize,  | 
2277  | 0  |                                          nYSize, eSrcType, eBufType,  | 
2278  | 0  |                                          nPixelSpace, nLineSpace, papszArgs);  | 
2279  | 0  | }  | 
2280  |  |  | 
2281  |  | static const char pszExprPixelFuncMetadata[] =  | 
2282  |  |     "<PixelFunctionArgumentsList>"  | 
2283  |  |     "   <Argument name='expression' "  | 
2284  |  |     "             description='Expression to be evaluated' "  | 
2285  |  |     "             type='string'></Argument>"  | 
2286  |  |     "   <Argument name='dialect' "  | 
2287  |  |     "             description='Expression dialect' "  | 
2288  |  |     "             type='string-select'"  | 
2289  |  |     "             default='muparser'>"  | 
2290  |  |     "       <Value>exprtk</Value>"  | 
2291  |  |     "       <Value>muparser</Value>"  | 
2292  |  |     "   </Argument>"  | 
2293  |  |     "   <Argument type='builtin' value='source_names' />"  | 
2294  |  |     "</PixelFunctionArgumentsList>";  | 
2295  |  |  | 
2296  |  | static CPLErr ExprPixelFunc(void **papoSources, int nSources, void *pData,  | 
2297  |  |                             int nXSize, int nYSize, GDALDataType eSrcType,  | 
2298  |  |                             GDALDataType eBufType, int nPixelSpace,  | 
2299  |  |                             int nLineSpace, CSLConstList papszArgs)  | 
2300  | 0  | { | 
2301  |  |     /* ---- Init ---- */  | 
2302  |  | 
  | 
2303  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2304  | 0  |     { | 
2305  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2306  | 0  |                  "expression cannot by applied to complex data types");  | 
2307  | 0  |         return CE_Failure;  | 
2308  | 0  |     }  | 
2309  |  |  | 
2310  | 0  |     std::unique_ptr<gdal::MathExpression> poExpression;  | 
2311  |  | 
  | 
2312  | 0  |     const char *pszExpression = CSLFetchNameValue(papszArgs, "expression");  | 
2313  |  | 
  | 
2314  | 0  |     const char *pszSourceNames = CSLFetchNameValue(papszArgs, "source_names");  | 
2315  | 0  |     const CPLStringList aosSourceNames(  | 
2316  | 0  |         CSLTokenizeString2(pszSourceNames, "|", 0));  | 
2317  | 0  |     if (aosSourceNames.size() != nSources)  | 
2318  | 0  |     { | 
2319  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2320  | 0  |                  "The source_names variable passed to ExprPixelFunc() has %d "  | 
2321  | 0  |                  "values, whereas %d were expected. An invalid variable name "  | 
2322  | 0  |                  "has likely been used",  | 
2323  | 0  |                  aosSourceNames.size(), nSources);  | 
2324  | 0  |         return CE_Failure;  | 
2325  | 0  |     }  | 
2326  |  |  | 
2327  | 0  |     std::vector<double> adfValuesForPixel(nSources);  | 
2328  |  | 
  | 
2329  | 0  |     const char *pszDialect = CSLFetchNameValue(papszArgs, "dialect");  | 
2330  | 0  |     if (!pszDialect)  | 
2331  | 0  |     { | 
2332  | 0  |         pszDialect = "muparser";  | 
2333  | 0  |     }  | 
2334  |  | 
  | 
2335  | 0  |     poExpression = gdal::MathExpression::Create(pszExpression, pszDialect);  | 
2336  |  |  | 
2337  |  |     // cppcheck-suppress knownConditionTrueFalse  | 
2338  | 0  |     if (!poExpression)  | 
2339  | 0  |     { | 
2340  | 0  |         return CE_Failure;  | 
2341  | 0  |     }  | 
2342  |  |  | 
2343  | 0  |     { | 
2344  | 0  |         int iSource = 0;  | 
2345  | 0  |         for (const auto &osName : aosSourceNames)  | 
2346  | 0  |         { | 
2347  | 0  |             poExpression->RegisterVariable(osName,  | 
2348  | 0  |                                            &adfValuesForPixel[iSource++]);  | 
2349  | 0  |         }  | 
2350  | 0  |     }  | 
2351  |  | 
  | 
2352  | 0  |     if (strstr(pszExpression, "BANDS"))  | 
2353  | 0  |     { | 
2354  | 0  |         poExpression->RegisterVector("BANDS", &adfValuesForPixel); | 
2355  | 0  |     }  | 
2356  |  | 
  | 
2357  | 0  |     std::unique_ptr<double, VSIFreeReleaser> padfResults(  | 
2358  | 0  |         static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));  | 
2359  | 0  |     if (!padfResults)  | 
2360  | 0  |         return CE_Failure;  | 
2361  |  |  | 
2362  |  |     /* ---- Set pixels ---- */  | 
2363  | 0  |     size_t ii = 0;  | 
2364  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2365  | 0  |     { | 
2366  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2367  | 0  |         { | 
2368  | 0  |             for (int iSrc = 0; iSrc < nSources; iSrc++)  | 
2369  | 0  |             { | 
2370  |  |                 // cppcheck-suppress unreadVariable  | 
2371  | 0  |                 adfValuesForPixel[iSrc] =  | 
2372  | 0  |                     GetSrcVal(papoSources[iSrc], eSrcType, ii);  | 
2373  | 0  |             }  | 
2374  |  | 
  | 
2375  | 0  |             if (auto eErr = poExpression->Evaluate(); eErr != CE_None)  | 
2376  | 0  |             { | 
2377  | 0  |                 return CE_Failure;  | 
2378  | 0  |             }  | 
2379  | 0  |             else  | 
2380  | 0  |             { | 
2381  | 0  |                 padfResults.get()[iCol] = poExpression->Results()[0];  | 
2382  | 0  |             }  | 
2383  | 0  |         }  | 
2384  |  |  | 
2385  | 0  |         GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),  | 
2386  | 0  |                       static_cast<GByte *>(pData) +  | 
2387  | 0  |                           static_cast<GSpacing>(nLineSpace) * iLine,  | 
2388  | 0  |                       eBufType, nPixelSpace, nXSize);  | 
2389  | 0  |     }  | 
2390  |  |  | 
2391  |  |     /* ---- Return success ---- */  | 
2392  | 0  |     return CE_None;  | 
2393  | 0  | }  // ExprPixelFunc  | 
2394  |  |  | 
2395  |  | static const char pszReclassifyPixelFuncMetadata[] =  | 
2396  |  |     "<PixelFunctionArgumentsList>"  | 
2397  |  |     "   <Argument name='mapping' "  | 
2398  |  |     "             description='Lookup table for mapping, in format "  | 
2399  |  |     "from=to,from=to' "  | 
2400  |  |     "             type='string'></Argument>"  | 
2401  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
2402  |  |     "</PixelFunctionArgumentsList>";  | 
2403  |  |  | 
2404  |  | static CPLErr ReclassifyPixelFunc(void **papoSources, int nSources, void *pData,  | 
2405  |  |                                   int nXSize, int nYSize, GDALDataType eSrcType,  | 
2406  |  |                                   GDALDataType eBufType, int nPixelSpace,  | 
2407  |  |                                   int nLineSpace, CSLConstList papszArgs)  | 
2408  | 0  | { | 
2409  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2410  | 0  |     { | 
2411  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2412  | 0  |                  "reclassify cannot by applied to complex data types");  | 
2413  | 0  |         return CE_Failure;  | 
2414  | 0  |     }  | 
2415  |  |  | 
2416  | 0  |     if (nSources != 1)  | 
2417  | 0  |     { | 
2418  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2419  | 0  |                  "reclassify only be applied to a single source at a time");  | 
2420  | 0  |         return CE_Failure;  | 
2421  | 0  |     }  | 
2422  | 0  |     std::optional<double> noDataValue{}; | 
2423  |  | 
  | 
2424  | 0  |     const char *pszNoData = CSLFetchNameValue(papszArgs, "NoData");  | 
2425  | 0  |     if (pszNoData != nullptr)  | 
2426  | 0  |     { | 
2427  | 0  |         noDataValue = CPLAtof(pszNoData);  | 
2428  | 0  |     }  | 
2429  |  | 
  | 
2430  | 0  |     const char *pszMappings = CSLFetchNameValue(papszArgs, "mapping");  | 
2431  | 0  |     if (pszMappings == nullptr)  | 
2432  | 0  |     { | 
2433  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2434  | 0  |                  "reclassify must be called with 'mapping' argument");  | 
2435  | 0  |         return CE_Failure;  | 
2436  | 0  |     }  | 
2437  |  |  | 
2438  | 0  |     gdal::Reclassifier oReclassifier;  | 
2439  | 0  |     if (auto eErr = oReclassifier.Init(pszMappings, noDataValue, eBufType);  | 
2440  | 0  |         eErr != CE_None)  | 
2441  | 0  |     { | 
2442  | 0  |         return eErr;  | 
2443  | 0  |     }  | 
2444  |  |  | 
2445  | 0  |     std::unique_ptr<double, VSIFreeReleaser> padfResults(  | 
2446  | 0  |         static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));  | 
2447  | 0  |     if (!padfResults)  | 
2448  | 0  |         return CE_Failure;  | 
2449  |  |  | 
2450  | 0  |     size_t ii = 0;  | 
2451  | 0  |     bool bSuccess = false;  | 
2452  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2453  | 0  |     { | 
2454  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2455  | 0  |         { | 
2456  | 0  |             double srcVal = GetSrcVal(papoSources[0], eSrcType, ii);  | 
2457  | 0  |             padfResults.get()[iCol] =  | 
2458  | 0  |                 oReclassifier.Reclassify(srcVal, bSuccess);  | 
2459  | 0  |             if (!bSuccess)  | 
2460  | 0  |             { | 
2461  | 0  |                 CPLError(CE_Failure, CPLE_AppDefined,  | 
2462  | 0  |                          "Encountered value %g with no specified mapping",  | 
2463  | 0  |                          srcVal);  | 
2464  | 0  |                 return CE_Failure;  | 
2465  | 0  |             }  | 
2466  | 0  |         }  | 
2467  |  |  | 
2468  | 0  |         GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),  | 
2469  | 0  |                       static_cast<GByte *>(pData) +  | 
2470  | 0  |                           static_cast<GSpacing>(nLineSpace) * iLine,  | 
2471  | 0  |                       eBufType, nPixelSpace, nXSize);  | 
2472  | 0  |     }  | 
2473  |  |  | 
2474  | 0  |     return CE_None;  | 
2475  | 0  | }  // ReclassifyPixelFunc  | 
2476  |  |  | 
2477  |  | struct MeanKernel  | 
2478  |  | { | 
2479  |  |     static constexpr const char *pszName = "mean";  | 
2480  |  |  | 
2481  |  |     double dfSum = 0;  | 
2482  |  |     int nValidSources = 0;  | 
2483  |  |  | 
2484  |  |     void Reset()  | 
2485  | 0  |     { | 
2486  | 0  |         dfSum = 0;  | 
2487  | 0  |         nValidSources = 0;  | 
2488  | 0  |     }  | 
2489  |  |  | 
2490  |  |     static CPLErr ProcessArguments(CSLConstList)  | 
2491  | 0  |     { | 
2492  | 0  |         return CE_None;  | 
2493  | 0  |     }  | 
2494  |  |  | 
2495  |  |     void ProcessPixel(double dfVal)  | 
2496  | 0  |     { | 
2497  | 0  |         dfSum += dfVal;  | 
2498  | 0  |         nValidSources++;  | 
2499  | 0  |     }  | 
2500  |  |  | 
2501  |  |     bool HasValue() const  | 
2502  | 0  |     { | 
2503  | 0  |         return nValidSources > 0;  | 
2504  | 0  |     }  | 
2505  |  |  | 
2506  |  |     double GetValue() const  | 
2507  | 0  |     { | 
2508  | 0  |         return dfSum / nValidSources;  | 
2509  | 0  |     }  | 
2510  |  | };  | 
2511  |  |  | 
2512  |  | struct GeoMeanKernel  | 
2513  |  | { | 
2514  |  |     static constexpr const char *pszName = "geometric_mean";  | 
2515  |  |  | 
2516  |  |     double dfProduct = 1;  | 
2517  |  |     int nValidSources = 0;  | 
2518  |  |  | 
2519  |  |     void Reset()  | 
2520  | 0  |     { | 
2521  | 0  |         dfProduct = 1;  | 
2522  | 0  |         nValidSources = 0;  | 
2523  | 0  |     }  | 
2524  |  |  | 
2525  |  |     static CPLErr ProcessArguments(CSLConstList)  | 
2526  | 0  |     { | 
2527  | 0  |         return CE_None;  | 
2528  | 0  |     }  | 
2529  |  |  | 
2530  |  |     void ProcessPixel(double dfVal)  | 
2531  | 0  |     { | 
2532  | 0  |         dfProduct *= dfVal;  | 
2533  | 0  |         nValidSources++;  | 
2534  | 0  |     }  | 
2535  |  |  | 
2536  |  |     bool HasValue() const  | 
2537  | 0  |     { | 
2538  | 0  |         return nValidSources > 0;  | 
2539  | 0  |     }  | 
2540  |  |  | 
2541  |  |     double GetValue() const  | 
2542  | 0  |     { | 
2543  | 0  |         return std::pow(dfProduct, 1.0 / nValidSources);  | 
2544  | 0  |     }  | 
2545  |  | };  | 
2546  |  |  | 
2547  |  | struct HarmonicMeanKernel  | 
2548  |  | { | 
2549  |  |     static constexpr const char *pszName = "harmonic_mean";  | 
2550  |  |  | 
2551  |  |     double dfDenom = 0;  | 
2552  |  |     int nValidSources = 0;  | 
2553  |  |     bool bValueIsZero = false;  | 
2554  |  |     bool bPropagateZero = false;  | 
2555  |  |  | 
2556  |  |     void Reset()  | 
2557  | 0  |     { | 
2558  | 0  |         dfDenom = 0;  | 
2559  | 0  |         nValidSources = 0;  | 
2560  | 0  |         bValueIsZero = false;  | 
2561  | 0  |     }  | 
2562  |  |  | 
2563  |  |     void ProcessPixel(double dfVal)  | 
2564  | 0  |     { | 
2565  | 0  |         if (dfVal == 0)  | 
2566  | 0  |         { | 
2567  | 0  |             bValueIsZero = true;  | 
2568  | 0  |         }  | 
2569  | 0  |         else  | 
2570  | 0  |         { | 
2571  | 0  |             dfDenom += 1 / dfVal;  | 
2572  | 0  |         }  | 
2573  | 0  |         nValidSources++;  | 
2574  | 0  |     }  | 
2575  |  |  | 
2576  |  |     CPLErr ProcessArguments(CSLConstList papszArgs)  | 
2577  | 0  |     { | 
2578  | 0  |         bPropagateZero =  | 
2579  | 0  |             CPLTestBool(CSLFetchNameValueDef(papszArgs, "propagateZero", "0"));  | 
2580  | 0  |         return CE_None;  | 
2581  | 0  |     }  | 
2582  |  |  | 
2583  |  |     bool HasValue() const  | 
2584  | 0  |     { | 
2585  | 0  |         return dfDenom > 0 && (bPropagateZero || !bValueIsZero);  | 
2586  | 0  |     }  | 
2587  |  |  | 
2588  |  |     double GetValue() const  | 
2589  | 0  |     { | 
2590  | 0  |         if (bPropagateZero && bValueIsZero)  | 
2591  | 0  |         { | 
2592  | 0  |             return 0;  | 
2593  | 0  |         }  | 
2594  | 0  |         return static_cast<double>(nValidSources) / dfDenom;  | 
2595  | 0  |     }  | 
2596  |  | };  | 
2597  |  |  | 
2598  |  | struct MedianKernel  | 
2599  |  | { | 
2600  |  |     static constexpr const char *pszName = "median";  | 
2601  |  |  | 
2602  |  |     mutable std::vector<double> values{}; | 
2603  |  |  | 
2604  |  |     void Reset()  | 
2605  | 0  |     { | 
2606  | 0  |         values.clear();  | 
2607  | 0  |     }  | 
2608  |  |  | 
2609  |  |     static CPLErr ProcessArguments(CSLConstList)  | 
2610  | 0  |     { | 
2611  | 0  |         return CE_None;  | 
2612  | 0  |     }  | 
2613  |  |  | 
2614  |  |     void ProcessPixel(double dfVal)  | 
2615  | 0  |     { | 
2616  | 0  |         if (!std::isnan(dfVal))  | 
2617  | 0  |         { | 
2618  | 0  |             values.push_back(dfVal);  | 
2619  | 0  |         }  | 
2620  | 0  |     }  | 
2621  |  |  | 
2622  |  |     bool HasValue() const  | 
2623  | 0  |     { | 
2624  | 0  |         return !values.empty();  | 
2625  | 0  |     }  | 
2626  |  |  | 
2627  |  |     double GetValue() const  | 
2628  | 0  |     { | 
2629  | 0  |         std::sort(values.begin(), values.end());  | 
2630  | 0  |         if (values.size() % 2 == 0)  | 
2631  | 0  |         { | 
2632  | 0  |             return 0.5 *  | 
2633  | 0  |                    (values[values.size() / 2 - 1] + values[values.size() / 2]);  | 
2634  | 0  |         }  | 
2635  |  |  | 
2636  | 0  |         return values[values.size() / 2];  | 
2637  | 0  |     }  | 
2638  |  | };  | 
2639  |  |  | 
2640  |  | struct ModeKernel  | 
2641  |  | { | 
2642  |  |     static constexpr const char *pszName = "mode";  | 
2643  |  |  | 
2644  |  |     std::map<double, size_t> counts{}; | 
2645  |  |     std::size_t nanCount{0}; | 
2646  |  |     double dfMax = std::numeric_limits<double>::quiet_NaN();  | 
2647  |  |     decltype(counts.begin()) oMax = counts.end();  | 
2648  |  |  | 
2649  |  |     void Reset()  | 
2650  | 0  |     { | 
2651  | 0  |         nanCount = 0;  | 
2652  | 0  |         counts.clear();  | 
2653  | 0  |         oMax = counts.end();  | 
2654  | 0  |     }  | 
2655  |  |  | 
2656  |  |     static CPLErr ProcessArguments(CSLConstList)  | 
2657  | 0  |     { | 
2658  | 0  |         return CE_None;  | 
2659  | 0  |     }  | 
2660  |  |  | 
2661  |  |     void ProcessPixel(double dfVal)  | 
2662  | 0  |     { | 
2663  | 0  |         if (std::isnan(dfVal))  | 
2664  | 0  |         { | 
2665  | 0  |             nanCount += 1;  | 
2666  | 0  |             return;  | 
2667  | 0  |         }  | 
2668  |  |  | 
2669  |  |         // if dfVal is NaN, try_emplace will return an entry for a different key!  | 
2670  | 0  |         auto [it, inserted] = counts.try_emplace(dfVal, 0);  | 
2671  |  | 
  | 
2672  | 0  |         it->second += 1;  | 
2673  |  | 
  | 
2674  | 0  |         if (oMax == counts.end() || it->second > oMax->second)  | 
2675  | 0  |         { | 
2676  | 0  |             oMax = it;  | 
2677  | 0  |         }  | 
2678  | 0  |     }  | 
2679  |  |  | 
2680  |  |     bool HasValue() const  | 
2681  | 0  |     { | 
2682  | 0  |         return nanCount > 0 || oMax != counts.end();  | 
2683  | 0  |     }  | 
2684  |  |  | 
2685  |  |     double GetValue() const  | 
2686  | 0  |     { | 
2687  | 0  |         double ret = std::numeric_limits<double>::quiet_NaN();  | 
2688  | 0  |         if (oMax != counts.end())  | 
2689  | 0  |         { | 
2690  | 0  |             const size_t nCount = oMax->second;  | 
2691  | 0  |             if (nCount > nanCount)  | 
2692  | 0  |                 ret = oMax->first;  | 
2693  | 0  |         }  | 
2694  | 0  |         return ret;  | 
2695  | 0  |     }  | 
2696  |  | };  | 
2697  |  |  | 
2698  |  | static const char pszBasicPixelFuncMetadata[] =  | 
2699  |  |     "<PixelFunctionArgumentsList>"  | 
2700  |  |     "   <Argument type='builtin' value='NoData' optional='true' />"  | 
2701  |  |     "   <Argument name='propagateNoData' description='Whether the output value "  | 
2702  |  |     "should be NoData as as soon as one source is NoData' type='boolean' "  | 
2703  |  |     "default='false' />"  | 
2704  |  |     "</PixelFunctionArgumentsList>";  | 
2705  |  |  | 
2706  |  | template <typename T>  | 
2707  |  | static CPLErr BasicPixelFunc(void **papoSources, int nSources, void *pData,  | 
2708  |  |                              int nXSize, int nYSize, GDALDataType eSrcType,  | 
2709  |  |                              GDALDataType eBufType, int nPixelSpace,  | 
2710  |  |                              int nLineSpace, CSLConstList papszArgs)  | 
2711  | 0  | { | 
2712  |  |     /* ---- Init ---- */  | 
2713  | 0  |     T oKernel;  | 
2714  |  | 
  | 
2715  | 0  |     if (GDALDataTypeIsComplex(eSrcType))  | 
2716  | 0  |     { | 
2717  | 0  |         CPLError(CE_Failure, CPLE_AppDefined,  | 
2718  | 0  |                  "Complex data types not supported by %s", oKernel.pszName);  | 
2719  | 0  |         return CE_Failure;  | 
2720  | 0  |     }  | 
2721  |  |  | 
2722  | 0  |     double dfNoData{0}; | 
2723  | 0  |     const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;  | 
2724  | 0  |     if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)  | 
2725  | 0  |         return CE_Failure;  | 
2726  |  |  | 
2727  | 0  |     const bool bPropagateNoData = CPLTestBool(  | 
2728  | 0  |         CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));  | 
2729  |  | 
  | 
2730  | 0  |     if (oKernel.ProcessArguments(papszArgs) == CE_Failure)  | 
2731  | 0  |     { | 
2732  | 0  |         return CE_Failure;  | 
2733  | 0  |     }  | 
2734  |  |  | 
2735  |  |     /* ---- Set pixels ---- */  | 
2736  | 0  |     size_t ii = 0;  | 
2737  | 0  |     for (int iLine = 0; iLine < nYSize; ++iLine)  | 
2738  | 0  |     { | 
2739  | 0  |         for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)  | 
2740  | 0  |         { | 
2741  | 0  |             oKernel.Reset();  | 
2742  | 0  |             bool bWriteNoData = false;  | 
2743  |  | 
  | 
2744  | 0  |             for (int iSrc = 0; iSrc < nSources; ++iSrc)  | 
2745  | 0  |             { | 
2746  | 0  |                 const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);  | 
2747  |  | 
  | 
2748  | 0  |                 if (bHasNoData && IsNoData(dfVal, dfNoData))  | 
2749  | 0  |                 { | 
2750  | 0  |                     if (bPropagateNoData)  | 
2751  | 0  |                     { | 
2752  | 0  |                         bWriteNoData = true;  | 
2753  | 0  |                         break;  | 
2754  | 0  |                     }  | 
2755  | 0  |                 }  | 
2756  | 0  |                 else  | 
2757  | 0  |                 { | 
2758  | 0  |                     oKernel.ProcessPixel(dfVal);  | 
2759  | 0  |                 }  | 
2760  | 0  |             }  | 
2761  |  | 
  | 
2762  | 0  |             double dfPixVal{dfNoData}; | 
2763  | 0  |             if (!bWriteNoData && oKernel.HasValue())  | 
2764  | 0  |             { | 
2765  | 0  |                 dfPixVal = oKernel.GetValue();  | 
2766  | 0  |             }  | 
2767  |  | 
  | 
2768  | 0  |             GDALCopyWords(&dfPixVal, GDT_Float64, 0,  | 
2769  | 0  |                           static_cast<GByte *>(pData) +  | 
2770  | 0  |                               static_cast<GSpacing>(nLineSpace) * iLine +  | 
2771  | 0  |                               iCol * nPixelSpace,  | 
2772  | 0  |                           eBufType, nPixelSpace, 1);  | 
2773  | 0  |         }  | 
2774  | 0  |     }  | 
2775  |  |  | 
2776  |  |     /* ---- Return success ---- */  | 
2777  | 0  |     return CE_None;  | 
2778  | 0  | }  // BasicPixelFunc Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<MeanKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*) Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<GeoMeanKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*) Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<HarmonicMeanKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*) Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<MedianKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*) Unexecuted instantiation: pixelfunctions.cpp:CPLErr BasicPixelFunc<ModeKernel>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)  | 
2779  |  |  | 
2780  |  | /************************************************************************/  | 
2781  |  | /*                     GDALRegisterDefaultPixelFunc()                   */  | 
2782  |  | /************************************************************************/  | 
2783  |  |  | 
2784  |  | /**  | 
2785  |  |  * This adds a default set of pixel functions to the global list of  | 
2786  |  |  * available pixel functions for derived bands:  | 
2787  |  |  *  | 
2788  |  |  * - "real": extract real part from a single raster band (just a copy if the  | 
2789  |  |  *           input is non-complex)  | 
2790  |  |  * - "imag": extract imaginary part from a single raster band (0 for  | 
2791  |  |  *           non-complex)  | 
2792  |  |  * - "complex": make a complex band merging two bands used as real and  | 
2793  |  |  *              imag values  | 
2794  |  |  * - "polar": make a complex band using input bands for amplitude and  | 
2795  |  |  *            phase values (b1 * exp( j * b2 ))  | 
2796  |  |  * - "mod": extract module from a single raster band (real or complex)  | 
2797  |  |  * - "phase": extract phase from a single raster band [-PI,PI] (0 or PI for  | 
2798  |  |               non-complex)  | 
2799  |  |  * - "conj": computes the complex conjugate of a single raster band (just a  | 
2800  |  |  *           copy if the input is non-complex)  | 
2801  |  |  * - "sum": sum 2 or more raster bands  | 
2802  |  |  * - "diff": computes the difference between 2 raster bands (b1 - b2)  | 
2803  |  |  * - "mul": multiply 2 or more raster bands  | 
2804  |  |  * - "div": divide one raster band by another (b1 / b2).  | 
2805  |  |  * - "min": minimum value of 2 or more raster bands  | 
2806  |  |  * - "max": maximum value of 2 or more raster bands  | 
2807  |  |  * - "norm_diff": computes the normalized difference between two raster bands:  | 
2808  |  |  *                ``(b1 - b2)/(b1 + b2)``.  | 
2809  |  |  * - "cmul": multiply the first band for the complex conjugate of the second  | 
2810  |  |  * - "inv": inverse (1./x).  | 
2811  |  |  * - "intensity": computes the intensity Re(x*conj(x)) of a single raster band  | 
2812  |  |  *                (real or complex)  | 
2813  |  |  * - "sqrt": perform the square root of a single raster band (real only)  | 
2814  |  |  * - "log10": compute the logarithm (base 10) of the abs of a single raster  | 
2815  |  |  *            band (real or complex): log10( abs( x ) )  | 
2816  |  |  * - "dB": perform conversion to dB of the abs of a single raster  | 
2817  |  |  *         band (real or complex): 20. * log10( abs( x ) ).  | 
2818  |  |  *         Note: the optional fact parameter can be set to 10. to get the  | 
2819  |  |  *         alternative formula: 10. * log10( abs( x ) )  | 
2820  |  |  * - "exp": computes the exponential of each element in the input band ``x``  | 
2821  |  |  *          (of real values): ``e ^ x``.  | 
2822  |  |  *          The function also accepts two optional parameters: ``base`` and  | 
2823  |  |  ``fact``  | 
2824  |  |  *          that allow to compute the generalized formula: ``base ^ ( fact *  | 
2825  |  |  x)``.  | 
2826  |  |  *          Note: this function is the recommended one to perform conversion  | 
2827  |  |  *          form logarithmic scale (dB): `` 10. ^ (x / 20.)``, in this case  | 
2828  |  |  *          ``base = 10.`` and ``fact = 1./20``  | 
2829  |  |  * - "dB2amp": perform scale conversion from logarithmic to linear  | 
2830  |  |  *             (amplitude) (i.e. 10 ^ ( x / 20 ) ) of a single raster  | 
2831  |  |  *             band (real only).  | 
2832  |  |  *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function  | 
2833  |  |  with  | 
2834  |  |  *             ``base = 10.`` and ``fact = 0.05`` i.e. ``1./20``  | 
2835  |  |  * - "dB2pow": perform scale conversion from logarithmic to linear  | 
2836  |  |  *             (power) (i.e. 10 ^ ( x / 10 ) ) of a single raster  | 
2837  |  |  *             band (real only)  | 
2838  |  |  *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function  | 
2839  |  |  with  | 
2840  |  |  *             ``base = 10.`` and ``fact = 0.1`` i.e. ``1./10``  | 
2841  |  |  * - "pow": raise a single raster band to a constant power  | 
2842  |  |  * - "interpolate_linear": interpolate values between two raster bands  | 
2843  |  |  *                         using linear interpolation  | 
2844  |  |  * - "interpolate_exp": interpolate values between two raster bands using  | 
2845  |  |  *                      exponential interpolation  | 
2846  |  |  * - "scale": Apply the RasterBand metadata values of "offset" and "scale"  | 
2847  |  |  * - "reclassify": Reclassify values matching ranges in a table  | 
2848  |  |  * - "nan": Convert incoming NoData values to IEEE 754 nan  | 
2849  |  |  *  | 
2850  |  |  * @see GDALAddDerivedBandPixelFunc  | 
2851  |  |  *  | 
2852  |  |  * @return CE_None  | 
2853  |  |  */  | 
2854  |  | CPLErr GDALRegisterDefaultPixelFunc()  | 
2855  | 0  | { | 
2856  | 0  |     GDALAddDerivedBandPixelFunc("real", RealPixelFunc); | 
2857  | 0  |     GDALAddDerivedBandPixelFunc("imag", ImagPixelFunc); | 
2858  | 0  |     GDALAddDerivedBandPixelFunc("complex", ComplexPixelFunc); | 
2859  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("polar", PolarPixelFunc, | 
2860  | 0  |                                         pszPolarPixelFuncMetadata);  | 
2861  | 0  |     GDALAddDerivedBandPixelFunc("mod", ModulePixelFunc); | 
2862  | 0  |     GDALAddDerivedBandPixelFunc("phase", PhasePixelFunc); | 
2863  | 0  |     GDALAddDerivedBandPixelFunc("conj", ConjPixelFunc); | 
2864  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("sum", SumPixelFunc, | 
2865  | 0  |                                         pszSumPixelFuncMetadata);  | 
2866  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("diff", DiffPixelFunc, | 
2867  | 0  |                                         pszDiffPixelFuncMetadata);  | 
2868  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("mul", MulPixelFunc, | 
2869  | 0  |                                         pszMulPixelFuncMetadata);  | 
2870  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("div", DivPixelFunc, | 
2871  | 0  |                                         pszDivPixelFuncMetadata);  | 
2872  | 0  |     GDALAddDerivedBandPixelFunc("cmul", CMulPixelFunc); | 
2873  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("inv", InvPixelFunc, | 
2874  | 0  |                                         pszInvPixelFuncMetadata);  | 
2875  | 0  |     GDALAddDerivedBandPixelFunc("intensity", IntensityPixelFunc); | 
2876  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("sqrt", SqrtPixelFunc, | 
2877  | 0  |                                         pszSqrtPixelFuncMetadata);  | 
2878  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("log10", Log10PixelFunc, | 
2879  | 0  |                                         pszLog10PixelFuncMetadata);  | 
2880  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("dB", DBPixelFunc, | 
2881  | 0  |                                         pszDBPixelFuncMetadata);  | 
2882  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("exp", ExpPixelFunc, | 
2883  | 0  |                                         pszExpPixelFuncMetadata);  | 
2884  | 0  |     GDALAddDerivedBandPixelFunc("dB2amp", | 
2885  | 0  |                                 dB2AmpPixelFunc);  // deprecated in v3.5  | 
2886  | 0  |     GDALAddDerivedBandPixelFunc("dB2pow", | 
2887  | 0  |                                 dB2PowPixelFunc);  // deprecated in v3.5  | 
2888  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("pow", PowPixelFunc, | 
2889  | 0  |                                         pszPowPixelFuncMetadata);  | 
2890  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("interpolate_linear", | 
2891  | 0  |                                         InterpolatePixelFunc<InterpolateLinear>,  | 
2892  | 0  |                                         pszInterpolatePixelFuncMetadata);  | 
2893  | 0  |     GDALAddDerivedBandPixelFuncWithArgs(  | 
2894  | 0  |         "interpolate_exp", InterpolatePixelFunc<InterpolateExponential>,  | 
2895  | 0  |         pszInterpolatePixelFuncMetadata);  | 
2896  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("replace_nodata", | 
2897  | 0  |                                         ReplaceNoDataPixelFunc,  | 
2898  | 0  |                                         pszReplaceNoDataPixelFuncMetadata);  | 
2899  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("scale", ScalePixelFunc, | 
2900  | 0  |                                         pszScalePixelFuncMetadata);  | 
2901  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("norm_diff", NormDiffPixelFunc, | 
2902  | 0  |                                         pszNormDiffPixelFuncMetadata);  | 
2903  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("min", MinPixelFunc, | 
2904  | 0  |                                         pszMinMaxFuncMetadataNodata);  | 
2905  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("max", MaxPixelFunc, | 
2906  | 0  |                                         pszMinMaxFuncMetadataNodata);  | 
2907  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("expression", ExprPixelFunc, | 
2908  | 0  |                                         pszExprPixelFuncMetadata);  | 
2909  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("reclassify", ReclassifyPixelFunc, | 
2910  | 0  |                                         pszReclassifyPixelFuncMetadata);  | 
2911  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("mean", BasicPixelFunc<MeanKernel>, | 
2912  | 0  |                                         pszBasicPixelFuncMetadata);  | 
2913  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("geometric_mean", | 
2914  | 0  |                                         BasicPixelFunc<GeoMeanKernel>,  | 
2915  | 0  |                                         pszBasicPixelFuncMetadata);  | 
2916  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("harmonic_mean", | 
2917  | 0  |                                         BasicPixelFunc<HarmonicMeanKernel>,  | 
2918  | 0  |                                         pszBasicPixelFuncMetadata);  | 
2919  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("median", BasicPixelFunc<MedianKernel>, | 
2920  | 0  |                                         pszBasicPixelFuncMetadata);  | 
2921  | 0  |     GDALAddDerivedBandPixelFuncWithArgs("mode", BasicPixelFunc<ModeKernel>, | 
2922  | 0  |                                         pszBasicPixelFuncMetadata);  | 
2923  | 0  |     return CE_None;  | 
2924  | 0  | }  |