Coverage Report

Created: 2025-06-13 06:18

/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
}