Coverage Report

Created: 2026-07-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/vrt/pixelfunctions.cpp
Line
Count
Source
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 <array>
15
#include <charconv>
16
#include <cmath>
17
#include "gdal.h"
18
#include "vrtdataset.h"
19
#include "vrtexpression.h"
20
#include "vrtreclassifier.h"
21
#include "cpl_float.h"
22
23
#include "geodesic.h"  // from PROJ
24
25
#if defined(__x86_64) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
26
#define USE_SSE2
27
#include "gdalsse_priv.h"
28
29
#if !defined(USE_NEON_OPTIMIZATIONS)
30
#define LIBDIVIDE_SSE2
31
#ifdef __GNUC__
32
#pragma GCC diagnostic push
33
#pragma GCC diagnostic ignored "-Wold-style-cast"
34
#pragma GCC diagnostic ignored "-Weffc++"
35
#endif
36
#include "../../third_party/libdivide/libdivide.h"
37
#ifdef __GNUC__
38
#pragma GCC diagnostic pop
39
#endif
40
#endif
41
42
#endif
43
44
#include "gdal_priv_templates.hpp"
45
46
#include <algorithm>
47
#include <cassert>
48
#include <limits>
49
50
namespace gdal
51
{
52
0
MathExpression::~MathExpression() = default;
53
}
54
55
template <typename T>
56
inline double GetSrcVal(const void *pSource, GDALDataType eSrcType, T ii)
57
0
{
58
0
    switch (eSrcType)
59
0
    {
60
0
        case GDT_Unknown:
61
0
            return 0;
62
0
        case GDT_UInt8:
63
0
            return static_cast<const GByte *>(pSource)[ii];
64
0
        case GDT_Int8:
65
0
            return static_cast<const GInt8 *>(pSource)[ii];
66
0
        case GDT_UInt16:
67
0
            return static_cast<const GUInt16 *>(pSource)[ii];
68
0
        case GDT_Int16:
69
0
            return static_cast<const GInt16 *>(pSource)[ii];
70
0
        case GDT_UInt32:
71
0
            return static_cast<const GUInt32 *>(pSource)[ii];
72
0
        case GDT_Int32:
73
0
            return static_cast<const GInt32 *>(pSource)[ii];
74
        // Precision loss currently for int64/uint64
75
0
        case GDT_UInt64:
76
0
            return static_cast<double>(
77
0
                static_cast<const uint64_t *>(pSource)[ii]);
78
0
        case GDT_Int64:
79
0
            return static_cast<double>(
80
0
                static_cast<const int64_t *>(pSource)[ii]);
81
0
        case GDT_Float16:
82
0
            return static_cast<const GFloat16 *>(pSource)[ii];
83
0
        case GDT_Float32:
84
0
            return static_cast<const float *>(pSource)[ii];
85
0
        case GDT_Float64:
86
0
            return static_cast<const double *>(pSource)[ii];
87
0
        case GDT_CInt16:
88
0
            return static_cast<const GInt16 *>(pSource)[2 * ii];
89
0
        case GDT_CInt32:
90
0
            return static_cast<const GInt32 *>(pSource)[2 * ii];
91
0
        case GDT_CFloat16:
92
0
            return static_cast<const GFloat16 *>(pSource)[2 * ii];
93
0
        case GDT_CFloat32:
94
0
            return static_cast<const float *>(pSource)[2 * ii];
95
0
        case GDT_CFloat64:
96
0
            return static_cast<const double *>(pSource)[2 * ii];
97
0
        case GDT_TypeCount:
98
0
            break;
99
0
    }
100
0
    return 0;
101
0
}
102
103
static bool IsNoData(double dfVal, double dfNoData)
104
0
{
105
0
    return dfVal == dfNoData || (std::isnan(dfVal) && std::isnan(dfNoData));
106
0
}
107
108
static CPLErr FetchDoubleArg(CSLConstList papszArgs, const char *pszName,
109
                             double *pdfX, double *pdfDefault = nullptr)
110
0
{
111
0
    const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
112
113
0
    if (pszVal == nullptr)
114
0
    {
115
0
        if (pdfDefault == nullptr)
116
0
        {
117
0
            CPLError(CE_Failure, CPLE_AppDefined,
118
0
                     "Missing pixel function argument: %s", pszName);
119
0
            return CE_Failure;
120
0
        }
121
0
        else
122
0
        {
123
0
            *pdfX = *pdfDefault;
124
0
            return CE_None;
125
0
        }
126
0
    }
127
128
0
    char *pszEnd = nullptr;
129
0
    *pdfX = std::strtod(pszVal, &pszEnd);
130
0
    if (pszEnd == pszVal)
131
0
    {
132
0
        CPLError(CE_Failure, CPLE_AppDefined,
133
0
                 "Failed to parse pixel function argument: %s", pszName);
134
0
        return CE_Failure;
135
0
    }
136
137
0
    return CE_None;
138
0
}
139
140
static CPLErr FetchIntegerArg(CSLConstList papszArgs, const char *pszName,
141
                              int *pnX, int *pnDefault = nullptr)
142
0
{
143
0
    const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
144
145
0
    if (pszVal == nullptr)
146
0
    {
147
0
        if (pnDefault == nullptr)
148
0
        {
149
0
            CPLError(CE_Failure, CPLE_AppDefined,
150
0
                     "Missing pixel function argument: %s", pszName);
151
0
            return CE_Failure;
152
0
        }
153
0
        else
154
0
        {
155
0
            *pnX = *pnDefault;
156
0
            return CE_None;
157
0
        }
158
0
    }
159
160
0
    char *pszEnd = nullptr;
161
0
    const auto ret = std::strtol(pszVal, &pszEnd, 10);
162
0
    while (std::isspace(*pszEnd))
163
0
    {
164
0
        pszEnd++;
165
0
    }
166
0
    if (*pszEnd != '\0')
167
0
    {
168
0
        CPLError(CE_Failure, CPLE_AppDefined,
169
0
                 "Failed to parse pixel function argument: %s", pszName);
170
0
        return CE_Failure;
171
0
    }
172
173
0
    if (ret > std::numeric_limits<int>::max())
174
0
    {
175
0
        CPLError(CE_Failure, CPLE_AppDefined,
176
0
                 "Pixel function argument %s is above the maximum value of %d",
177
0
                 pszName, std::numeric_limits<int>::max());
178
0
        return CE_Failure;
179
0
    }
180
181
0
    *pnX = static_cast<int>(ret);
182
183
0
    return CE_None;
184
0
}
185
186
static CPLErr RealPixelFunc(void **papoSources, int nSources, void *pData,
187
                            int nXSize, int nYSize, GDALDataType eSrcType,
188
                            GDALDataType eBufType, int nPixelSpace,
189
                            int nLineSpace)
190
0
{
191
    /* ---- Init ---- */
192
0
    if (nSources != 1)
193
0
        return CE_Failure;
194
195
0
    const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);
196
0
    const size_t nLineSpaceSrc = static_cast<size_t>(nPixelSpaceSrc) * nXSize;
197
198
    /* ---- Set pixels ---- */
199
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
200
0
    {
201
0
        GDALCopyWords(static_cast<GByte *>(papoSources[0]) +
202
0
                          nLineSpaceSrc * iLine,
203
0
                      eSrcType, nPixelSpaceSrc,
204
0
                      static_cast<GByte *>(pData) +
205
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
206
0
                      eBufType, nPixelSpace, nXSize);
207
0
    }
208
209
    /* ---- Return success ---- */
210
0
    return CE_None;
211
0
}  // RealPixelFunc
212
213
static CPLErr ImagPixelFunc(void **papoSources, int nSources, void *pData,
214
                            int nXSize, int nYSize, GDALDataType eSrcType,
215
                            GDALDataType eBufType, int nPixelSpace,
216
                            int nLineSpace)
217
0
{
218
    /* ---- Init ---- */
219
0
    if (nSources != 1)
220
0
        return CE_Failure;
221
222
0
    if (GDALDataTypeIsComplex(eSrcType))
223
0
    {
224
0
        const GDALDataType eSrcBaseType = GDALGetNonComplexDataType(eSrcType);
225
0
        const int nPixelSpaceSrc = GDALGetDataTypeSizeBytes(eSrcType);
226
0
        const size_t nLineSpaceSrc =
227
0
            static_cast<size_t>(nPixelSpaceSrc) * nXSize;
228
229
0
        const void *const pImag = static_cast<GByte *>(papoSources[0]) +
230
0
                                  GDALGetDataTypeSizeBytes(eSrcType) / 2;
231
232
        /* ---- Set pixels ---- */
233
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
234
0
        {
235
0
            GDALCopyWords(static_cast<const GByte *>(pImag) +
236
0
                              nLineSpaceSrc * iLine,
237
0
                          eSrcBaseType, nPixelSpaceSrc,
238
0
                          static_cast<GByte *>(pData) +
239
0
                              static_cast<GSpacing>(nLineSpace) * iLine,
240
0
                          eBufType, nPixelSpace, nXSize);
241
0
        }
242
0
    }
243
0
    else
244
0
    {
245
0
        const double dfImag = 0;
246
247
        /* ---- Set pixels ---- */
248
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
249
0
        {
250
            // Always copy from the same location.
251
0
            GDALCopyWords(&dfImag, eSrcType, 0,
252
0
                          static_cast<GByte *>(pData) +
253
0
                              static_cast<GSpacing>(nLineSpace) * iLine,
254
0
                          eBufType, nPixelSpace, nXSize);
255
0
        }
256
0
    }
257
258
    /* ---- Return success ---- */
259
0
    return CE_None;
260
0
}  // ImagPixelFunc
261
262
static CPLErr ComplexPixelFunc(void **papoSources, int nSources, void *pData,
263
                               int nXSize, int nYSize, GDALDataType eSrcType,
264
                               GDALDataType eBufType, int nPixelSpace,
265
                               int nLineSpace)
266
0
{
267
    /* ---- Init ---- */
268
0
    if (nSources != 2)
269
0
        return CE_Failure;
270
271
0
    const void *const pReal = papoSources[0];
272
0
    const void *const pImag = papoSources[1];
273
274
    /* ---- Set pixels ---- */
275
0
    size_t ii = 0;
276
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
277
0
    {
278
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
279
0
        {
280
            // Source raster pixels may be obtained with GetSrcVal macro.
281
0
            const double adfPixVal[2] = {
282
0
                GetSrcVal(pReal, eSrcType, ii),  // re
283
0
                GetSrcVal(pImag, eSrcType, ii)   // im
284
0
            };
285
286
0
            GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
287
0
                          static_cast<GByte *>(pData) +
288
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
289
0
                              iCol * nPixelSpace,
290
0
                          eBufType, nPixelSpace, 1);
291
0
        }
292
0
    }
293
294
    /* ---- Return success ---- */
295
0
    return CE_None;
296
0
}  // ComplexPixelFunc
297
298
typedef enum
299
{
300
    GAT_amplitude,
301
    GAT_intensity,
302
    GAT_dB
303
} PolarAmplitudeType;
304
305
static const char pszPolarPixelFuncMetadata[] =
306
    "<PixelFunctionArgumentsList>"
307
    "   <Argument name='amplitude_type' description='Amplitude Type' "
308
    "type='string-select' default='AMPLITUDE'>"
309
    "       <Value>INTENSITY</Value>"
310
    "       <Value>dB</Value>"
311
    "       <Value>AMPLITUDE</Value>"
312
    "   </Argument>"
313
    "</PixelFunctionArgumentsList>";
314
315
static CPLErr PolarPixelFunc(void **papoSources, int nSources, void *pData,
316
                             int nXSize, int nYSize, GDALDataType eSrcType,
317
                             GDALDataType eBufType, int nPixelSpace,
318
                             int nLineSpace, CSLConstList papszArgs)
319
0
{
320
    /* ---- Init ---- */
321
0
    if (nSources != 2)
322
0
        return CE_Failure;
323
324
0
    const char pszName[] = "amplitude_type";
325
0
    const char *pszVal = CSLFetchNameValue(papszArgs, pszName);
326
0
    PolarAmplitudeType amplitudeType = GAT_amplitude;
327
0
    if (pszVal != nullptr)
328
0
    {
329
0
        if (strcmp(pszVal, "INTENSITY") == 0)
330
0
            amplitudeType = GAT_intensity;
331
0
        else if (strcmp(pszVal, "dB") == 0)
332
0
            amplitudeType = GAT_dB;
333
0
        else if (strcmp(pszVal, "AMPLITUDE") != 0)
334
0
        {
335
0
            CPLError(CE_Failure, CPLE_AppDefined,
336
0
                     "Invalid value for pixel function argument '%s': %s",
337
0
                     pszName, pszVal);
338
0
            return CE_Failure;
339
0
        }
340
0
    }
341
342
0
    const void *const pAmp = papoSources[0];
343
0
    const void *const pPhase = papoSources[1];
344
345
    /* ---- Set pixels ---- */
346
0
    size_t ii = 0;
347
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
348
0
    {
349
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
350
0
        {
351
            // Source raster pixels may be obtained with GetSrcVal macro.
352
0
            double dfAmp = GetSrcVal(pAmp, eSrcType, ii);
353
0
            switch (amplitudeType)
354
0
            {
355
0
                case GAT_intensity:
356
                    // clip to zero
357
0
                    dfAmp = dfAmp <= 0 ? 0 : std::sqrt(dfAmp);
358
0
                    break;
359
0
                case GAT_dB:
360
0
                    dfAmp = dfAmp <= 0
361
0
                                ? -std::numeric_limits<double>::infinity()
362
0
                                : pow(10, dfAmp / 20.);
363
0
                    break;
364
0
                case GAT_amplitude:
365
0
                    break;
366
0
            }
367
0
            const double dfPhase = GetSrcVal(pPhase, eSrcType, ii);
368
0
            const double adfPixVal[2] = {
369
0
                dfAmp * std::cos(dfPhase),  // re
370
0
                dfAmp * std::sin(dfPhase)   // im
371
0
            };
372
373
0
            GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
374
0
                          static_cast<GByte *>(pData) +
375
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
376
0
                              iCol * nPixelSpace,
377
0
                          eBufType, nPixelSpace, 1);
378
0
        }
379
0
    }
380
381
    /* ---- Return success ---- */
382
0
    return CE_None;
383
0
}  // PolarPixelFunc
384
385
static constexpr char pszModulePixelFuncMetadata[] =
386
    "<PixelFunctionArgumentsList>"
387
    "   <Argument type='builtin' value='NoData' optional='true' />"
388
    "</PixelFunctionArgumentsList>";
389
390
static CPLErr ModulePixelFunc(void **papoSources, int nSources, void *pData,
391
                              int nXSize, int nYSize, GDALDataType eSrcType,
392
                              GDALDataType eBufType, int nPixelSpace,
393
                              int nLineSpace, CSLConstList papszArgs)
394
0
{
395
    /* ---- Init ---- */
396
0
    if (nSources != 1)
397
0
        return CE_Failure;
398
399
0
    if (GDALDataTypeIsComplex(eSrcType))
400
0
    {
401
0
        const void *pReal = papoSources[0];
402
0
        const void *pImag = static_cast<GByte *>(papoSources[0]) +
403
0
                            GDALGetDataTypeSizeBytes(eSrcType) / 2;
404
405
        /* ---- Set pixels ---- */
406
0
        size_t ii = 0;
407
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
408
0
        {
409
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
410
0
            {
411
                // Source raster pixels may be obtained with GetSrcVal macro.
412
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
413
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
414
415
0
                const double dfPixVal = sqrt(dfReal * dfReal + dfImag * dfImag);
416
417
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
418
0
                              static_cast<GByte *>(pData) +
419
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
420
0
                                  iCol * nPixelSpace,
421
0
                              eBufType, nPixelSpace, 1);
422
0
            }
423
0
        }
424
0
    }
425
0
    else
426
0
    {
427
0
        double dfNoData{0};
428
0
        const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
429
0
        if (bHasNoData &&
430
0
            FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
431
0
            return CE_Failure;
432
433
        /* ---- Set pixels ---- */
434
0
        size_t ii = 0;
435
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
436
0
        {
437
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
438
0
            {
439
0
                const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
440
441
                // Source raster pixels may be obtained with GetSrcVal macro.
442
0
                const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
443
0
                                            ? dfNoData
444
0
                                            : std::fabs(dfVal);
445
446
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
447
0
                              static_cast<GByte *>(pData) +
448
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
449
0
                                  iCol * nPixelSpace,
450
0
                              eBufType, nPixelSpace, 1);
451
0
            }
452
0
        }
453
0
    }
454
455
    /* ---- Return success ---- */
456
0
    return CE_None;
457
0
}  // ModulePixelFunc
458
459
static CPLErr PhasePixelFunc(void **papoSources, int nSources, void *pData,
460
                             int nXSize, int nYSize, GDALDataType eSrcType,
461
                             GDALDataType eBufType, int nPixelSpace,
462
                             int nLineSpace)
463
0
{
464
    /* ---- Init ---- */
465
0
    if (nSources != 1)
466
0
        return CE_Failure;
467
468
0
    if (GDALDataTypeIsComplex(eSrcType))
469
0
    {
470
0
        const void *const pReal = papoSources[0];
471
0
        const void *const pImag = static_cast<GByte *>(papoSources[0]) +
472
0
                                  GDALGetDataTypeSizeBytes(eSrcType) / 2;
473
474
        /* ---- Set pixels ---- */
475
0
        size_t ii = 0;
476
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
477
0
        {
478
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
479
0
            {
480
                // Source raster pixels may be obtained with GetSrcVal macro.
481
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
482
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
483
484
0
                const double dfPixVal = atan2(dfImag, dfReal);
485
486
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
487
0
                              static_cast<GByte *>(pData) +
488
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
489
0
                                  iCol * nPixelSpace,
490
0
                              eBufType, nPixelSpace, 1);
491
0
            }
492
0
        }
493
0
    }
494
0
    else if (GDALDataTypeIsInteger(eSrcType) && !GDALDataTypeIsSigned(eSrcType))
495
0
    {
496
0
        constexpr double dfZero = 0;
497
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
498
0
        {
499
0
            GDALCopyWords(&dfZero, GDT_Float64, 0,
500
0
                          static_cast<GByte *>(pData) +
501
0
                              static_cast<GSpacing>(nLineSpace) * iLine,
502
0
                          eBufType, nPixelSpace, nXSize);
503
0
        }
504
0
    }
505
0
    else
506
0
    {
507
        /* ---- Set pixels ---- */
508
0
        size_t ii = 0;
509
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
510
0
        {
511
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
512
0
            {
513
0
                const void *const pReal = papoSources[0];
514
515
                // Source raster pixels may be obtained with GetSrcVal macro.
516
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
517
0
                const double dfPixVal = (dfReal < 0) ? M_PI : 0.0;
518
519
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
520
0
                              static_cast<GByte *>(pData) +
521
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
522
0
                                  iCol * nPixelSpace,
523
0
                              eBufType, nPixelSpace, 1);
524
0
            }
525
0
        }
526
0
    }
527
528
    /* ---- Return success ---- */
529
0
    return CE_None;
530
0
}  // PhasePixelFunc
531
532
static CPLErr ConjPixelFunc(void **papoSources, int nSources, void *pData,
533
                            int nXSize, int nYSize, GDALDataType eSrcType,
534
                            GDALDataType eBufType, int nPixelSpace,
535
                            int nLineSpace)
536
0
{
537
    /* ---- Init ---- */
538
0
    if (nSources != 1)
539
0
        return CE_Failure;
540
541
0
    if (GDALDataTypeIsComplex(eSrcType) && GDALDataTypeIsComplex(eBufType))
542
0
    {
543
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
544
0
        const void *const pReal = papoSources[0];
545
0
        const void *const pImag =
546
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
547
548
        /* ---- Set pixels ---- */
549
0
        size_t ii = 0;
550
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
551
0
        {
552
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
553
0
            {
554
                // Source raster pixels may be obtained with GetSrcVal macro.
555
0
                const double adfPixVal[2] = {
556
0
                    +GetSrcVal(pReal, eSrcType, ii),  // re
557
0
                    -GetSrcVal(pImag, eSrcType, ii)   // im
558
0
                };
559
560
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
561
0
                              static_cast<GByte *>(pData) +
562
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
563
0
                                  iCol * nPixelSpace,
564
0
                              eBufType, nPixelSpace, 1);
565
0
            }
566
0
        }
567
0
    }
568
0
    else
569
0
    {
570
        // No complex data type.
571
0
        return RealPixelFunc(papoSources, nSources, pData, nXSize, nYSize,
572
0
                             eSrcType, eBufType, nPixelSpace, nLineSpace);
573
0
    }
574
575
    /* ---- Return success ---- */
576
0
    return CE_None;
577
0
}  // ConjPixelFunc
578
579
static constexpr char pszRoundPixelFuncMetadata[] =
580
    "<PixelFunctionArgumentsList>"
581
    "   <Argument name='digits' description='Digits' type='integer' "
582
    "default='0' />"
583
    "   <Argument type='builtin' value='NoData' optional='true' />"
584
    "</PixelFunctionArgumentsList>";
585
586
static CPLErr RoundPixelFunc(void **papoSources, int nSources, void *pData,
587
                             int nXSize, int nYSize, GDALDataType eSrcType,
588
                             GDALDataType eBufType, int nPixelSpace,
589
                             int nLineSpace, CSLConstList papszArgs)
590
0
{
591
    /* ---- Init ---- */
592
0
    if (nSources != 1)
593
0
    {
594
0
        CPLError(CE_Failure, CPLE_AppDefined,
595
0
                 "round: input must be a single band");
596
0
        return CE_Failure;
597
0
    }
598
599
0
    if (GDALDataTypeIsComplex(eSrcType))
600
0
    {
601
0
        CPLError(CE_Failure, CPLE_AppDefined,
602
0
                 "round: complex data types not supported");
603
0
        return CE_Failure;
604
0
    }
605
606
0
    double dfNoData{0};
607
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
608
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
609
0
        return CE_Failure;
610
611
0
    int nDigits{0};
612
0
    if (FetchIntegerArg(papszArgs, "digits", &nDigits, &nDigits) != CE_None)
613
0
        return CE_Failure;
614
615
0
    const double dfScaleVal = std::pow(10, nDigits);
616
0
    const double dfInvScaleVal = 1. / dfScaleVal;
617
618
    /* ---- Set pixels ---- */
619
0
    size_t ii = 0;
620
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
621
0
    {
622
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
623
0
        {
624
            // Source raster pixels may be obtained with GetSrcVal macro.
625
0
            const double dfSrcVal = GetSrcVal(papoSources[0], eSrcType, ii);
626
627
0
            const double dfDstVal =
628
0
                bHasNoData && IsNoData(dfSrcVal, dfNoData)
629
0
                    ? dfNoData
630
0
                    : std::round(dfSrcVal * dfScaleVal) * dfInvScaleVal;
631
632
0
            GDALCopyWords(&dfDstVal, GDT_Float64, 0,
633
0
                          static_cast<GByte *>(pData) +
634
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
635
0
                              iCol * nPixelSpace,
636
0
                          eBufType, nPixelSpace, 1);
637
0
        }
638
0
    }
639
640
    /* ---- Return success ---- */
641
0
    return CE_None;
642
0
}  // RoundPixelFunc
643
644
#ifdef USE_SSE2
645
646
/************************************************************************/
647
/*                      OptimizedSumToFloat_SSE2()                      */
648
/************************************************************************/
649
650
template <typename Tsrc>
651
static void OptimizedSumToFloat_SSE2(double dfK, void *pOutBuffer,
652
                                     int nLineSpace, int nXSize, int nYSize,
653
                                     int nSources,
654
                                     const void *const *papoSources)
655
0
{
656
0
    const XMMReg4Float cst = XMMReg4Float::Set1(static_cast<float>(dfK));
657
658
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
659
0
    {
660
0
        float *CPL_RESTRICT const pDest = reinterpret_cast<float *>(
661
0
            static_cast<GByte *>(pOutBuffer) +
662
0
            static_cast<GSpacing>(nLineSpace) * iLine);
663
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
664
665
0
        constexpr int VALUES_PER_REG = 4;
666
0
        constexpr int UNROLLING = 4 * VALUES_PER_REG;
667
0
        int iCol = 0;
668
0
        for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)
669
0
        {
670
0
            XMMReg4Float d0(cst);
671
0
            XMMReg4Float d1(cst);
672
0
            XMMReg4Float d2(cst);
673
0
            XMMReg4Float d3(cst);
674
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
675
0
            {
676
0
                XMMReg4Float t0, t1, t2, t3;
677
0
                XMMReg4Float::Load16Val(
678
0
                    static_cast<const Tsrc * CPL_RESTRICT>(papoSources[iSrc]) +
679
0
                        iOffsetLine + iCol,
680
0
                    t0, t1, t2, t3);
681
0
                d0 += t0;
682
0
                d1 += t1;
683
0
                d2 += t2;
684
0
                d3 += t3;
685
0
            }
686
0
            d0.Store4Val(pDest + iCol + VALUES_PER_REG * 0);
687
0
            d1.Store4Val(pDest + iCol + VALUES_PER_REG * 1);
688
0
            d2.Store4Val(pDest + iCol + VALUES_PER_REG * 2);
689
0
            d3.Store4Val(pDest + iCol + VALUES_PER_REG * 3);
690
0
        }
691
692
0
        for (; iCol < nXSize; iCol++)
693
0
        {
694
0
            float d = static_cast<float>(dfK);
695
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
696
0
            {
697
0
                d += static_cast<const Tsrc * CPL_RESTRICT>(
698
0
                    papoSources[iSrc])[iOffsetLine + iCol];
699
0
            }
700
0
            pDest[iCol] = d;
701
0
        }
702
0
    }
703
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*)
704
705
/************************************************************************/
706
/*                     OptimizedSumToDouble_SSE2()                      */
707
/************************************************************************/
708
709
template <typename Tsrc>
710
static void OptimizedSumToDouble_SSE2(double dfK, void *pOutBuffer,
711
                                      int nLineSpace, int nXSize, int nYSize,
712
                                      int nSources,
713
                                      const void *const *papoSources)
714
0
{
715
0
    const XMMReg4Double cst = XMMReg4Double::Set1(dfK);
716
717
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
718
0
    {
719
0
        double *CPL_RESTRICT const pDest = reinterpret_cast<double *>(
720
0
            static_cast<GByte *>(pOutBuffer) +
721
0
            static_cast<GSpacing>(nLineSpace) * iLine);
722
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
723
724
0
        constexpr int VALUES_PER_REG = 4;
725
0
        constexpr int UNROLLING = 2 * VALUES_PER_REG;
726
0
        int iCol = 0;
727
0
        for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)
728
0
        {
729
0
            XMMReg4Double d0(cst);
730
0
            XMMReg4Double d1(cst);
731
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
732
0
            {
733
0
                XMMReg4Double t0, t1;
734
0
                XMMReg4Double::Load8Val(
735
0
                    static_cast<const Tsrc * CPL_RESTRICT>(papoSources[iSrc]) +
736
0
                        iOffsetLine + iCol,
737
0
                    t0, t1);
738
0
                d0 += t0;
739
0
                d1 += t1;
740
0
            }
741
0
            d0.Store4Val(pDest + iCol + VALUES_PER_REG * 0);
742
0
            d1.Store4Val(pDest + iCol + VALUES_PER_REG * 1);
743
0
        }
744
745
0
        for (; iCol < nXSize; iCol++)
746
0
        {
747
0
            double d = dfK;
748
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
749
0
            {
750
0
                d += static_cast<const Tsrc * CPL_RESTRICT>(
751
0
                    papoSources[iSrc])[iOffsetLine + iCol];
752
0
            }
753
0
            pDest[iCol] = d;
754
0
        }
755
0
    }
756
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*)
757
758
/************************************************************************/
759
/*                     OptimizedSumSameType_SSE2()                      */
760
/************************************************************************/
761
762
template <typename T, typename Tsigned, typename Tacc, class SSEWrapper>
763
static void OptimizedSumSameType_SSE2(double dfK, void *pOutBuffer,
764
                                      int nLineSpace, int nXSize, int nYSize,
765
                                      int nSources,
766
                                      const void *const *papoSources)
767
0
{
768
0
    static_assert(std::numeric_limits<T>::is_integer);
769
0
    static_assert(!std::numeric_limits<T>::is_signed);
770
0
    static_assert(std::numeric_limits<Tsigned>::is_integer);
771
0
    static_assert(std::numeric_limits<Tsigned>::is_signed);
772
0
    static_assert(sizeof(T) == sizeof(Tsigned));
773
0
    const T nK = static_cast<T>(dfK);
774
0
    Tsigned nKSigned;
775
0
    memcpy(&nKSigned, &nK, sizeof(T));
776
0
    const __m128i valInit = SSEWrapper::Set1(nKSigned);
777
0
    constexpr int VALUES_PER_REG =
778
0
        static_cast<int>(sizeof(valInit) / sizeof(T));
779
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
780
0
    {
781
0
        T *CPL_RESTRICT const pDest =
782
0
            reinterpret_cast<T *>(static_cast<GByte *>(pOutBuffer) +
783
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
784
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
785
0
        int iCol = 0;
786
0
        for (; iCol < nXSize - (4 * VALUES_PER_REG - 1);
787
0
             iCol += 4 * VALUES_PER_REG)
788
0
        {
789
0
            __m128i reg0 = valInit;
790
0
            __m128i reg1 = valInit;
791
0
            __m128i reg2 = valInit;
792
0
            __m128i reg3 = valInit;
793
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
794
0
            {
795
0
                reg0 = SSEWrapper::AddSaturate(
796
0
                    reg0,
797
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
798
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
799
0
                        iOffsetLine + iCol)));
800
0
                reg1 = SSEWrapper::AddSaturate(
801
0
                    reg1,
802
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
803
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
804
0
                        iOffsetLine + iCol + VALUES_PER_REG)));
805
0
                reg2 = SSEWrapper::AddSaturate(
806
0
                    reg2,
807
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
808
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
809
0
                        iOffsetLine + iCol + 2 * VALUES_PER_REG)));
810
0
                reg3 = SSEWrapper::AddSaturate(
811
0
                    reg3,
812
0
                    _mm_loadu_si128(reinterpret_cast<const __m128i *>(
813
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
814
0
                        iOffsetLine + iCol + 3 * VALUES_PER_REG)));
815
0
            }
816
0
            _mm_storeu_si128(reinterpret_cast<__m128i *>(pDest + iCol), reg0);
817
0
            _mm_storeu_si128(
818
0
                reinterpret_cast<__m128i *>(pDest + iCol + VALUES_PER_REG),
819
0
                reg1);
820
0
            _mm_storeu_si128(
821
0
                reinterpret_cast<__m128i *>(pDest + iCol + 2 * VALUES_PER_REG),
822
0
                reg2);
823
0
            _mm_storeu_si128(
824
0
                reinterpret_cast<__m128i *>(pDest + iCol + 3 * VALUES_PER_REG),
825
0
                reg3);
826
0
        }
827
0
        for (; iCol < nXSize; ++iCol)
828
0
        {
829
0
            Tacc nAcc = nK;
830
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
831
0
            {
832
0
                nAcc = std::min<Tacc>(
833
0
                    nAcc + static_cast<const T * CPL_RESTRICT>(
834
0
                               papoSources[iSrc])[iOffsetLine + iCol],
835
0
                    std::numeric_limits<T>::max());
836
0
            }
837
0
            pDest[iCol] = static_cast<T>(nAcc);
838
0
        }
839
0
    }
840
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumSameType_SSE2<unsigned char, signed char, unsigned int, SumPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::SSEWrapper>(double, void*, int, int, int, int, void const* const*)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedSumSameType_SSE2<unsigned short, short, unsigned int, SumPixelFunc(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::SSEWrapper>(double, void*, int, int, int, int, void const* const*)
841
#endif  // USE_SSE2
842
843
/************************************************************************/
844
/*                      OptimizedSumPackedOutput()                      */
845
/************************************************************************/
846
847
template <typename Tsrc, typename Tdest>
848
static void OptimizedSumPackedOutput(double dfK, void *pOutBuffer,
849
                                     int nLineSpace, int nXSize, int nYSize,
850
                                     int nSources,
851
                                     const void *const *papoSources)
852
0
{
853
0
#ifdef USE_SSE2
854
    if constexpr (std::is_same_v<Tdest, float> && !std::is_same_v<Tsrc, double>)
855
0
    {
856
0
        OptimizedSumToFloat_SSE2<Tsrc>(dfK, pOutBuffer, nLineSpace, nXSize,
857
0
                                       nYSize, nSources, papoSources);
858
    }
859
    else if constexpr (std::is_same_v<Tdest, double>)
860
0
    {
861
0
        OptimizedSumToDouble_SSE2<Tsrc>(dfK, pOutBuffer, nLineSpace, nXSize,
862
0
                                        nYSize, nSources, papoSources);
863
    }
864
    else
865
#endif  // USE_SSE2
866
0
    {
867
0
        const Tdest nCst = static_cast<Tdest>(dfK);
868
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
869
0
        {
870
0
            Tdest *CPL_RESTRICT const pDest = reinterpret_cast<Tdest *>(
871
0
                static_cast<GByte *>(pOutBuffer) +
872
0
                static_cast<GSpacing>(nLineSpace) * iLine);
873
0
            const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
874
875
0
#define LOAD_SRCVAL(iSrc_, j_)                                                 \
876
0
    static_cast<Tdest>(static_cast<const Tsrc * CPL_RESTRICT>(                 \
877
0
        papoSources[(iSrc_)])[iOffsetLine + iCol + (j_)])
878
879
0
            constexpr int UNROLLING = 4;
880
0
            int iCol = 0;
881
0
            for (; iCol < nXSize - (UNROLLING - 1); iCol += UNROLLING)
882
0
            {
883
0
                Tdest d[4] = {nCst, nCst, nCst, nCst};
884
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
885
0
                {
886
0
                    d[0] += LOAD_SRCVAL(iSrc, 0);
887
0
                    d[1] += LOAD_SRCVAL(iSrc, 1);
888
0
                    d[2] += LOAD_SRCVAL(iSrc, 2);
889
0
                    d[3] += LOAD_SRCVAL(iSrc, 3);
890
0
                }
891
0
                pDest[iCol + 0] = d[0];
892
0
                pDest[iCol + 1] = d[1];
893
0
                pDest[iCol + 2] = d[2];
894
0
                pDest[iCol + 3] = d[3];
895
0
            }
896
0
            for (; iCol < nXSize; iCol++)
897
0
            {
898
0
                Tdest d0 = nCst;
899
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
900
0
                {
901
0
                    d0 += LOAD_SRCVAL(iSrc, 0);
902
0
                }
903
0
                pDest[iCol] = d0;
904
0
            }
905
0
#undef LOAD_SRCVAL
906
0
        }
907
0
    }
908
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*)
909
910
/************************************************************************/
911
/*                      OptimizedSumPackedOutput()                      */
912
/************************************************************************/
913
914
template <typename Tdest>
915
static bool OptimizedSumPackedOutput(GDALDataType eSrcType, double dfK,
916
                                     void *pOutBuffer, int nLineSpace,
917
                                     int nXSize, int nYSize, int nSources,
918
                                     const void *const *papoSources)
919
0
{
920
0
    switch (eSrcType)
921
0
    {
922
0
        case GDT_UInt8:
923
0
            OptimizedSumPackedOutput<uint8_t, Tdest>(dfK, pOutBuffer,
924
0
                                                     nLineSpace, nXSize, nYSize,
925
0
                                                     nSources, papoSources);
926
0
            return true;
927
928
0
        case GDT_UInt16:
929
0
            OptimizedSumPackedOutput<uint16_t, Tdest>(
930
0
                dfK, pOutBuffer, nLineSpace, nXSize, nYSize, nSources,
931
0
                papoSources);
932
0
            return true;
933
934
0
        case GDT_Int16:
935
0
            OptimizedSumPackedOutput<int16_t, Tdest>(dfK, pOutBuffer,
936
0
                                                     nLineSpace, nXSize, nYSize,
937
0
                                                     nSources, papoSources);
938
0
            return true;
939
940
0
        case GDT_Int32:
941
0
            OptimizedSumPackedOutput<int32_t, Tdest>(dfK, pOutBuffer,
942
0
                                                     nLineSpace, nXSize, nYSize,
943
0
                                                     nSources, papoSources);
944
0
            return true;
945
946
0
        case GDT_Float32:
947
0
            OptimizedSumPackedOutput<float, Tdest>(dfK, pOutBuffer, nLineSpace,
948
0
                                                   nXSize, nYSize, nSources,
949
0
                                                   papoSources);
950
0
            return true;
951
952
0
        case GDT_Float64:
953
0
            OptimizedSumPackedOutput<double, Tdest>(dfK, pOutBuffer, nLineSpace,
954
0
                                                    nXSize, nYSize, nSources,
955
0
                                                    papoSources);
956
0
            return true;
957
958
0
        default:
959
0
            break;
960
0
    }
961
0
    return false;
962
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*)
963
964
/************************************************************************/
965
/*                   OptimizedSumThroughLargerType()                    */
966
/************************************************************************/
967
968
namespace
969
{
970
template <typename Tsrc, typename Tdest, typename Enable = void>
971
struct TintermediateS
972
{
973
    using type = double;
974
};
975
976
template <typename Tsrc, typename Tdest>
977
struct TintermediateS<
978
    Tsrc, Tdest,
979
    std::enable_if_t<
980
        (std::is_same_v<Tsrc, uint8_t> || std::is_same_v<Tsrc, int16_t> ||
981
         std::is_same_v<Tsrc, uint16_t>) &&
982
            (std::is_same_v<Tdest, uint8_t> || std::is_same_v<Tdest, int16_t> ||
983
             std::is_same_v<Tdest, uint16_t>),
984
        bool>>
985
{
986
    using type = int32_t;
987
};
988
989
}  // namespace
990
991
template <typename Tsrc, typename Tdest>
992
static bool OptimizedSumThroughLargerType(double dfK, void *pOutBuffer,
993
                                          int nPixelSpace, int nLineSpace,
994
                                          int nXSize, int nYSize, int nSources,
995
                                          const void *const *papoSources)
996
0
{
997
0
    using Tintermediate = typename TintermediateS<Tsrc, Tdest>::type;
998
0
    const Tintermediate k = static_cast<Tintermediate>(dfK);
999
1000
0
    size_t ii = 0;
1001
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
1002
0
    {
1003
0
        GByte *CPL_RESTRICT pDest = static_cast<GByte *>(pOutBuffer) +
1004
0
                                    static_cast<GSpacing>(nLineSpace) * iLine;
1005
1006
0
        constexpr int UNROLLING = 4;
1007
0
        int iCol = 0;
1008
0
        for (; iCol < nXSize - (UNROLLING - 1);
1009
0
             iCol += UNROLLING, ii += UNROLLING)
1010
0
        {
1011
0
            Tintermediate aSum[4] = {k, k, k, k};
1012
1013
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
1014
0
            {
1015
0
                aSum[0] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 0];
1016
0
                aSum[1] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 1];
1017
0
                aSum[2] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 2];
1018
0
                aSum[3] += static_cast<const Tsrc *>(papoSources[iSrc])[ii + 3];
1019
0
            }
1020
1021
0
            GDALCopyWord(aSum[0], *reinterpret_cast<Tdest *>(pDest));
1022
0
            pDest += nPixelSpace;
1023
0
            GDALCopyWord(aSum[1], *reinterpret_cast<Tdest *>(pDest));
1024
0
            pDest += nPixelSpace;
1025
0
            GDALCopyWord(aSum[2], *reinterpret_cast<Tdest *>(pDest));
1026
0
            pDest += nPixelSpace;
1027
0
            GDALCopyWord(aSum[3], *reinterpret_cast<Tdest *>(pDest));
1028
0
            pDest += nPixelSpace;
1029
0
        }
1030
0
        for (; iCol < nXSize; ++iCol, ++ii, pDest += nPixelSpace)
1031
0
        {
1032
0
            Tintermediate sum = k;
1033
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
1034
0
            {
1035
0
                sum += static_cast<const Tsrc *>(papoSources[iSrc])[ii];
1036
0
            }
1037
1038
0
            auto pDst = reinterpret_cast<Tdest *>(pDest);
1039
0
            GDALCopyWord(sum, *pDst);
1040
0
        }
1041
0
    }
1042
0
    return true;
1043
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*)
1044
1045
/************************************************************************/
1046
/*                   OptimizedSumThroughLargerType()                    */
1047
/************************************************************************/
1048
1049
template <typename Tsrc>
1050
static bool OptimizedSumThroughLargerType(GDALDataType eBufType, double dfK,
1051
                                          void *pOutBuffer, int nPixelSpace,
1052
                                          int nLineSpace, int nXSize,
1053
                                          int nYSize, int nSources,
1054
                                          const void *const *papoSources)
1055
0
{
1056
0
    switch (eBufType)
1057
0
    {
1058
0
        case GDT_UInt8:
1059
0
            return OptimizedSumThroughLargerType<Tsrc, uint8_t>(
1060
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
1061
0
                nSources, papoSources);
1062
1063
0
        case GDT_UInt16:
1064
0
            return OptimizedSumThroughLargerType<Tsrc, uint16_t>(
1065
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
1066
0
                nSources, papoSources);
1067
1068
0
        case GDT_Int16:
1069
0
            return OptimizedSumThroughLargerType<Tsrc, int16_t>(
1070
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
1071
0
                nSources, papoSources);
1072
1073
0
        case GDT_Int32:
1074
0
            return OptimizedSumThroughLargerType<Tsrc, int32_t>(
1075
0
                dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize, nYSize,
1076
0
                nSources, papoSources);
1077
1078
        // Float32 and Float64 already covered by OptimizedSum() for packed case
1079
0
        default:
1080
0
            break;
1081
0
    }
1082
0
    return false;
1083
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*)
1084
1085
/************************************************************************/
1086
/*                   OptimizedSumThroughLargerType()                    */
1087
/************************************************************************/
1088
1089
static bool OptimizedSumThroughLargerType(GDALDataType eSrcType,
1090
                                          GDALDataType eBufType, double dfK,
1091
                                          void *pOutBuffer, int nPixelSpace,
1092
                                          int nLineSpace, int nXSize,
1093
                                          int nYSize, int nSources,
1094
                                          const void *const *papoSources)
1095
0
{
1096
0
    switch (eSrcType)
1097
0
    {
1098
0
        case GDT_UInt8:
1099
0
            return OptimizedSumThroughLargerType<uint8_t>(
1100
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
1101
0
                nYSize, nSources, papoSources);
1102
1103
0
        case GDT_UInt16:
1104
0
            return OptimizedSumThroughLargerType<uint16_t>(
1105
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
1106
0
                nYSize, nSources, papoSources);
1107
1108
0
        case GDT_Int16:
1109
0
            return OptimizedSumThroughLargerType<int16_t>(
1110
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
1111
0
                nYSize, nSources, papoSources);
1112
1113
0
        case GDT_Int32:
1114
0
            return OptimizedSumThroughLargerType<int32_t>(
1115
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
1116
0
                nYSize, nSources, papoSources);
1117
1118
0
        case GDT_Float32:
1119
0
            return OptimizedSumThroughLargerType<float>(
1120
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
1121
0
                nYSize, nSources, papoSources);
1122
1123
0
        case GDT_Float64:
1124
0
            return OptimizedSumThroughLargerType<double>(
1125
0
                eBufType, dfK, pOutBuffer, nPixelSpace, nLineSpace, nXSize,
1126
0
                nYSize, nSources, papoSources);
1127
1128
0
        default:
1129
0
            break;
1130
0
    }
1131
1132
0
    return false;
1133
0
}
1134
1135
/************************************************************************/
1136
/*                            SumPixelFunc()                            */
1137
/************************************************************************/
1138
1139
static const char pszSumPixelFuncMetadata[] =
1140
    "<PixelFunctionArgumentsList>"
1141
    "   <Argument name='k' description='Optional constant term' type='double' "
1142
    "default='0.0' />"
1143
    "   <Argument name='propagateNoData' description='Whether the output value "
1144
    "should be NoData as as soon as one source is NoData' type='boolean' "
1145
    "default='false' />"
1146
    "   <Argument type='builtin' value='NoData' optional='true' />"
1147
    "</PixelFunctionArgumentsList>";
1148
1149
static CPLErr SumPixelFunc(void **papoSources, int nSources, void *pData,
1150
                           int nXSize, int nYSize, GDALDataType eSrcType,
1151
                           GDALDataType eBufType, int nPixelSpace,
1152
                           int nLineSpace, CSLConstList papszArgs)
1153
0
{
1154
    /* ---- Init ---- */
1155
0
    if (nSources < 1)
1156
0
    {
1157
0
        CPLError(CE_Failure, CPLE_AppDefined,
1158
0
                 "sum requires at least one source");
1159
0
        return CE_Failure;
1160
0
    }
1161
1162
0
    double dfK = 0.0;
1163
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
1164
0
        return CE_Failure;
1165
1166
0
    double dfNoData{0};
1167
0
    bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1168
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1169
0
        return CE_Failure;
1170
1171
0
    const bool bPropagateNoData = CPLTestBool(
1172
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
1173
1174
0
    if (dfNoData == 0 && !bPropagateNoData)
1175
0
        bHasNoData = false;
1176
1177
    /* ---- Set pixels ---- */
1178
0
    if (GDALDataTypeIsComplex(eSrcType))
1179
0
    {
1180
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1181
1182
        /* ---- Set pixels ---- */
1183
0
        size_t ii = 0;
1184
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1185
0
        {
1186
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1187
0
            {
1188
0
                double adfSum[2] = {dfK, 0.0};
1189
1190
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
1191
0
                {
1192
0
                    const void *const pReal = papoSources[iSrc];
1193
0
                    const void *const pImag =
1194
0
                        static_cast<const GByte *>(pReal) + nOffset;
1195
1196
                    // Source raster pixels may be obtained with GetSrcVal
1197
                    // macro.
1198
0
                    adfSum[0] += GetSrcVal(pReal, eSrcType, ii);
1199
0
                    adfSum[1] += GetSrcVal(pImag, eSrcType, ii);
1200
0
                }
1201
1202
0
                GDALCopyWords(adfSum, GDT_CFloat64, 0,
1203
0
                              static_cast<GByte *>(pData) +
1204
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1205
0
                                  iCol * nPixelSpace,
1206
0
                              eBufType, nPixelSpace, 1);
1207
0
            }
1208
0
        }
1209
0
    }
1210
0
    else
1211
0
    {
1212
        /* ---- Set pixels ---- */
1213
0
        bool bGeneralCase = true;
1214
0
        if (dfNoData == 0 && !bPropagateNoData)
1215
0
        {
1216
0
#ifdef USE_SSE2
1217
0
            if (eBufType == GDT_UInt8 && nPixelSpace == sizeof(uint8_t) &&
1218
0
                eSrcType == GDT_UInt8 &&
1219
0
                dfK >= std::numeric_limits<uint8_t>::min() &&
1220
0
                dfK <= std::numeric_limits<uint8_t>::max() &&
1221
0
                static_cast<int>(dfK) == dfK)
1222
0
            {
1223
0
                bGeneralCase = false;
1224
1225
0
                struct SSEWrapper
1226
0
                {
1227
0
                    inline static __m128i Set1(int8_t x)
1228
0
                    {
1229
0
                        return _mm_set1_epi8(x);
1230
0
                    }
1231
1232
0
                    inline static __m128i AddSaturate(__m128i x, __m128i y)
1233
0
                    {
1234
0
                        return _mm_adds_epu8(x, y);
1235
0
                    }
1236
0
                };
1237
1238
0
                OptimizedSumSameType_SSE2<uint8_t, int8_t, uint32_t,
1239
0
                                          SSEWrapper>(dfK, pData, nLineSpace,
1240
0
                                                      nXSize, nYSize, nSources,
1241
0
                                                      papoSources);
1242
0
            }
1243
0
            else if (eBufType == GDT_UInt16 &&
1244
0
                     nPixelSpace == sizeof(uint16_t) &&
1245
0
                     eSrcType == GDT_UInt16 &&
1246
0
                     dfK >= std::numeric_limits<uint16_t>::min() &&
1247
0
                     dfK <= std::numeric_limits<uint16_t>::max() &&
1248
0
                     static_cast<int>(dfK) == dfK)
1249
0
            {
1250
0
                bGeneralCase = false;
1251
1252
0
                struct SSEWrapper
1253
0
                {
1254
0
                    inline static __m128i Set1(int16_t x)
1255
0
                    {
1256
0
                        return _mm_set1_epi16(x);
1257
0
                    }
1258
1259
0
                    inline static __m128i AddSaturate(__m128i x, __m128i y)
1260
0
                    {
1261
0
                        return _mm_adds_epu16(x, y);
1262
0
                    }
1263
0
                };
1264
1265
0
                OptimizedSumSameType_SSE2<uint16_t, int16_t, uint32_t,
1266
0
                                          SSEWrapper>(dfK, pData, nLineSpace,
1267
0
                                                      nXSize, nYSize, nSources,
1268
0
                                                      papoSources);
1269
0
            }
1270
0
            else
1271
0
#endif
1272
0
                if (eBufType == GDT_Float32 && nPixelSpace == sizeof(float))
1273
0
            {
1274
0
                bGeneralCase = !OptimizedSumPackedOutput<float>(
1275
0
                    eSrcType, dfK, pData, nLineSpace, nXSize, nYSize, nSources,
1276
0
                    papoSources);
1277
0
            }
1278
0
            else if (eBufType == GDT_Float64 && nPixelSpace == sizeof(double))
1279
0
            {
1280
0
                bGeneralCase = !OptimizedSumPackedOutput<double>(
1281
0
                    eSrcType, dfK, pData, nLineSpace, nXSize, nYSize, nSources,
1282
0
                    papoSources);
1283
0
            }
1284
0
            else if (
1285
0
                dfK >= 0 && dfK <= INT_MAX && eBufType == GDT_Int32 &&
1286
0
                nPixelSpace == sizeof(int32_t) && eSrcType == GDT_UInt8 &&
1287
                // Limitation to avoid overflow of int32 if all source values are at the max of their data type
1288
0
                nSources <=
1289
0
                    (INT_MAX - dfK) / std::numeric_limits<uint8_t>::max())
1290
0
            {
1291
0
                bGeneralCase = false;
1292
0
                OptimizedSumPackedOutput<uint8_t, int32_t>(
1293
0
                    dfK, pData, nLineSpace, nXSize, nYSize, nSources,
1294
0
                    papoSources);
1295
0
            }
1296
1297
0
            if (bGeneralCase && dfK >= 0 && dfK <= INT_MAX &&
1298
0
                nSources <=
1299
0
                    (INT_MAX - dfK) / std::numeric_limits<uint16_t>::max())
1300
0
            {
1301
0
                bGeneralCase = !OptimizedSumThroughLargerType(
1302
0
                    eSrcType, eBufType, dfK, pData, nPixelSpace, nLineSpace,
1303
0
                    nXSize, nYSize, nSources, papoSources);
1304
0
            }
1305
0
        }
1306
1307
0
        if (bGeneralCase)
1308
0
        {
1309
0
            size_t ii = 0;
1310
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
1311
0
            {
1312
0
                for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1313
0
                {
1314
0
                    double dfSum = dfK;
1315
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
1316
0
                    {
1317
0
                        const double dfVal =
1318
0
                            GetSrcVal(papoSources[iSrc], eSrcType, ii);
1319
1320
0
                        if (bHasNoData && IsNoData(dfVal, dfNoData))
1321
0
                        {
1322
0
                            if (bPropagateNoData)
1323
0
                            {
1324
0
                                dfSum = dfNoData;
1325
0
                                break;
1326
0
                            }
1327
0
                        }
1328
0
                        else
1329
0
                        {
1330
0
                            dfSum += dfVal;
1331
0
                        }
1332
0
                    }
1333
1334
0
                    GDALCopyWords(&dfSum, GDT_Float64, 0,
1335
0
                                  static_cast<GByte *>(pData) +
1336
0
                                      static_cast<GSpacing>(nLineSpace) *
1337
0
                                          iLine +
1338
0
                                      iCol * nPixelSpace,
1339
0
                                  eBufType, nPixelSpace, 1);
1340
0
                }
1341
0
            }
1342
0
        }
1343
0
    }
1344
1345
    /* ---- Return success ---- */
1346
0
    return CE_None;
1347
0
} /* SumPixelFunc */
1348
1349
static const char pszDiffPixelFuncMetadata[] =
1350
    "<PixelFunctionArgumentsList>"
1351
    "   <Argument type='builtin' value='NoData' optional='true' />"
1352
    "</PixelFunctionArgumentsList>";
1353
1354
static CPLErr DiffPixelFunc(void **papoSources, int nSources, void *pData,
1355
                            int nXSize, int nYSize, GDALDataType eSrcType,
1356
                            GDALDataType eBufType, int nPixelSpace,
1357
                            int nLineSpace, CSLConstList papszArgs)
1358
0
{
1359
    /* ---- Init ---- */
1360
0
    if (nSources != 2)
1361
0
        return CE_Failure;
1362
1363
0
    double dfNoData{0};
1364
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1365
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1366
0
        return CE_Failure;
1367
1368
0
    if (GDALDataTypeIsComplex(eSrcType))
1369
0
    {
1370
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1371
0
        const void *const pReal0 = papoSources[0];
1372
0
        const void *const pImag0 =
1373
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1374
0
        const void *const pReal1 = papoSources[1];
1375
0
        const void *const pImag1 =
1376
0
            static_cast<GByte *>(papoSources[1]) + nOffset;
1377
1378
        /* ---- Set pixels ---- */
1379
0
        size_t ii = 0;
1380
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1381
0
        {
1382
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1383
0
            {
1384
                // Source raster pixels may be obtained with GetSrcVal macro.
1385
0
                double adfPixVal[2] = {GetSrcVal(pReal0, eSrcType, ii) -
1386
0
                                           GetSrcVal(pReal1, eSrcType, ii),
1387
0
                                       GetSrcVal(pImag0, eSrcType, ii) -
1388
0
                                           GetSrcVal(pImag1, eSrcType, ii)};
1389
1390
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1391
0
                              static_cast<GByte *>(pData) +
1392
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1393
0
                                  iCol * nPixelSpace,
1394
0
                              eBufType, nPixelSpace, 1);
1395
0
            }
1396
0
        }
1397
0
    }
1398
0
    else
1399
0
    {
1400
        /* ---- Set pixels ---- */
1401
0
        size_t ii = 0;
1402
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1403
0
        {
1404
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1405
0
            {
1406
0
                const double dfA = GetSrcVal(papoSources[0], eSrcType, ii);
1407
0
                const double dfB = GetSrcVal(papoSources[1], eSrcType, ii);
1408
1409
0
                const double dfPixVal =
1410
0
                    bHasNoData &&
1411
0
                            (IsNoData(dfA, dfNoData) || IsNoData(dfB, dfNoData))
1412
0
                        ? dfNoData
1413
0
                        : dfA - dfB;
1414
1415
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1416
0
                              static_cast<GByte *>(pData) +
1417
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1418
0
                                  iCol * nPixelSpace,
1419
0
                              eBufType, nPixelSpace, 1);
1420
0
            }
1421
0
        }
1422
0
    }
1423
1424
    /* ---- Return success ---- */
1425
0
    return CE_None;
1426
0
}  // DiffPixelFunc
1427
1428
static const char pszMulPixelFuncMetadata[] =
1429
    "<PixelFunctionArgumentsList>"
1430
    "   <Argument name='k' description='Optional constant factor' "
1431
    "type='double' default='1.0' />"
1432
    "   <Argument name='propagateNoData' description='Whether the output value "
1433
    "should be NoData as as soon as one source is NoData' type='boolean' "
1434
    "default='false' />"
1435
    "   <Argument type='builtin' value='NoData' optional='true' />"
1436
    "</PixelFunctionArgumentsList>";
1437
1438
static CPLErr MulPixelFunc(void **papoSources, int nSources, void *pData,
1439
                           int nXSize, int nYSize, GDALDataType eSrcType,
1440
                           GDALDataType eBufType, int nPixelSpace,
1441
                           int nLineSpace, CSLConstList papszArgs)
1442
0
{
1443
    /* ---- Init ---- */
1444
0
    if (nSources < 2 && CSLFetchNameValue(papszArgs, "k") == nullptr)
1445
0
    {
1446
0
        CPLError(CE_Failure, CPLE_AppDefined,
1447
0
                 "mul requires at least two sources or a specified constant k");
1448
0
        return CE_Failure;
1449
0
    }
1450
1451
0
    double dfK = 1.0;
1452
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
1453
0
        return CE_Failure;
1454
1455
0
    double dfNoData{0};
1456
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1457
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1458
0
        return CE_Failure;
1459
1460
0
    const bool bPropagateNoData = CPLTestBool(
1461
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
1462
1463
    /* ---- Set pixels ---- */
1464
0
    if (GDALDataTypeIsComplex(eSrcType))
1465
0
    {
1466
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1467
1468
        /* ---- Set pixels ---- */
1469
0
        size_t ii = 0;
1470
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1471
0
        {
1472
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1473
0
            {
1474
0
                double adfPixVal[2] = {dfK, 0.0};
1475
1476
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
1477
0
                {
1478
0
                    const void *const pReal = papoSources[iSrc];
1479
0
                    const void *const pImag =
1480
0
                        static_cast<const GByte *>(pReal) + nOffset;
1481
1482
0
                    const double dfOldR = adfPixVal[0];
1483
0
                    const double dfOldI = adfPixVal[1];
1484
1485
                    // Source raster pixels may be obtained with GetSrcVal
1486
                    // macro.
1487
0
                    const double dfNewR = GetSrcVal(pReal, eSrcType, ii);
1488
0
                    const double dfNewI = GetSrcVal(pImag, eSrcType, ii);
1489
1490
0
                    adfPixVal[0] = dfOldR * dfNewR - dfOldI * dfNewI;
1491
0
                    adfPixVal[1] = dfOldR * dfNewI + dfOldI * dfNewR;
1492
0
                }
1493
1494
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1495
0
                              static_cast<GByte *>(pData) +
1496
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1497
0
                                  iCol * nPixelSpace,
1498
0
                              eBufType, nPixelSpace, 1);
1499
0
            }
1500
0
        }
1501
0
    }
1502
0
    else
1503
0
    {
1504
        /* ---- Set pixels ---- */
1505
0
        size_t ii = 0;
1506
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1507
0
        {
1508
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1509
0
            {
1510
0
                double dfPixVal = dfK;  // Not complex.
1511
1512
0
                for (int iSrc = 0; iSrc < nSources; ++iSrc)
1513
0
                {
1514
0
                    const double dfVal =
1515
0
                        GetSrcVal(papoSources[iSrc], eSrcType, ii);
1516
1517
0
                    if (bHasNoData && IsNoData(dfVal, dfNoData))
1518
0
                    {
1519
0
                        if (bPropagateNoData)
1520
0
                        {
1521
0
                            dfPixVal = dfNoData;
1522
0
                            break;
1523
0
                        }
1524
0
                    }
1525
0
                    else
1526
0
                    {
1527
0
                        dfPixVal *= dfVal;
1528
0
                    }
1529
0
                }
1530
1531
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1532
0
                              static_cast<GByte *>(pData) +
1533
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1534
0
                                  iCol * nPixelSpace,
1535
0
                              eBufType, nPixelSpace, 1);
1536
0
            }
1537
0
        }
1538
0
    }
1539
1540
    /* ---- Return success ---- */
1541
0
    return CE_None;
1542
0
}  // MulPixelFunc
1543
1544
static const char pszDivPixelFuncMetadata[] =
1545
    "<PixelFunctionArgumentsList>"
1546
    "   "
1547
    "<Argument type='builtin' value='NoData' optional='true' />"
1548
    "</PixelFunctionArgumentsList>";
1549
1550
static CPLErr DivPixelFunc(void **papoSources, int nSources, void *pData,
1551
                           int nXSize, int nYSize, GDALDataType eSrcType,
1552
                           GDALDataType eBufType, int nPixelSpace,
1553
                           int nLineSpace, CSLConstList papszArgs)
1554
0
{
1555
    /* ---- Init ---- */
1556
0
    if (nSources != 2)
1557
0
        return CE_Failure;
1558
1559
0
    double dfNoData{0};
1560
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1561
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1562
0
        return CE_Failure;
1563
1564
    /* ---- Set pixels ---- */
1565
0
    if (GDALDataTypeIsComplex(eSrcType))
1566
0
    {
1567
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1568
0
        const void *const pReal0 = papoSources[0];
1569
0
        const void *const pImag0 =
1570
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1571
0
        const void *const pReal1 = papoSources[1];
1572
0
        const void *const pImag1 =
1573
0
            static_cast<GByte *>(papoSources[1]) + nOffset;
1574
1575
        /* ---- Set pixels ---- */
1576
0
        size_t ii = 0;
1577
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1578
0
        {
1579
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1580
0
            {
1581
                // Source raster pixels may be obtained with GetSrcVal macro.
1582
0
                const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);
1583
0
                const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);
1584
0
                const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);
1585
0
                const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);
1586
0
                const double dfAux = dfReal1 * dfReal1 + dfImag1 * dfImag1;
1587
1588
0
                const double adfPixVal[2] = {
1589
0
                    dfAux == 0
1590
0
                        ? std::numeric_limits<double>::infinity()
1591
0
                        : dfReal0 * dfReal1 / dfAux + dfImag0 * dfImag1 / dfAux,
1592
0
                    dfAux == 0 ? std::numeric_limits<double>::infinity()
1593
0
                               : dfReal1 / dfAux * dfImag0 -
1594
0
                                     dfReal0 * dfImag1 / dfAux};
1595
1596
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1597
0
                              static_cast<GByte *>(pData) +
1598
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1599
0
                                  iCol * nPixelSpace,
1600
0
                              eBufType, nPixelSpace, 1);
1601
0
            }
1602
0
        }
1603
0
    }
1604
0
    else
1605
0
    {
1606
        /* ---- Set pixels ---- */
1607
0
        size_t ii = 0;
1608
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1609
0
        {
1610
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1611
0
            {
1612
0
                const double dfNum = GetSrcVal(papoSources[0], eSrcType, ii);
1613
0
                const double dfDenom = GetSrcVal(papoSources[1], eSrcType, ii);
1614
1615
0
                double dfPixVal = dfNoData;
1616
0
                if (!bHasNoData || (!IsNoData(dfNum, dfNoData) &&
1617
0
                                    !IsNoData(dfDenom, dfNoData)))
1618
0
                {
1619
                    // coverity[divide_by_zero]
1620
0
                    dfPixVal =
1621
0
                        dfDenom == 0
1622
0
                            ? std::numeric_limits<double>::infinity()
1623
0
                            : dfNum /
1624
#ifdef __COVERITY__
1625
                                  (dfDenom + std::numeric_limits<double>::min())
1626
#else
1627
0
                                  dfDenom
1628
0
#endif
1629
0
                        ;
1630
0
                }
1631
1632
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1633
0
                              static_cast<GByte *>(pData) +
1634
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1635
0
                                  iCol * nPixelSpace,
1636
0
                              eBufType, nPixelSpace, 1);
1637
0
            }
1638
0
        }
1639
0
    }
1640
1641
    /* ---- Return success ---- */
1642
0
    return CE_None;
1643
0
}  // DivPixelFunc
1644
1645
static CPLErr CMulPixelFunc(void **papoSources, int nSources, void *pData,
1646
                            int nXSize, int nYSize, GDALDataType eSrcType,
1647
                            GDALDataType eBufType, int nPixelSpace,
1648
                            int nLineSpace)
1649
0
{
1650
    /* ---- Init ---- */
1651
0
    if (nSources != 2)
1652
0
        return CE_Failure;
1653
1654
    /* ---- Set pixels ---- */
1655
0
    if (GDALDataTypeIsComplex(eSrcType))
1656
0
    {
1657
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1658
0
        const void *const pReal0 = papoSources[0];
1659
0
        const void *const pImag0 =
1660
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1661
0
        const void *const pReal1 = papoSources[1];
1662
0
        const void *const pImag1 =
1663
0
            static_cast<GByte *>(papoSources[1]) + nOffset;
1664
1665
0
        size_t ii = 0;
1666
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1667
0
        {
1668
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1669
0
            {
1670
                // Source raster pixels may be obtained with GetSrcVal macro.
1671
0
                const double dfReal0 = GetSrcVal(pReal0, eSrcType, ii);
1672
0
                const double dfReal1 = GetSrcVal(pReal1, eSrcType, ii);
1673
0
                const double dfImag0 = GetSrcVal(pImag0, eSrcType, ii);
1674
0
                const double dfImag1 = GetSrcVal(pImag1, eSrcType, ii);
1675
0
                const double adfPixVal[2] = {
1676
0
                    dfReal0 * dfReal1 + dfImag0 * dfImag1,
1677
0
                    dfReal1 * dfImag0 - dfReal0 * dfImag1};
1678
1679
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1680
0
                              static_cast<GByte *>(pData) +
1681
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1682
0
                                  iCol * nPixelSpace,
1683
0
                              eBufType, nPixelSpace, 1);
1684
0
            }
1685
0
        }
1686
0
    }
1687
0
    else
1688
0
    {
1689
0
        size_t ii = 0;
1690
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1691
0
        {
1692
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1693
0
            {
1694
                // Source raster pixels may be obtained with GetSrcVal macro.
1695
                // Not complex.
1696
0
                const double adfPixVal[2] = {
1697
0
                    GetSrcVal(papoSources[0], eSrcType, ii) *
1698
0
                        GetSrcVal(papoSources[1], eSrcType, ii),
1699
0
                    0.0};
1700
1701
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1702
0
                              static_cast<GByte *>(pData) +
1703
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1704
0
                                  iCol * nPixelSpace,
1705
0
                              eBufType, nPixelSpace, 1);
1706
0
            }
1707
0
        }
1708
0
    }
1709
1710
    /* ---- Return success ---- */
1711
0
    return CE_None;
1712
0
}  // CMulPixelFunc
1713
1714
static const char pszInvPixelFuncMetadata[] =
1715
    "<PixelFunctionArgumentsList>"
1716
    "   <Argument name='k' description='Optional constant factor' "
1717
    "type='double' default='1.0' />"
1718
    "   "
1719
    "<Argument type='builtin' value='NoData' optional='true' />"
1720
    "</PixelFunctionArgumentsList>";
1721
1722
static CPLErr InvPixelFunc(void **papoSources, int nSources, void *pData,
1723
                           int nXSize, int nYSize, GDALDataType eSrcType,
1724
                           GDALDataType eBufType, int nPixelSpace,
1725
                           int nLineSpace, CSLConstList papszArgs)
1726
0
{
1727
    /* ---- Init ---- */
1728
0
    if (nSources != 1)
1729
0
        return CE_Failure;
1730
1731
0
    double dfK = 1.0;
1732
0
    if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
1733
0
        return CE_Failure;
1734
1735
0
    double dfNoData{0};
1736
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1737
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1738
0
        return CE_Failure;
1739
1740
    /* ---- Set pixels ---- */
1741
0
    if (GDALDataTypeIsComplex(eSrcType))
1742
0
    {
1743
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1744
0
        const void *const pReal = papoSources[0];
1745
0
        const void *const pImag =
1746
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1747
1748
0
        size_t ii = 0;
1749
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1750
0
        {
1751
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1752
0
            {
1753
                // Source raster pixels may be obtained with GetSrcVal macro.
1754
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
1755
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
1756
0
                const double dfAux = dfReal * dfReal + dfImag * dfImag;
1757
0
                const double adfPixVal[2] = {
1758
0
                    dfAux == 0 ? std::numeric_limits<double>::infinity()
1759
0
                               : dfK * dfReal / dfAux,
1760
0
                    dfAux == 0 ? std::numeric_limits<double>::infinity()
1761
0
                               : -dfK * dfImag / dfAux};
1762
1763
0
                GDALCopyWords(adfPixVal, GDT_CFloat64, 0,
1764
0
                              static_cast<GByte *>(pData) +
1765
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1766
0
                                  iCol * nPixelSpace,
1767
0
                              eBufType, nPixelSpace, 1);
1768
0
            }
1769
0
        }
1770
0
    }
1771
0
    else
1772
0
    {
1773
        /* ---- Set pixels ---- */
1774
0
        size_t ii = 0;
1775
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1776
0
        {
1777
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1778
0
            {
1779
                // Source raster pixels may be obtained with GetSrcVal macro.
1780
                // Not complex.
1781
0
                const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
1782
0
                double dfPixVal = dfNoData;
1783
1784
0
                if (!bHasNoData || !IsNoData(dfVal, dfNoData))
1785
0
                {
1786
0
                    dfPixVal =
1787
0
                        dfVal == 0
1788
0
                            ? std::numeric_limits<double>::infinity()
1789
0
                            : dfK /
1790
#ifdef __COVERITY__
1791
                                  (dfVal + std::numeric_limits<double>::min())
1792
#else
1793
0
                                  dfVal
1794
0
#endif
1795
0
                        ;
1796
0
                }
1797
1798
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1799
0
                              static_cast<GByte *>(pData) +
1800
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1801
0
                                  iCol * nPixelSpace,
1802
0
                              eBufType, nPixelSpace, 1);
1803
0
            }
1804
0
        }
1805
0
    }
1806
1807
    /* ---- Return success ---- */
1808
0
    return CE_None;
1809
0
}  // InvPixelFunc
1810
1811
static CPLErr IntensityPixelFunc(void **papoSources, int nSources, void *pData,
1812
                                 int nXSize, int nYSize, GDALDataType eSrcType,
1813
                                 GDALDataType eBufType, int nPixelSpace,
1814
                                 int nLineSpace)
1815
0
{
1816
    /* ---- Init ---- */
1817
0
    if (nSources != 1)
1818
0
        return CE_Failure;
1819
1820
0
    if (GDALDataTypeIsComplex(eSrcType))
1821
0
    {
1822
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1823
0
        const void *const pReal = papoSources[0];
1824
0
        const void *const pImag =
1825
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1826
1827
        /* ---- Set pixels ---- */
1828
0
        size_t ii = 0;
1829
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1830
0
        {
1831
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1832
0
            {
1833
                // Source raster pixels may be obtained with GetSrcVal macro.
1834
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
1835
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
1836
1837
0
                const double dfPixVal = dfReal * dfReal + dfImag * dfImag;
1838
1839
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1840
0
                              static_cast<GByte *>(pData) +
1841
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1842
0
                                  iCol * nPixelSpace,
1843
0
                              eBufType, nPixelSpace, 1);
1844
0
            }
1845
0
        }
1846
0
    }
1847
0
    else
1848
0
    {
1849
        /* ---- Set pixels ---- */
1850
0
        size_t ii = 0;
1851
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1852
0
        {
1853
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1854
0
            {
1855
                // Source raster pixels may be obtained with GetSrcVal macro.
1856
0
                double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
1857
0
                dfPixVal *= dfPixVal;
1858
1859
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1860
0
                              static_cast<GByte *>(pData) +
1861
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1862
0
                                  iCol * nPixelSpace,
1863
0
                              eBufType, nPixelSpace, 1);
1864
0
            }
1865
0
        }
1866
0
    }
1867
1868
    /* ---- Return success ---- */
1869
0
    return CE_None;
1870
0
}  // IntensityPixelFunc
1871
1872
static const char pszSqrtPixelFuncMetadata[] =
1873
    "<PixelFunctionArgumentsList>"
1874
    "   <Argument type='builtin' value='NoData' optional='true'/>"
1875
    "</PixelFunctionArgumentsList>";
1876
1877
static CPLErr SqrtPixelFunc(void **papoSources, int nSources, void *pData,
1878
                            int nXSize, int nYSize, GDALDataType eSrcType,
1879
                            GDALDataType eBufType, int nPixelSpace,
1880
                            int nLineSpace, CSLConstList papszArgs)
1881
0
{
1882
    /* ---- Init ---- */
1883
0
    if (nSources != 1)
1884
0
        return CE_Failure;
1885
0
    if (GDALDataTypeIsComplex(eSrcType))
1886
0
        return CE_Failure;
1887
1888
0
    double dfNoData{0};
1889
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1890
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1891
0
        return CE_Failure;
1892
1893
    /* ---- Set pixels ---- */
1894
0
    size_t ii = 0;
1895
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
1896
0
    {
1897
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1898
0
        {
1899
            // Source raster pixels may be obtained with GetSrcVal macro.
1900
0
            double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
1901
1902
0
            if (bHasNoData && IsNoData(dfPixVal, dfNoData))
1903
0
            {
1904
0
                dfPixVal = dfNoData;
1905
0
            }
1906
0
            else
1907
0
            {
1908
0
                dfPixVal = std::sqrt(dfPixVal);
1909
0
            }
1910
1911
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1912
0
                          static_cast<GByte *>(pData) +
1913
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
1914
0
                              iCol * nPixelSpace,
1915
0
                          eBufType, nPixelSpace, 1);
1916
0
        }
1917
0
    }
1918
1919
    /* ---- Return success ---- */
1920
0
    return CE_None;
1921
0
}  // SqrtPixelFunc
1922
1923
static CPLErr Log10PixelFuncHelper(void **papoSources, int nSources,
1924
                                   void *pData, int nXSize, int nYSize,
1925
                                   GDALDataType eSrcType, GDALDataType eBufType,
1926
                                   int nPixelSpace, int nLineSpace,
1927
                                   CSLConstList papszArgs, double fact)
1928
0
{
1929
    /* ---- Init ---- */
1930
0
    if (nSources != 1)
1931
0
        return CE_Failure;
1932
1933
0
    double dfNoData{0};
1934
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
1935
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
1936
0
        return CE_Failure;
1937
1938
0
    if (GDALDataTypeIsComplex(eSrcType))
1939
0
    {
1940
        // Complex input datatype.
1941
0
        const int nOffset = GDALGetDataTypeSizeBytes(eSrcType) / 2;
1942
0
        const void *const pReal = papoSources[0];
1943
0
        const void *const pImag =
1944
0
            static_cast<GByte *>(papoSources[0]) + nOffset;
1945
1946
        /* We should compute fact * log10( sqrt( dfReal * dfReal + dfImag *
1947
         * dfImag ) ) */
1948
        /* Given that log10(sqrt(x)) = 0.5 * log10(x) */
1949
        /* we can remove the sqrt() by multiplying fact by 0.5 */
1950
0
        fact *= 0.5;
1951
1952
        /* ---- Set pixels ---- */
1953
0
        size_t ii = 0;
1954
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1955
0
        {
1956
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1957
0
            {
1958
                // Source raster pixels may be obtained with GetSrcVal macro.
1959
0
                const double dfReal = GetSrcVal(pReal, eSrcType, ii);
1960
0
                const double dfImag = GetSrcVal(pImag, eSrcType, ii);
1961
1962
0
                const double dfPixVal =
1963
0
                    fact * log10(dfReal * dfReal + dfImag * dfImag);
1964
1965
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1966
0
                              static_cast<GByte *>(pData) +
1967
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1968
0
                                  iCol * nPixelSpace,
1969
0
                              eBufType, nPixelSpace, 1);
1970
0
            }
1971
0
        }
1972
0
    }
1973
0
    else
1974
0
    {
1975
        /* ---- Set pixels ---- */
1976
0
        size_t ii = 0;
1977
0
        for (int iLine = 0; iLine < nYSize; ++iLine)
1978
0
        {
1979
0
            for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
1980
0
            {
1981
                // Source raster pixels may be obtained with GetSrcVal macro.
1982
0
                const double dfSrcVal = GetSrcVal(papoSources[0], eSrcType, ii);
1983
0
                const double dfPixVal =
1984
0
                    bHasNoData && IsNoData(dfSrcVal, dfNoData)
1985
0
                        ? dfNoData
1986
0
                        : fact * std::log10(std::abs(dfSrcVal));
1987
1988
0
                GDALCopyWords(&dfPixVal, GDT_Float64, 0,
1989
0
                              static_cast<GByte *>(pData) +
1990
0
                                  static_cast<GSpacing>(nLineSpace) * iLine +
1991
0
                                  iCol * nPixelSpace,
1992
0
                              eBufType, nPixelSpace, 1);
1993
0
            }
1994
0
        }
1995
0
    }
1996
1997
    /* ---- Return success ---- */
1998
0
    return CE_None;
1999
0
}  // Log10PixelFuncHelper
2000
2001
static const char pszLog10PixelFuncMetadata[] =
2002
    "<PixelFunctionArgumentsList>"
2003
    "   <Argument type='builtin' value='NoData' optional='true'/>"
2004
    "</PixelFunctionArgumentsList>";
2005
2006
static CPLErr Log10PixelFunc(void **papoSources, int nSources, void *pData,
2007
                             int nXSize, int nYSize, GDALDataType eSrcType,
2008
                             GDALDataType eBufType, int nPixelSpace,
2009
                             int nLineSpace, CSLConstList papszArgs)
2010
0
{
2011
0
    return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
2012
0
                                eSrcType, eBufType, nPixelSpace, nLineSpace,
2013
0
                                papszArgs, 1.0);
2014
0
}  // Log10PixelFunc
2015
2016
static const char pszDBPixelFuncMetadata[] =
2017
    "<PixelFunctionArgumentsList>"
2018
    "   <Argument name='fact' description='Factor' type='double' "
2019
    "default='20.0' />"
2020
    "   <Argument type='builtin' value='NoData' optional='true' />"
2021
    "</PixelFunctionArgumentsList>";
2022
2023
static CPLErr DBPixelFunc(void **papoSources, int nSources, void *pData,
2024
                          int nXSize, int nYSize, GDALDataType eSrcType,
2025
                          GDALDataType eBufType, int nPixelSpace,
2026
                          int nLineSpace, CSLConstList papszArgs)
2027
0
{
2028
0
    double dfFact = 20.;
2029
0
    if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)
2030
0
        return CE_Failure;
2031
2032
0
    return Log10PixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
2033
0
                                eSrcType, eBufType, nPixelSpace, nLineSpace,
2034
0
                                papszArgs, dfFact);
2035
0
}  // DBPixelFunc
2036
2037
static CPLErr ExpPixelFuncHelper(void **papoSources, int nSources, void *pData,
2038
                                 int nXSize, int nYSize, GDALDataType eSrcType,
2039
                                 GDALDataType eBufType, int nPixelSpace,
2040
                                 int nLineSpace, CSLConstList papszArgs,
2041
                                 double base, double fact)
2042
0
{
2043
    /* ---- Init ---- */
2044
0
    if (nSources != 1)
2045
0
        return CE_Failure;
2046
0
    if (GDALDataTypeIsComplex(eSrcType))
2047
0
        return CE_Failure;
2048
2049
0
    double dfNoData{0};
2050
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2051
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2052
0
        return CE_Failure;
2053
2054
    /* ---- Set pixels ---- */
2055
0
    size_t ii = 0;
2056
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2057
0
    {
2058
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2059
0
        {
2060
            // Source raster pixels may be obtained with GetSrcVal macro.
2061
0
            const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
2062
0
            const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
2063
0
                                        ? dfNoData
2064
0
                                        : pow(base, dfVal * fact);
2065
2066
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2067
0
                          static_cast<GByte *>(pData) +
2068
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2069
0
                              iCol * nPixelSpace,
2070
0
                          eBufType, nPixelSpace, 1);
2071
0
        }
2072
0
    }
2073
2074
    /* ---- Return success ---- */
2075
0
    return CE_None;
2076
0
}  // ExpPixelFuncHelper
2077
2078
static const char pszExpPixelFuncMetadata[] =
2079
    "<PixelFunctionArgumentsList>"
2080
    "   <Argument name='base' description='Base' type='double' "
2081
    "default='2.7182818284590452353602874713526624' />"
2082
    "   <Argument name='fact' description='Factor' type='double' default='1' />"
2083
    "   <Argument type='builtin' value='NoData' optional='true' />"
2084
    "</PixelFunctionArgumentsList>";
2085
2086
static CPLErr ExpPixelFunc(void **papoSources, int nSources, void *pData,
2087
                           int nXSize, int nYSize, GDALDataType eSrcType,
2088
                           GDALDataType eBufType, int nPixelSpace,
2089
                           int nLineSpace, CSLConstList papszArgs)
2090
0
{
2091
0
    double dfBase = 2.7182818284590452353602874713526624;
2092
0
    double dfFact = 1.;
2093
2094
0
    if (FetchDoubleArg(papszArgs, "base", &dfBase, &dfBase) != CE_None)
2095
0
        return CE_Failure;
2096
2097
0
    if (FetchDoubleArg(papszArgs, "fact", &dfFact, &dfFact) != CE_None)
2098
0
        return CE_Failure;
2099
2100
0
    return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
2101
0
                              eSrcType, eBufType, nPixelSpace, nLineSpace,
2102
0
                              papszArgs, dfBase, dfFact);
2103
0
}  // ExpPixelFunc
2104
2105
static CPLErr dB2AmpPixelFunc(void **papoSources, int nSources, void *pData,
2106
                              int nXSize, int nYSize, GDALDataType eSrcType,
2107
                              GDALDataType eBufType, int nPixelSpace,
2108
                              int nLineSpace)
2109
0
{
2110
0
    return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
2111
0
                              eSrcType, eBufType, nPixelSpace, nLineSpace,
2112
0
                              nullptr, 10.0, 1. / 20);
2113
0
}  // dB2AmpPixelFunc
2114
2115
static CPLErr dB2PowPixelFunc(void **papoSources, int nSources, void *pData,
2116
                              int nXSize, int nYSize, GDALDataType eSrcType,
2117
                              GDALDataType eBufType, int nPixelSpace,
2118
                              int nLineSpace)
2119
0
{
2120
0
    return ExpPixelFuncHelper(papoSources, nSources, pData, nXSize, nYSize,
2121
0
                              eSrcType, eBufType, nPixelSpace, nLineSpace,
2122
0
                              nullptr, 10.0, 1. / 10);
2123
0
}  // dB2PowPixelFunc
2124
2125
static const char pszPowPixelFuncMetadata[] =
2126
    "<PixelFunctionArgumentsList>"
2127
    "   <Argument name='power' description='Exponent' type='double' "
2128
    "mandatory='1' />"
2129
    "   <Argument type='builtin' value='NoData' optional='true' />"
2130
    "</PixelFunctionArgumentsList>";
2131
2132
static CPLErr PowPixelFunc(void **papoSources, int nSources, void *pData,
2133
                           int nXSize, int nYSize, GDALDataType eSrcType,
2134
                           GDALDataType eBufType, int nPixelSpace,
2135
                           int nLineSpace, CSLConstList papszArgs)
2136
0
{
2137
    /* ---- Init ---- */
2138
0
    if (nSources != 1)
2139
0
        return CE_Failure;
2140
0
    if (GDALDataTypeIsComplex(eSrcType))
2141
0
        return CE_Failure;
2142
2143
0
    double power;
2144
0
    if (FetchDoubleArg(papszArgs, "power", &power) != CE_None)
2145
0
        return CE_Failure;
2146
2147
0
    double dfNoData{0};
2148
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2149
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2150
0
        return CE_Failure;
2151
2152
    /* ---- Set pixels ---- */
2153
0
    size_t ii = 0;
2154
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2155
0
    {
2156
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2157
0
        {
2158
0
            const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
2159
2160
0
            const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
2161
0
                                        ? dfNoData
2162
0
                                        : std::pow(dfVal, power);
2163
2164
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2165
0
                          static_cast<GByte *>(pData) +
2166
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2167
0
                              iCol * nPixelSpace,
2168
0
                          eBufType, nPixelSpace, 1);
2169
0
        }
2170
0
    }
2171
2172
    /* ---- Return success ---- */
2173
0
    return CE_None;
2174
0
}
2175
2176
// Given nt intervals spaced by dt and beginning at t0, return the index of
2177
// the lower bound of the interval that should be used to
2178
// interpolate/extrapolate a value for t.
2179
static std::size_t intervalLeft(double t0, double dt, std::size_t nt, double t)
2180
0
{
2181
0
    if (t < t0)
2182
0
    {
2183
0
        return 0;
2184
0
    }
2185
2186
0
    std::size_t n = static_cast<std::size_t>((t - t0) / dt);
2187
2188
0
    if (n >= nt - 1)
2189
0
    {
2190
0
        return nt - 2;
2191
0
    }
2192
2193
0
    return n;
2194
0
}
2195
2196
static double InterpolateLinear(double dfX0, double dfX1, double dfY0,
2197
                                double dfY1, double dfX)
2198
0
{
2199
0
    return dfY0 + (dfX - dfX0) * (dfY1 - dfY0) / (dfX1 - dfX0);
2200
0
}
2201
2202
static double InterpolateExponential(double dfX0, double dfX1, double dfY0,
2203
                                     double dfY1, double dfX)
2204
0
{
2205
0
    const double r = std::log(dfY1 / dfY0) / (dfX1 - dfX0);
2206
0
    return dfY0 * std::exp(r * (dfX - dfX0));
2207
0
}
2208
2209
static const char pszInterpolatePixelFuncMetadata[] =
2210
    "<PixelFunctionArgumentsList>"
2211
    "   <Argument name='t0' description='t0' type='double' mandatory='1' />"
2212
    "   <Argument name='dt' description='dt' type='double' mandatory='1' />"
2213
    "   <Argument name='t' description='t' type='double' mandatory='1' />"
2214
    "   <Argument type='builtin' value='NoData' optional='true' />"
2215
    "</PixelFunctionArgumentsList>";
2216
2217
template <decltype(InterpolateLinear) InterpolationFunction>
2218
CPLErr InterpolatePixelFunc(void **papoSources, int nSources, void *pData,
2219
                            int nXSize, int nYSize, GDALDataType eSrcType,
2220
                            GDALDataType eBufType, int nPixelSpace,
2221
                            int nLineSpace, CSLConstList papszArgs)
2222
0
{
2223
    /* ---- Init ---- */
2224
0
    if (GDALDataTypeIsComplex(eSrcType))
2225
0
        return CE_Failure;
2226
2227
0
    double dfT0;
2228
0
    if (FetchDoubleArg(papszArgs, "t0", &dfT0) == CE_Failure)
2229
0
        return CE_Failure;
2230
2231
0
    double dfT;
2232
0
    if (FetchDoubleArg(papszArgs, "t", &dfT) == CE_Failure)
2233
0
        return CE_Failure;
2234
2235
0
    double dfDt;
2236
0
    if (FetchDoubleArg(papszArgs, "dt", &dfDt) == CE_Failure)
2237
0
        return CE_Failure;
2238
2239
0
    double dfNoData{0};
2240
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2241
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2242
0
        return CE_Failure;
2243
2244
0
    if (nSources < 2)
2245
0
    {
2246
0
        CPLError(CE_Failure, CPLE_AppDefined,
2247
0
                 "At least two sources required for interpolation.");
2248
0
        return CE_Failure;
2249
0
    }
2250
2251
0
    if (dfT == 0 || !std::isfinite(dfT))
2252
0
    {
2253
0
        CPLError(CE_Failure, CPLE_AppDefined, "dt must be finite and non-zero");
2254
0
        return CE_Failure;
2255
0
    }
2256
2257
0
    const auto i0 = intervalLeft(dfT0, dfDt, nSources, dfT);
2258
0
    const auto i1 = i0 + 1;
2259
0
    const double dfX0 = dfT0 + static_cast<double>(i0) * dfDt;
2260
0
    const double dfX1 = dfT0 + static_cast<double>(i0 + 1) * dfDt;
2261
2262
    /* ---- Set pixels ---- */
2263
0
    size_t ii = 0;
2264
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2265
0
    {
2266
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2267
0
        {
2268
0
            const double dfY0 = GetSrcVal(papoSources[i0], eSrcType, ii);
2269
0
            const double dfY1 = GetSrcVal(papoSources[i1], eSrcType, ii);
2270
2271
0
            double dfPixVal = dfNoData;
2272
0
            if (dfT == dfX0)
2273
0
                dfPixVal = dfY0;
2274
0
            else if (dfT == dfX1)
2275
0
                dfPixVal = dfY1;
2276
0
            else if (!bHasNoData ||
2277
0
                     (!IsNoData(dfY0, dfNoData) && !IsNoData(dfY1, dfNoData)))
2278
0
                dfPixVal = InterpolationFunction(dfX0, dfX1, dfY0, dfY1, dfT);
2279
2280
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2281
0
                          static_cast<GByte *>(pData) +
2282
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2283
0
                              iCol * nPixelSpace,
2284
0
                          eBufType, nPixelSpace, 1);
2285
0
        }
2286
0
    }
2287
2288
    /* ---- Return success ---- */
2289
0
    return CE_None;
2290
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*)
2291
2292
static const char pszReplaceNoDataPixelFuncMetadata[] =
2293
    "<PixelFunctionArgumentsList>"
2294
    "   <Argument type='builtin' value='NoData' />"
2295
    "   <Argument name='to' type='double' description='New NoData value to be "
2296
    "replaced' default='nan' />"
2297
    "</PixelFunctionArgumentsList>";
2298
2299
static CPLErr ReplaceNoDataPixelFunc(void **papoSources, int nSources,
2300
                                     void *pData, int nXSize, int nYSize,
2301
                                     GDALDataType eSrcType,
2302
                                     GDALDataType eBufType, int nPixelSpace,
2303
                                     int nLineSpace, CSLConstList papszArgs)
2304
0
{
2305
    /* ---- Init ---- */
2306
0
    if (nSources != 1)
2307
0
        return CE_Failure;
2308
0
    if (GDALDataTypeIsComplex(eSrcType))
2309
0
    {
2310
0
        CPLError(CE_Failure, CPLE_AppDefined,
2311
0
                 "replace_nodata cannot convert complex data types");
2312
0
        return CE_Failure;
2313
0
    }
2314
2315
0
    double dfOldNoData, dfNewNoData = NAN;
2316
0
    if (FetchDoubleArg(papszArgs, "NoData", &dfOldNoData) != CE_None)
2317
0
        return CE_Failure;
2318
0
    if (FetchDoubleArg(papszArgs, "to", &dfNewNoData, &dfNewNoData) != CE_None)
2319
0
        return CE_Failure;
2320
2321
0
    if (!GDALDataTypeIsFloating(eBufType) && std::isnan(dfNewNoData))
2322
0
    {
2323
0
        CPLError(CE_Failure, CPLE_AppDefined,
2324
0
                 "Using nan requires a floating point type output buffer");
2325
0
        return CE_Failure;
2326
0
    }
2327
2328
    /* ---- Set pixels ---- */
2329
0
    size_t ii = 0;
2330
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2331
0
    {
2332
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2333
0
        {
2334
0
            double dfPixVal = GetSrcVal(papoSources[0], eSrcType, ii);
2335
0
            if (dfPixVal == dfOldNoData || std::isnan(dfPixVal))
2336
0
                dfPixVal = dfNewNoData;
2337
2338
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2339
0
                          static_cast<GByte *>(pData) +
2340
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2341
0
                              iCol * nPixelSpace,
2342
0
                          eBufType, nPixelSpace, 1);
2343
0
        }
2344
0
    }
2345
2346
    /* ---- Return success ---- */
2347
0
    return CE_None;
2348
0
}
2349
2350
static const char pszScalePixelFuncMetadata[] =
2351
    "<PixelFunctionArgumentsList>"
2352
    "   <Argument type='builtin' value='offset' />"
2353
    "   <Argument type='builtin' value='scale' />"
2354
    "   <Argument type='builtin' value='NoData' optional='true' />"
2355
    "</PixelFunctionArgumentsList>";
2356
2357
static CPLErr ScalePixelFunc(void **papoSources, int nSources, void *pData,
2358
                             int nXSize, int nYSize, GDALDataType eSrcType,
2359
                             GDALDataType eBufType, int nPixelSpace,
2360
                             int nLineSpace, CSLConstList papszArgs)
2361
0
{
2362
    /* ---- Init ---- */
2363
0
    if (nSources != 1)
2364
0
        return CE_Failure;
2365
0
    if (GDALDataTypeIsComplex(eSrcType))
2366
0
    {
2367
0
        CPLError(CE_Failure, CPLE_AppDefined,
2368
0
                 "scale cannot by applied to complex data types");
2369
0
        return CE_Failure;
2370
0
    }
2371
2372
0
    double dfNoData{0};
2373
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2374
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2375
0
        return CE_Failure;
2376
2377
0
    double dfScale, dfOffset;
2378
0
    if (FetchDoubleArg(papszArgs, "scale", &dfScale) != CE_None)
2379
0
        return CE_Failure;
2380
0
    if (FetchDoubleArg(papszArgs, "offset", &dfOffset) != CE_None)
2381
0
        return CE_Failure;
2382
2383
    /* ---- Set pixels ---- */
2384
0
    size_t ii = 0;
2385
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2386
0
    {
2387
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2388
0
        {
2389
0
            const double dfVal = GetSrcVal(papoSources[0], eSrcType, ii);
2390
2391
0
            const double dfPixVal = bHasNoData && IsNoData(dfVal, dfNoData)
2392
0
                                        ? dfNoData
2393
0
                                        : dfVal * dfScale + dfOffset;
2394
2395
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2396
0
                          static_cast<GByte *>(pData) +
2397
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2398
0
                              iCol * nPixelSpace,
2399
0
                          eBufType, nPixelSpace, 1);
2400
0
        }
2401
0
    }
2402
2403
    /* ---- Return success ---- */
2404
0
    return CE_None;
2405
0
}
2406
2407
static const char pszNormDiffPixelFuncMetadata[] =
2408
    "<PixelFunctionArgumentsList>"
2409
    "   <Argument type='builtin' value='NoData' optional='true' />"
2410
    "</PixelFunctionArgumentsList>";
2411
2412
static CPLErr NormDiffPixelFunc(void **papoSources, int nSources, void *pData,
2413
                                int nXSize, int nYSize, GDALDataType eSrcType,
2414
                                GDALDataType eBufType, int nPixelSpace,
2415
                                int nLineSpace, CSLConstList papszArgs)
2416
0
{
2417
    /* ---- Init ---- */
2418
0
    if (nSources != 2)
2419
0
        return CE_Failure;
2420
2421
0
    if (GDALDataTypeIsComplex(eSrcType))
2422
0
    {
2423
0
        CPLError(CE_Failure, CPLE_AppDefined,
2424
0
                 "norm_diff cannot by applied to complex data types");
2425
0
        return CE_Failure;
2426
0
    }
2427
2428
0
    double dfNoData{0};
2429
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2430
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2431
0
        return CE_Failure;
2432
2433
    /* ---- Set pixels ---- */
2434
0
    size_t ii = 0;
2435
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2436
0
    {
2437
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2438
0
        {
2439
0
            const double dfLeftVal = GetSrcVal(papoSources[0], eSrcType, ii);
2440
0
            const double dfRightVal = GetSrcVal(papoSources[1], eSrcType, ii);
2441
2442
0
            double dfPixVal = dfNoData;
2443
2444
0
            if (!bHasNoData || (!IsNoData(dfLeftVal, dfNoData) &&
2445
0
                                !IsNoData(dfRightVal, dfNoData)))
2446
0
            {
2447
0
                const double dfDenom = (dfLeftVal + dfRightVal);
2448
                // coverity[divide_by_zero]
2449
0
                dfPixVal =
2450
0
                    dfDenom == 0
2451
0
                        ? std::numeric_limits<double>::infinity()
2452
0
                        : (dfLeftVal - dfRightVal) /
2453
#ifdef __COVERITY__
2454
                              (dfDenom + std::numeric_limits<double>::min())
2455
#else
2456
0
                              dfDenom
2457
0
#endif
2458
0
                    ;
2459
0
            }
2460
2461
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
2462
0
                          static_cast<GByte *>(pData) +
2463
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2464
0
                              iCol * nPixelSpace,
2465
0
                          eBufType, nPixelSpace, 1);
2466
0
        }
2467
0
    }
2468
2469
    /* ---- Return success ---- */
2470
0
    return CE_None;
2471
0
}  // NormDiffPixelFunc
2472
2473
/************************************************************************/
2474
/*                     pszMinMaxFuncMetadataNodata                      */
2475
/************************************************************************/
2476
2477
static const char pszArgMinMaxFuncMetadataNodata[] =
2478
    "<PixelFunctionArgumentsList>"
2479
    "   <Argument type='builtin' value='NoData' optional='true' />"
2480
    "   <Argument name='propagateNoData' description='Whether the output value "
2481
    "should be NoData as as soon as one source is NoData' type='boolean' "
2482
    "default='false' />"
2483
    "</PixelFunctionArgumentsList>";
2484
2485
static const char pszMinMaxFuncMetadataNodata[] =
2486
    "<PixelFunctionArgumentsList>"
2487
    "   <Argument name='k' description='Optional constant term' type='double' "
2488
    "default='nan' />"
2489
    "   <Argument type='builtin' value='NoData' optional='true' />"
2490
    "   <Argument name='propagateNoData' description='Whether the output value "
2491
    "should be NoData as as soon as one source is NoData' type='boolean' "
2492
    "default='false' />"
2493
    "</PixelFunctionArgumentsList>";
2494
2495
namespace
2496
{
2497
struct ReturnIndex;
2498
struct ReturnValue;
2499
}  // namespace
2500
2501
template <class Comparator, class ReturnType = ReturnValue>
2502
static CPLErr MinOrMaxPixelFunc(double dfK, void **papoSources, int nSources,
2503
                                void *pData, int nXSize, int nYSize,
2504
                                GDALDataType eSrcType, GDALDataType eBufType,
2505
                                int nPixelSpace, int nLineSpace,
2506
                                CSLConstList papszArgs)
2507
0
{
2508
    /* ---- Init ---- */
2509
0
    if (GDALDataTypeIsComplex(eSrcType))
2510
0
    {
2511
0
        CPLError(CE_Failure, CPLE_AppDefined,
2512
0
                 "Complex data type not supported for min/max().");
2513
0
        return CE_Failure;
2514
0
    }
2515
2516
0
    double dfNoData = std::numeric_limits<double>::quiet_NaN();
2517
0
    if (FetchDoubleArg(papszArgs, "NoData", &dfNoData, &dfNoData) != CE_None)
2518
0
        return CE_Failure;
2519
0
    const bool bPropagateNoData = CPLTestBool(
2520
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
2521
2522
    /* ---- Set pixels ---- */
2523
0
    size_t ii = 0;
2524
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2525
0
    {
2526
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
2527
0
        {
2528
0
            double dfRes = std::numeric_limits<double>::quiet_NaN();
2529
0
            double dfResSrc = std::numeric_limits<double>::quiet_NaN();
2530
2531
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
2532
0
            {
2533
0
                const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
2534
2535
0
                if (std::isnan(dfVal) || dfVal == dfNoData)
2536
0
                {
2537
0
                    if (bPropagateNoData)
2538
0
                    {
2539
0
                        dfRes = dfNoData;
2540
                        if constexpr (std::is_same_v<ReturnType, ReturnIndex>)
2541
0
                        {
2542
0
                            dfResSrc = std::numeric_limits<double>::quiet_NaN();
2543
0
                        }
2544
0
                        break;
2545
0
                    }
2546
0
                }
2547
0
                else if (Comparator::compare(dfVal, dfRes))
2548
0
                {
2549
0
                    dfRes = dfVal;
2550
                    if constexpr (std::is_same_v<ReturnType, ReturnIndex>)
2551
0
                    {
2552
0
                        dfResSrc = iSrc;
2553
0
                    }
2554
0
                }
2555
0
            }
2556
2557
            if constexpr (std::is_same_v<ReturnType, ReturnIndex>)
2558
0
            {
2559
0
                static_cast<void>(dfK);  // Placate gcc 9.4
2560
0
                dfRes = std::isnan(dfResSrc) ? dfNoData : dfResSrc + 1;
2561
            }
2562
            else
2563
0
            {
2564
0
                if (std::isnan(dfRes))
2565
0
                {
2566
0
                    dfRes = dfNoData;
2567
0
                }
2568
2569
0
                if (IsNoData(dfRes, dfNoData))
2570
0
                {
2571
0
                    if (!bPropagateNoData && !std::isnan(dfK))
2572
0
                    {
2573
0
                        dfRes = dfK;
2574
0
                    }
2575
0
                }
2576
0
                else if (!std::isnan(dfK) && Comparator::compare(dfK, dfRes))
2577
0
                {
2578
0
                    dfRes = dfK;
2579
0
                }
2580
0
            }
2581
2582
0
            GDALCopyWords(&dfRes, GDT_Float64, 0,
2583
0
                          static_cast<GByte *>(pData) +
2584
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
2585
0
                              iCol * nPixelSpace,
2586
0
                          eBufType, nPixelSpace, 1);
2587
0
        }
2588
0
    }
2589
2590
    /* ---- Return success ---- */
2591
0
    return CE_None;
2592
0
} /* MinOrMaxPixelFunc */
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MinPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnValue>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MinPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnIndex>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MaxPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnValue>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinOrMaxPixelFunc<MaxPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator, (anonymous namespace)::ReturnIndex>(double, void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2593
2594
#ifdef USE_SSE2
2595
2596
template <class T, class SSEWrapper>
2597
static void OptimizedMinOrMaxSSE2(const void *const *papoSources, int nSources,
2598
                                  void *pData, int nXSize, int nYSize,
2599
                                  int nLineSpace)
2600
0
{
2601
0
    assert(nSources >= 1);
2602
0
    constexpr int VALUES_PER_REG =
2603
0
        static_cast<int>(sizeof(typename SSEWrapper::Vec) / sizeof(T));
2604
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
2605
0
    {
2606
0
        T *CPL_RESTRICT pDest =
2607
0
            reinterpret_cast<T *>(static_cast<GByte *>(pData) +
2608
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
2609
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
2610
0
        int iCol = 0;
2611
0
        for (; iCol < nXSize - (2 * VALUES_PER_REG - 1);
2612
0
             iCol += 2 * VALUES_PER_REG)
2613
0
        {
2614
0
            auto reg0 = SSEWrapper::LoadU(
2615
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
2616
0
                iOffsetLine + iCol);
2617
0
            auto reg1 = SSEWrapper::LoadU(
2618
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
2619
0
                iOffsetLine + iCol + VALUES_PER_REG);
2620
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
2621
0
            {
2622
0
                reg0 = SSEWrapper::MinOrMax(
2623
0
                    reg0, SSEWrapper::LoadU(static_cast<const T * CPL_RESTRICT>(
2624
0
                                                papoSources[iSrc]) +
2625
0
                                            iOffsetLine + iCol));
2626
0
                reg1 = SSEWrapper::MinOrMax(
2627
0
                    reg1,
2628
0
                    SSEWrapper::LoadU(
2629
0
                        static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
2630
0
                        iOffsetLine + iCol + VALUES_PER_REG));
2631
0
            }
2632
0
            SSEWrapper::StoreU(pDest + iCol, reg0);
2633
0
            SSEWrapper::StoreU(pDest + iCol + VALUES_PER_REG, reg1);
2634
0
        }
2635
0
        for (; iCol < nXSize; ++iCol)
2636
0
        {
2637
0
            T v = static_cast<const T * CPL_RESTRICT>(
2638
0
                papoSources[0])[iOffsetLine + iCol];
2639
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
2640
0
            {
2641
0
                v = SSEWrapper::MinOrMax(
2642
0
                    v, static_cast<const T * CPL_RESTRICT>(
2643
0
                           papoSources[iSrc])[iOffsetLine + iCol]);
2644
0
            }
2645
0
            pDest[iCol] = v;
2646
0
        }
2647
0
    }
2648
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned char, (anonymous namespace)::SSEWrapperMinByte>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned short, (anonymous namespace)::SSEWrapperMinUInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<short, (anonymous namespace)::SSEWrapperMinInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<float, (anonymous namespace)::SSEWrapperMinFloat>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<double, (anonymous namespace)::SSEWrapperMinDouble>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned char, (anonymous namespace)::SSEWrapperMaxByte>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<unsigned short, (anonymous namespace)::SSEWrapperMaxUInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<short, (anonymous namespace)::SSEWrapperMaxInt16>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<float, (anonymous namespace)::SSEWrapperMaxFloat>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMinOrMaxSSE2<double, (anonymous namespace)::SSEWrapperMaxDouble>(void const* const*, int, void*, int, int, int)
2649
2650
// clang-format off
2651
namespace
2652
{
2653
struct SSEWrapperMinByte
2654
{
2655
    using T = uint8_t;
2656
    typedef __m128i Vec;
2657
2658
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2659
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2660
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epu8(x, y); }
2661
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2662
};
2663
2664
struct SSEWrapperMaxByte
2665
{
2666
    using T = uint8_t;
2667
    typedef __m128i Vec;
2668
2669
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2670
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2671
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epu8(x, y); }
2672
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2673
};
2674
2675
struct SSEWrapperMinUInt16
2676
{
2677
    using T = uint16_t;
2678
    typedef __m128i Vec;
2679
2680
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2681
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2682
#if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
2683
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epu16(x, y); }
2684
#else
2685
0
    static inline Vec MinOrMax(Vec x, Vec y) { return
2686
0
        _mm_add_epi16(
2687
0
           _mm_min_epi16(
2688
0
             _mm_add_epi16(x, _mm_set1_epi16(-32768)),
2689
0
             _mm_add_epi16(y, _mm_set1_epi16(-32768))),
2690
0
           _mm_set1_epi16(-32768)); }
2691
#endif
2692
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2693
};
2694
2695
struct SSEWrapperMaxUInt16
2696
{
2697
    using T = uint16_t;
2698
    typedef __m128i Vec;
2699
2700
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2701
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2702
#if defined(__SSE4_1__) || defined(USE_NEON_OPTIMIZATIONS)
2703
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epu16(x, y); }
2704
#else
2705
0
    static inline Vec MinOrMax(Vec x, Vec y) { return
2706
0
        _mm_add_epi16(
2707
0
           _mm_max_epi16(
2708
0
             _mm_add_epi16(x, _mm_set1_epi16(-32768)),
2709
0
             _mm_add_epi16(y, _mm_set1_epi16(-32768))),
2710
0
           _mm_set1_epi16(-32768)); }
2711
#endif
2712
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2713
};
2714
2715
struct SSEWrapperMinInt16
2716
{
2717
    using T = int16_t;
2718
    typedef __m128i Vec;
2719
2720
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2721
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2722
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_epi16(x, y); }
2723
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2724
};
2725
2726
struct SSEWrapperMaxInt16
2727
{
2728
    using T = int16_t;
2729
    typedef __m128i Vec;
2730
2731
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_si128(reinterpret_cast<const Vec*>(x)); }
2732
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_si128(reinterpret_cast<Vec*>(x), y); }
2733
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_epi16(x, y); }
2734
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2735
};
2736
2737
struct SSEWrapperMinFloat
2738
{
2739
    using T = float;
2740
    typedef __m128 Vec;
2741
2742
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_ps(x); }
2743
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_ps(x, y); }
2744
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_ps(x, y); }
2745
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2746
};
2747
2748
struct SSEWrapperMaxFloat
2749
{
2750
    using T = float;
2751
    typedef __m128 Vec;
2752
2753
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_ps(x); }
2754
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_ps(x, y); }
2755
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_ps(x, y); }
2756
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2757
};
2758
2759
struct SSEWrapperMinDouble
2760
{
2761
    using T = double;
2762
    typedef __m128d Vec;
2763
2764
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_pd(x); }
2765
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_pd(x, y); }
2766
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_min_pd(x, y); }
2767
0
    static inline T MinOrMax(T x, T y) { return std::min(x, y); }
2768
};
2769
2770
struct SSEWrapperMaxDouble
2771
{
2772
    using T = double;
2773
    typedef __m128d Vec;
2774
2775
0
    static inline Vec LoadU(const T *x) { return _mm_loadu_pd(x); }
2776
0
    static inline void StoreU(T *x, Vec y) { _mm_storeu_pd(x, y); }
2777
0
    static inline Vec MinOrMax(Vec x, Vec y) { return _mm_max_pd(x, y); }
2778
0
    static inline T MinOrMax(T x, T y) { return std::max(x, y); }
2779
};
2780
2781
}  // namespace
2782
2783
// clang-format on
2784
2785
#endif  // USE_SSE2
2786
2787
template <typename ReturnType>
2788
static CPLErr MinPixelFunc(void **papoSources, int nSources, void *pData,
2789
                           int nXSize, int nYSize, GDALDataType eSrcType,
2790
                           GDALDataType eBufType, int nPixelSpace,
2791
                           int nLineSpace, CSLConstList papszArgs)
2792
0
{
2793
0
    struct Comparator
2794
0
    {
2795
0
        static bool compare(double x, double resVal)
2796
0
        {
2797
            // Written this way to deal with resVal being NaN
2798
0
            return !(x >= resVal);
2799
0
        }
Unexecuted instantiation: pixelfunctions.cpp:MinPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
Unexecuted instantiation: pixelfunctions.cpp:MinPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
2800
0
    };
2801
2802
0
    double dfK = std::numeric_limits<double>::quiet_NaN();
2803
    if constexpr (std::is_same_v<ReturnType, ReturnValue>)
2804
0
    {
2805
0
        if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
2806
0
            return CE_Failure;
2807
2808
0
#ifdef USE_SSE2
2809
0
        const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2810
0
        if (std::isnan(dfK) && nSources > 0 && !bHasNoData &&
2811
0
            eSrcType == eBufType &&
2812
0
            nPixelSpace == GDALGetDataTypeSizeBytes(eSrcType))
2813
0
        {
2814
0
            if (eSrcType == GDT_UInt8)
2815
0
            {
2816
0
                OptimizedMinOrMaxSSE2<uint8_t, SSEWrapperMinByte>(
2817
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2818
0
                return CE_None;
2819
0
            }
2820
0
            else if (eSrcType == GDT_UInt16)
2821
0
            {
2822
0
                OptimizedMinOrMaxSSE2<uint16_t, SSEWrapperMinUInt16>(
2823
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2824
0
                return CE_None;
2825
0
            }
2826
0
            else if (eSrcType == GDT_Int16)
2827
0
            {
2828
0
                OptimizedMinOrMaxSSE2<int16_t, SSEWrapperMinInt16>(
2829
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2830
0
                return CE_None;
2831
0
            }
2832
0
            else if (eSrcType == GDT_Float32)
2833
0
            {
2834
0
                OptimizedMinOrMaxSSE2<float, SSEWrapperMinFloat>(
2835
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2836
0
                return CE_None;
2837
0
            }
2838
0
            else if (eSrcType == GDT_Float64)
2839
0
            {
2840
0
                OptimizedMinOrMaxSSE2<double, SSEWrapperMinDouble>(
2841
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2842
0
                return CE_None;
2843
0
            }
2844
0
        }
2845
0
#endif
2846
0
    }
2847
2848
0
    return MinOrMaxPixelFunc<Comparator, ReturnType>(
2849
0
        dfK, papoSources, nSources, pData, nXSize, nYSize, eSrcType, eBufType,
2850
0
        nPixelSpace, nLineSpace, papszArgs);
2851
0
}
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MinPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2852
2853
template <typename ReturnType>
2854
static CPLErr MaxPixelFunc(void **papoSources, int nSources, void *pData,
2855
                           int nXSize, int nYSize, GDALDataType eSrcType,
2856
                           GDALDataType eBufType, int nPixelSpace,
2857
                           int nLineSpace, CSLConstList papszArgs)
2858
0
{
2859
0
    struct Comparator
2860
0
    {
2861
0
        static bool compare(double x, double resVal)
2862
0
        {
2863
            // Written this way to deal with resVal being NaN
2864
0
            return !(x <= resVal);
2865
0
        }
Unexecuted instantiation: pixelfunctions.cpp:MaxPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
Unexecuted instantiation: pixelfunctions.cpp:MaxPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)::Comparator::compare(double, double)
2866
0
    };
2867
2868
0
    double dfK = std::numeric_limits<double>::quiet_NaN();
2869
    if constexpr (std::is_same_v<ReturnType, ReturnValue>)
2870
0
    {
2871
0
        if (FetchDoubleArg(papszArgs, "k", &dfK, &dfK) != CE_None)
2872
0
            return CE_Failure;
2873
2874
0
#ifdef USE_SSE2
2875
0
        const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2876
0
        if (std::isnan(dfK) && nSources > 0 && !bHasNoData &&
2877
0
            eSrcType == eBufType &&
2878
0
            nPixelSpace == GDALGetDataTypeSizeBytes(eSrcType))
2879
0
        {
2880
0
            if (eSrcType == GDT_UInt8)
2881
0
            {
2882
0
                OptimizedMinOrMaxSSE2<uint8_t, SSEWrapperMaxByte>(
2883
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2884
0
                return CE_None;
2885
0
            }
2886
0
            else if (eSrcType == GDT_UInt16)
2887
0
            {
2888
0
                OptimizedMinOrMaxSSE2<uint16_t, SSEWrapperMaxUInt16>(
2889
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2890
0
                return CE_None;
2891
0
            }
2892
0
            else if (eSrcType == GDT_Int16)
2893
0
            {
2894
0
                OptimizedMinOrMaxSSE2<int16_t, SSEWrapperMaxInt16>(
2895
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2896
0
                return CE_None;
2897
0
            }
2898
0
            else if (eSrcType == GDT_Float32)
2899
0
            {
2900
0
                OptimizedMinOrMaxSSE2<float, SSEWrapperMaxFloat>(
2901
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2902
0
                return CE_None;
2903
0
            }
2904
0
            else if (eSrcType == GDT_Float64)
2905
0
            {
2906
0
                OptimizedMinOrMaxSSE2<double, SSEWrapperMaxDouble>(
2907
0
                    papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
2908
0
                return CE_None;
2909
0
            }
2910
0
        }
2911
0
#endif
2912
0
    }
2913
2914
0
    return MinOrMaxPixelFunc<Comparator, ReturnType>(
2915
0
        dfK, papoSources, nSources, pData, nXSize, nYSize, eSrcType, eBufType,
2916
0
        nPixelSpace, nLineSpace, papszArgs);
2917
0
}
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MaxPixelFunc<(anonymous namespace)::ReturnValue>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
Unexecuted instantiation: pixelfunctions.cpp:CPLErr MaxPixelFunc<(anonymous namespace)::ReturnIndex>(void**, int, void*, int, int, GDALDataType, GDALDataType, int, int, char const* const*)
2918
2919
static const char pszExprPixelFuncMetadata[] =
2920
    "<PixelFunctionArgumentsList>"
2921
    "   <Argument type='builtin' value='NoData' optional='true' />"
2922
    "   <Argument name='propagateNoData' description='Whether the output value "
2923
    "should be NoData as as soon as one source is NoData' type='boolean' "
2924
    "default='false' />"
2925
    "   <Argument name='expression' "
2926
    "             description='Expression to be evaluated' "
2927
    "             type='string'></Argument>"
2928
    "   <Argument name='dialect' "
2929
    "             description='Expression dialect' "
2930
    "             type='string-select'"
2931
    "             default='muparser'>"
2932
    "       <Value>exprtk</Value>"
2933
    "       <Value>muparser</Value>"
2934
    "   </Argument>"
2935
    "   <Argument type='builtin' value='source_names' />"
2936
    "   <Argument type='builtin' value='xoff' />"
2937
    "   <Argument type='builtin' value='yoff' />"
2938
    "   <Argument type='builtin' value='geotransform' />"
2939
    "</PixelFunctionArgumentsList>";
2940
2941
static CPLErr ExprPixelFunc(void **papoSources, int nSources, void *pData,
2942
                            int nXSize, int nYSize, GDALDataType eSrcType,
2943
                            GDALDataType eBufType, int nPixelSpace,
2944
                            int nLineSpace, CSLConstList papszArgs)
2945
0
{
2946
    /* ---- Init ---- */
2947
0
    if (GDALDataTypeIsComplex(eSrcType))
2948
0
    {
2949
0
        CPLError(CE_Failure, CPLE_AppDefined,
2950
0
                 "expression cannot by applied to complex data types");
2951
0
        return CE_Failure;
2952
0
    }
2953
2954
0
    double dfNoData{0};
2955
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
2956
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
2957
0
        return CE_Failure;
2958
2959
0
    const bool bPropagateNoData = CPLTestBool(
2960
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
2961
2962
0
    const char *pszExpression = CSLFetchNameValue(papszArgs, "expression");
2963
0
    if (!pszExpression)
2964
0
    {
2965
0
        CPLError(CE_Failure, CPLE_AppDefined,
2966
0
                 "Missing 'expression' pixel function argument");
2967
0
        return CE_Failure;
2968
0
    }
2969
2970
0
    const char *pszSourceNames = CSLFetchNameValue(papszArgs, "source_names");
2971
0
    const CPLStringList aosSourceNames(
2972
0
        CSLTokenizeString2(pszSourceNames, "|", 0));
2973
0
    if (aosSourceNames.size() != nSources)
2974
0
    {
2975
0
        CPLError(CE_Failure, CPLE_AppDefined,
2976
0
                 "The source_names variable passed to ExprPixelFunc() has %d "
2977
0
                 "values, whereas %d were expected. An invalid variable name "
2978
0
                 "has likely been used",
2979
0
                 aosSourceNames.size(), nSources);
2980
0
        return CE_Failure;
2981
0
    }
2982
2983
0
    std::vector<double> adfValuesForPixel(nSources);
2984
2985
0
    const char *pszDialect = CSLFetchNameValue(papszArgs, "dialect");
2986
0
    if (!pszDialect)
2987
0
    {
2988
0
        pszDialect = "muparser";
2989
0
    }
2990
2991
0
    auto poExpression = gdal::MathExpression::Create(pszExpression, pszDialect);
2992
2993
    // cppcheck-suppress knownConditionTrueFalse
2994
0
    if (!poExpression)
2995
0
    {
2996
0
        return CE_Failure;
2997
0
    }
2998
2999
0
    int nXOff = 0;
3000
0
    int nYOff = 0;
3001
0
    GDALGeoTransform gt;
3002
0
    double dfCenterX = 0;
3003
0
    double dfCenterY = 0;
3004
3005
0
    bool includeCenterCoords = false;
3006
0
    if (strstr(pszExpression, "_CENTER_X_") ||
3007
0
        strstr(pszExpression, "_CENTER_Y_"))
3008
0
    {
3009
0
        includeCenterCoords = true;
3010
3011
0
        const char *pszXOff = CSLFetchNameValue(papszArgs, "xoff");
3012
0
        nXOff = std::atoi(pszXOff);
3013
3014
0
        const char *pszYOff = CSLFetchNameValue(papszArgs, "yoff");
3015
0
        nYOff = std::atoi(pszYOff);
3016
3017
0
        const char *pszGT = CSLFetchNameValue(papszArgs, "geotransform");
3018
0
        if (pszGT == nullptr)
3019
0
        {
3020
0
            CPLError(CE_Failure, CPLE_AppDefined,
3021
0
                     "To use _CENTER_X_ or _CENTER_Y_ in an expression, "
3022
0
                     "VRTDataset must have a <GeoTransform> element.");
3023
0
            return CE_Failure;
3024
0
        }
3025
3026
0
        if (!gt.Init(pszGT))
3027
0
        {
3028
0
            CPLError(CE_Failure, CPLE_AppDefined,
3029
0
                     "Invalid GeoTransform argument");
3030
0
            return CE_Failure;
3031
0
        }
3032
0
    }
3033
3034
0
    {
3035
0
        int iSource = 0;
3036
0
        for (const auto &osName : aosSourceNames)
3037
0
        {
3038
0
            poExpression->RegisterVariable(osName,
3039
0
                                           &adfValuesForPixel[iSource++]);
3040
0
        }
3041
0
    }
3042
3043
0
    if (includeCenterCoords)
3044
0
    {
3045
0
        poExpression->RegisterVariable("_CENTER_X_", &dfCenterX);
3046
0
        poExpression->RegisterVariable("_CENTER_Y_", &dfCenterY);
3047
0
    }
3048
3049
0
    if (bHasNoData)
3050
0
    {
3051
0
        poExpression->RegisterVariable("NODATA", &dfNoData);
3052
0
    }
3053
3054
0
    if (strstr(pszExpression, "BANDS"))
3055
0
    {
3056
0
        poExpression->RegisterVector("BANDS", &adfValuesForPixel);
3057
0
    }
3058
3059
0
    std::unique_ptr<double, VSIFreeReleaser> padfResults(
3060
0
        static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
3061
0
    if (!padfResults)
3062
0
        return CE_Failure;
3063
3064
    /* ---- Set pixels ---- */
3065
0
    size_t ii = 0;
3066
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3067
0
    {
3068
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
3069
0
        {
3070
0
            double &dfResult = padfResults.get()[iCol];
3071
0
            bool resultIsNoData = false;
3072
3073
0
            for (int iSrc = 0; iSrc < nSources; iSrc++)
3074
0
            {
3075
                // cppcheck-suppress unreadVariable
3076
0
                double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
3077
3078
0
                if (bHasNoData && bPropagateNoData && IsNoData(dfVal, dfNoData))
3079
0
                {
3080
0
                    resultIsNoData = true;
3081
0
                }
3082
3083
0
                adfValuesForPixel[iSrc] = dfVal;
3084
0
            }
3085
3086
0
            if (includeCenterCoords)
3087
0
            {
3088
                // Add 0.5 to pixel / line to move from pixel corner to cell center
3089
0
                gt.Apply(static_cast<double>(iCol + nXOff) + 0.5,
3090
0
                         static_cast<double>(iLine + nYOff) + 0.5, &dfCenterX,
3091
0
                         &dfCenterY);
3092
0
            }
3093
3094
0
            if (resultIsNoData)
3095
0
            {
3096
0
                dfResult = dfNoData;
3097
0
            }
3098
0
            else
3099
0
            {
3100
0
                if (auto eErr = poExpression->Evaluate(); eErr != CE_None)
3101
0
                {
3102
0
                    return CE_Failure;
3103
0
                }
3104
3105
0
                dfResult = poExpression->Results()[0];
3106
0
            }
3107
0
        }
3108
3109
0
        GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
3110
0
                      static_cast<GByte *>(pData) +
3111
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
3112
0
                      eBufType, nPixelSpace, nXSize);
3113
0
    }
3114
3115
    /* ---- Return success ---- */
3116
0
    return CE_None;
3117
0
}  // ExprPixelFunc
3118
3119
static constexpr char pszAreaPixelFuncMetadata[] =
3120
    "<PixelFunctionArgumentsList>"
3121
    "   <Argument type='builtin' value='crs' />"
3122
    "   <Argument type='builtin' value='xoff' />"
3123
    "   <Argument type='builtin' value='yoff' />"
3124
    "   <Argument type='builtin' value='geotransform' />"
3125
    "</PixelFunctionArgumentsList>";
3126
3127
static CPLErr AreaPixelFunc(void ** /*papoSources*/, int nSources, void *pData,
3128
                            int nXSize, int nYSize, GDALDataType /* eSrcType */,
3129
                            GDALDataType eBufType, int nPixelSpace,
3130
                            int nLineSpace, CSLConstList papszArgs)
3131
0
{
3132
0
    if (nSources)
3133
0
    {
3134
0
        CPLError(CE_Failure, CPLE_AppDefined,
3135
0
                 "area: unexpected source band(s)");
3136
0
        return CE_Failure;
3137
0
    }
3138
3139
0
    const char *pszGT = CSLFetchNameValue(papszArgs, "geotransform");
3140
0
    if (pszGT == nullptr)
3141
0
    {
3142
0
        CPLError(CE_Failure, CPLE_AppDefined,
3143
0
                 "area: VRTDataset has no <GeoTransform>");
3144
0
        return CE_Failure;
3145
0
    }
3146
3147
0
    GDALGeoTransform gt;
3148
0
    if (!gt.Init(pszGT))
3149
0
    {
3150
0
        CPLError(CE_Failure, CPLE_AppDefined,
3151
0
                 "area: Invalid GeoTransform argument");
3152
0
        return CE_Failure;
3153
0
    }
3154
3155
0
    const char *pszXOff = CSLFetchNameValue(papszArgs, "xoff");
3156
0
    const int nXOff = std::atoi(pszXOff);
3157
3158
0
    const char *pszYOff = CSLFetchNameValue(papszArgs, "yoff");
3159
0
    const int nYOff = std::atoi(pszYOff);
3160
3161
0
    const char *pszCrsPtr = CSLFetchNameValue(papszArgs, "crs");
3162
3163
0
    if (!pszCrsPtr)
3164
0
    {
3165
0
        CPLError(CE_Failure, CPLE_AppDefined, "area: VRTDataset has no <SRS>");
3166
0
        return CE_Failure;
3167
0
    }
3168
3169
0
    std::uintptr_t nCrsPtr = 0;
3170
0
    if (auto [end, ec] =
3171
0
            std::from_chars(pszCrsPtr, pszCrsPtr + strlen(pszCrsPtr), nCrsPtr);
3172
0
        ec != std::errc())
3173
0
    {
3174
        // Since "crs" is populated by GDAL, this should never happen.
3175
0
        CPLError(CE_Failure, CPLE_AppDefined, "Failed to read CRS");
3176
0
        return CE_Failure;
3177
0
    }
3178
3179
0
    const OGRSpatialReference *poCRS =
3180
0
        reinterpret_cast<const OGRSpatialReference *>(nCrsPtr);
3181
3182
0
    if (!poCRS)
3183
0
    {
3184
        // can't get here, but cppcheck doesn't know that
3185
0
        return CE_Failure;
3186
0
    }
3187
3188
0
    const OGRSpatialReference *poGeographicCRS = nullptr;
3189
0
    std::unique_ptr<OGRSpatialReference> poGeographicCRSHolder;
3190
0
    std::unique_ptr<OGRCoordinateTransformation> poTransform;
3191
3192
0
    if (!poCRS->IsGeographic())
3193
0
    {
3194
0
        poGeographicCRSHolder = std::make_unique<OGRSpatialReference>();
3195
0
        if (poGeographicCRSHolder->CopyGeogCSFrom(poCRS) != OGRERR_NONE)
3196
0
        {
3197
0
            CPLError(CE_Failure, CPLE_AppDefined,
3198
0
                     "Cannot reproject geometry to geographic CRS");
3199
0
            return CE_Failure;
3200
0
        }
3201
0
        poGeographicCRSHolder->SetAxisMappingStrategy(
3202
0
            OAMS_TRADITIONAL_GIS_ORDER);
3203
3204
0
        poTransform.reset(OGRCreateCoordinateTransformation(
3205
0
            poCRS, poGeographicCRSHolder.get()));
3206
3207
0
        if (!poTransform)
3208
0
        {
3209
0
            CPLError(CE_Failure, CPLE_AppDefined,
3210
0
                     "Cannot reproject geometry to geographic CRS");
3211
0
            return CE_Failure;
3212
0
        }
3213
3214
0
        poGeographicCRS = poGeographicCRSHolder.get();
3215
0
    }
3216
0
    else
3217
0
    {
3218
0
        poGeographicCRS = poCRS;
3219
0
    }
3220
3221
0
    geod_geodesic g{};
3222
0
    OGRErr eErr = OGRERR_NONE;
3223
0
    double dfSemiMajor = poGeographicCRS->GetSemiMajor(&eErr);
3224
0
    if (eErr != OGRERR_NONE)
3225
0
        return CE_Failure;
3226
0
    const double dfInvFlattening = poGeographicCRS->GetInvFlattening(&eErr);
3227
0
    if (eErr != OGRERR_NONE)
3228
0
        return CE_Failure;
3229
0
    geod_init(&g, dfSemiMajor,
3230
0
              dfInvFlattening != 0 ? 1.0 / dfInvFlattening : 0.0);
3231
3232
0
    std::array<double, 5> adfLon{};
3233
0
    std::array<double, 5> adfLat{};
3234
3235
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3236
0
    {
3237
0
        for (int iCol = 0; iCol < nXSize; ++iCol)
3238
0
        {
3239
0
            gt.Apply(static_cast<double>(iCol + nXOff),
3240
0
                     static_cast<double>(iLine + nYOff), &adfLon[0],
3241
0
                     &adfLat[0]);
3242
0
            gt.Apply(static_cast<double>(iCol + nXOff + 1),
3243
0
                     static_cast<double>(iLine + nYOff), &adfLon[1],
3244
0
                     &adfLat[1]);
3245
0
            gt.Apply(static_cast<double>(iCol + nXOff + 1),
3246
0
                     static_cast<double>(iLine + nYOff + 1), &adfLon[2],
3247
0
                     &adfLat[2]);
3248
0
            gt.Apply(static_cast<double>(iCol + nXOff),
3249
0
                     static_cast<double>(iLine + nYOff + 1), &adfLon[3],
3250
0
                     &adfLat[3]);
3251
0
            adfLon[4] = adfLon[0];
3252
0
            adfLat[4] = adfLat[0];
3253
3254
0
            if (poTransform &&
3255
0
                !poTransform->Transform(adfLon.size(), adfLon.data(),
3256
0
                                        adfLat.data(), nullptr))
3257
0
            {
3258
0
                CPLError(CE_Failure, CPLE_AppDefined,
3259
0
                         "Failed to reproject cell corners to geographic CRS");
3260
0
                return CE_Failure;
3261
0
            }
3262
3263
0
            double dfArea = -1.0;
3264
0
            geod_polygonarea(&g, adfLat.data(), adfLon.data(),
3265
0
                             static_cast<int>(adfLat.size()), &dfArea, nullptr);
3266
0
            dfArea = std::fabs(dfArea);
3267
3268
0
            GDALCopyWords(&dfArea, GDT_Float64, 0,
3269
0
                          static_cast<GByte *>(pData) +
3270
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
3271
0
                              iCol * nPixelSpace,
3272
0
                          eBufType, nPixelSpace, 1);
3273
0
        }
3274
0
    }
3275
3276
0
    return CE_None;
3277
0
}  // AreaPixelFunc
3278
3279
static const char pszReclassifyPixelFuncMetadata[] =
3280
    "<PixelFunctionArgumentsList>"
3281
    "   <Argument name='mapping' "
3282
    "             description='Lookup table for mapping, in format "
3283
    "from=to,from=to' "
3284
    "             type='string'></Argument>"
3285
    "   <Argument type='builtin' value='NoData' optional='true' />"
3286
    "</PixelFunctionArgumentsList>";
3287
3288
static CPLErr ReclassifyPixelFunc(void **papoSources, int nSources, void *pData,
3289
                                  int nXSize, int nYSize, GDALDataType eSrcType,
3290
                                  GDALDataType eBufType, int nPixelSpace,
3291
                                  int nLineSpace, CSLConstList papszArgs)
3292
0
{
3293
0
    if (GDALDataTypeIsComplex(eSrcType))
3294
0
    {
3295
0
        CPLError(CE_Failure, CPLE_AppDefined,
3296
0
                 "reclassify cannot by applied to complex data types");
3297
0
        return CE_Failure;
3298
0
    }
3299
3300
0
    if (nSources != 1)
3301
0
    {
3302
0
        CPLError(CE_Failure, CPLE_AppDefined,
3303
0
                 "reclassify only be applied to a single source at a time");
3304
0
        return CE_Failure;
3305
0
    }
3306
0
    std::optional<double> noDataValue{};
3307
3308
0
    const char *pszNoData = CSLFetchNameValue(papszArgs, "NoData");
3309
0
    if (pszNoData != nullptr)
3310
0
    {
3311
0
        noDataValue = CPLAtof(pszNoData);
3312
0
    }
3313
3314
0
    const char *pszMappings = CSLFetchNameValue(papszArgs, "mapping");
3315
0
    if (pszMappings == nullptr)
3316
0
    {
3317
0
        CPLError(CE_Failure, CPLE_AppDefined,
3318
0
                 "reclassify must be called with 'mapping' argument");
3319
0
        return CE_Failure;
3320
0
    }
3321
3322
0
    gdal::Reclassifier oReclassifier;
3323
0
    if (auto eErr = oReclassifier.Init(pszMappings, noDataValue, eBufType);
3324
0
        eErr != CE_None)
3325
0
    {
3326
0
        return eErr;
3327
0
    }
3328
3329
0
    std::unique_ptr<double, VSIFreeReleaser> padfResults(
3330
0
        static_cast<double *>(VSI_MALLOC2_VERBOSE(nXSize, sizeof(double))));
3331
0
    if (!padfResults)
3332
0
        return CE_Failure;
3333
3334
0
    size_t ii = 0;
3335
0
    bool bSuccess = false;
3336
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3337
0
    {
3338
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
3339
0
        {
3340
0
            double srcVal = GetSrcVal(papoSources[0], eSrcType, ii);
3341
0
            padfResults.get()[iCol] =
3342
0
                oReclassifier.Reclassify(srcVal, bSuccess);
3343
0
            if (!bSuccess)
3344
0
            {
3345
0
                CPLError(CE_Failure, CPLE_AppDefined,
3346
0
                         "Encountered value %g with no specified mapping",
3347
0
                         srcVal);
3348
0
                return CE_Failure;
3349
0
            }
3350
0
        }
3351
3352
0
        GDALCopyWords(padfResults.get(), GDT_Float64, sizeof(double),
3353
0
                      static_cast<GByte *>(pData) +
3354
0
                          static_cast<GSpacing>(nLineSpace) * iLine,
3355
0
                      eBufType, nPixelSpace, nXSize);
3356
0
    }
3357
3358
0
    return CE_None;
3359
0
}  // ReclassifyPixelFunc
3360
3361
struct MeanKernel
3362
{
3363
    static constexpr const char *pszName = "mean";
3364
3365
    double dfMean = 0;
3366
    int nValidSources = 0;
3367
3368
    void Reset()
3369
0
    {
3370
0
        dfMean = 0;
3371
0
        nValidSources = 0;
3372
0
    }
3373
3374
    static CPLErr ProcessArguments(CSLConstList)
3375
0
    {
3376
0
        return CE_None;
3377
0
    }
3378
3379
    void ProcessPixel(double dfVal)
3380
0
    {
3381
0
        ++nValidSources;
3382
3383
0
        if (CPL_UNLIKELY(std::isinf(dfVal)))
3384
0
        {
3385
0
            if (nValidSources == 1)
3386
0
            {
3387
0
                dfMean = dfVal;
3388
0
            }
3389
0
            else if (dfVal == -dfMean)
3390
0
            {
3391
0
                dfMean = std::numeric_limits<double>::quiet_NaN();
3392
0
            }
3393
0
        }
3394
0
        else if (CPL_UNLIKELY(std::isinf(dfMean)))
3395
0
        {
3396
0
            if (!std::isfinite(dfVal))
3397
0
            {
3398
0
                dfMean = std::numeric_limits<double>::quiet_NaN();
3399
0
            }
3400
0
        }
3401
0
        else
3402
0
        {
3403
0
            const double delta = dfVal - dfMean;
3404
0
            if (CPL_UNLIKELY(std::isinf(delta)))
3405
0
                dfMean += dfVal / nValidSources - dfMean / nValidSources;
3406
0
            else
3407
0
                dfMean += delta / nValidSources;
3408
0
        }
3409
0
    }
3410
3411
    bool HasValue() const
3412
0
    {
3413
0
        return nValidSources > 0;
3414
0
    }
3415
3416
    double GetValue() const
3417
0
    {
3418
0
        return dfMean;
3419
0
    }
3420
};
3421
3422
struct GeoMeanKernel
3423
{
3424
    static constexpr const char *pszName = "geometric_mean";
3425
3426
    double dfProduct = 1;
3427
    int nValidSources = 0;
3428
3429
    void Reset()
3430
0
    {
3431
0
        dfProduct = 1;
3432
0
        nValidSources = 0;
3433
0
    }
3434
3435
    static CPLErr ProcessArguments(CSLConstList)
3436
0
    {
3437
0
        return CE_None;
3438
0
    }
3439
3440
    void ProcessPixel(double dfVal)
3441
0
    {
3442
0
        dfProduct *= dfVal;
3443
0
        nValidSources++;
3444
0
    }
3445
3446
    bool HasValue() const
3447
0
    {
3448
0
        return nValidSources > 0;
3449
0
    }
3450
3451
    double GetValue() const
3452
0
    {
3453
0
        return std::pow(dfProduct, 1.0 / nValidSources);
3454
0
    }
3455
};
3456
3457
struct HarmonicMeanKernel
3458
{
3459
    static constexpr const char *pszName = "harmonic_mean";
3460
3461
    double dfDenom = 0;
3462
    int nValidSources = 0;
3463
    bool bValueIsZero = false;
3464
    bool bPropagateZero = false;
3465
3466
    void Reset()
3467
0
    {
3468
0
        dfDenom = 0;
3469
0
        nValidSources = 0;
3470
0
        bValueIsZero = false;
3471
0
    }
3472
3473
    void ProcessPixel(double dfVal)
3474
0
    {
3475
0
        if (dfVal == 0)
3476
0
        {
3477
0
            bValueIsZero = true;
3478
0
        }
3479
0
        else
3480
0
        {
3481
0
            dfDenom += 1 / dfVal;
3482
0
        }
3483
0
        nValidSources++;
3484
0
    }
3485
3486
    CPLErr ProcessArguments(CSLConstList papszArgs)
3487
0
    {
3488
0
        bPropagateZero =
3489
0
            CPLTestBool(CSLFetchNameValueDef(papszArgs, "propagateZero", "0"));
3490
0
        return CE_None;
3491
0
    }
3492
3493
    bool HasValue() const
3494
0
    {
3495
0
        return dfDenom > 0 && (bPropagateZero || !bValueIsZero);
3496
0
    }
3497
3498
    double GetValue() const
3499
0
    {
3500
0
        if (bPropagateZero && bValueIsZero)
3501
0
        {
3502
0
            return 0;
3503
0
        }
3504
0
        return static_cast<double>(nValidSources) / dfDenom;
3505
0
    }
3506
};
3507
3508
struct MedianKernel
3509
{
3510
    static constexpr const char *pszName = "median";
3511
3512
    mutable std::vector<double> values{};
3513
3514
    void Reset()
3515
0
    {
3516
0
        values.clear();
3517
0
    }
3518
3519
    static CPLErr ProcessArguments(CSLConstList)
3520
0
    {
3521
0
        return CE_None;
3522
0
    }
3523
3524
    void ProcessPixel(double dfVal)
3525
0
    {
3526
0
        if (!std::isnan(dfVal))
3527
0
        {
3528
0
            values.push_back(dfVal);
3529
0
        }
3530
0
    }
3531
3532
    bool HasValue() const
3533
0
    {
3534
0
        return !values.empty();
3535
0
    }
3536
3537
    double GetValue() const
3538
0
    {
3539
0
        std::sort(values.begin(), values.end());
3540
0
        if (values.size() % 2 == 0)
3541
0
        {
3542
0
            return 0.5 *
3543
0
                   (values[values.size() / 2 - 1] + values[values.size() / 2]);
3544
0
        }
3545
3546
0
        return values[values.size() / 2];
3547
0
    }
3548
};
3549
3550
struct QuantileKernel
3551
{
3552
    static constexpr const char *pszName = "quantile";
3553
3554
    mutable std::vector<double> values{};
3555
    double q = 0.5;
3556
3557
    void Reset()
3558
0
    {
3559
0
        values.clear();
3560
        // q intentionally preserved (set via ProcessArguments)
3561
0
    }
3562
3563
    CPLErr ProcessArguments(CSLConstList papszArgs)
3564
0
    {
3565
0
        const char *pszQ = CSLFetchNameValue(papszArgs, "q");
3566
0
        if (pszQ)
3567
0
        {
3568
0
            char *end;
3569
0
            const double dq = CPLStrtod(pszQ, &end);
3570
0
            while (isspace(*end))
3571
0
            {
3572
0
                end++;
3573
0
            }
3574
0
            if (*end != '\0' || dq < 0.0 || dq > 1.0 || std::isnan(dq))
3575
0
            {
3576
0
                CPLError(CE_Failure, CPLE_AppDefined,
3577
0
                         "quantile: q must be between 0 and 1");
3578
0
                return CE_Failure;
3579
0
            }
3580
0
            q = dq;
3581
0
        }
3582
0
        else
3583
0
        {
3584
0
            CPLError(CE_Failure, CPLE_AppDefined,
3585
0
                     "quantile: q must be specified");
3586
0
            return CE_Failure;
3587
0
        }
3588
0
        return CE_None;
3589
0
    }
3590
3591
    void ProcessPixel(double dfVal)
3592
0
    {
3593
0
        if (!std::isnan(dfVal))
3594
0
        {
3595
0
            values.push_back(dfVal);
3596
0
        }
3597
0
    }
3598
3599
    bool HasValue() const
3600
0
    {
3601
0
        return !values.empty();
3602
0
    }
3603
3604
    double GetValue() const
3605
0
    {
3606
0
        if (values.empty())
3607
0
        {
3608
0
            return std::numeric_limits<double>::quiet_NaN();
3609
0
        }
3610
3611
0
        std::sort(values.begin(), values.end());
3612
0
        const double loc = q * static_cast<double>(values.size() - 1);
3613
3614
        // Use formula from NumPy docs with default linear interpolation
3615
        // g: fractional component of loc
3616
        // j: integral component of loc
3617
0
        double j;
3618
0
        const double g = std::modf(loc, &j);
3619
3620
0
        if (static_cast<size_t>(j) + 1 == values.size())
3621
0
        {
3622
0
            return values[static_cast<size_t>(j)];
3623
0
        }
3624
3625
0
        return (1 - g) * values[static_cast<size_t>(j)] +
3626
0
               g * values[static_cast<size_t>(j) + 1];
3627
0
    }
3628
};
3629
3630
struct ModeKernel
3631
{
3632
    static constexpr const char *pszName = "mode";
3633
3634
    std::map<double, size_t> counts{};
3635
    std::size_t nanCount{0};
3636
    double dfMax = std::numeric_limits<double>::quiet_NaN();
3637
    decltype(counts.begin()) oMax = counts.end();
3638
3639
    void Reset()
3640
0
    {
3641
0
        nanCount = 0;
3642
0
        counts.clear();
3643
0
        oMax = counts.end();
3644
0
    }
3645
3646
    static CPLErr ProcessArguments(CSLConstList)
3647
0
    {
3648
0
        return CE_None;
3649
0
    }
3650
3651
    void ProcessPixel(double dfVal)
3652
0
    {
3653
0
        if (std::isnan(dfVal))
3654
0
        {
3655
0
            nanCount += 1;
3656
0
            return;
3657
0
        }
3658
3659
        // if dfVal is NaN, try_emplace will return an entry for a different key!
3660
0
        auto [it, inserted] = counts.try_emplace(dfVal, 0);
3661
3662
0
        it->second += 1;
3663
3664
0
        if (oMax == counts.end() || it->second > oMax->second)
3665
0
        {
3666
0
            oMax = it;
3667
0
        }
3668
0
    }
3669
3670
    bool HasValue() const
3671
0
    {
3672
0
        return nanCount > 0 || oMax != counts.end();
3673
0
    }
3674
3675
    double GetValue() const
3676
0
    {
3677
0
        double ret = std::numeric_limits<double>::quiet_NaN();
3678
0
        if (oMax != counts.end())
3679
0
        {
3680
0
            const size_t nCount = oMax->second;
3681
0
            if (nCount > nanCount)
3682
0
                ret = oMax->first;
3683
0
        }
3684
0
        return ret;
3685
0
    }
3686
};
3687
3688
static const char pszBasicPixelFuncMetadata[] =
3689
    "<PixelFunctionArgumentsList>"
3690
    "   <Argument type='builtin' value='NoData' optional='true' />"
3691
    "   <Argument name='propagateNoData' description='Whether the output value "
3692
    "should be NoData as as soon as one source is NoData' type='boolean' "
3693
    "default='false' />"
3694
    "</PixelFunctionArgumentsList>";
3695
3696
static const char pszQuantilePixelFuncMetadata[] =
3697
    "<PixelFunctionArgumentsList>"
3698
    "   <Argument name='q' type='float' description='Quantile in [0,1]' />"
3699
    "   <Argument type='builtin' value='NoData' optional='true' />"
3700
    "   <Argument name='propagateNoData' type='boolean' default='false' />"
3701
    "</PixelFunctionArgumentsList>";
3702
3703
#if defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3704
inline __m128i packus_epi32(__m128i low, __m128i high)
3705
0
{
3706
#if __SSE4_1__
3707
    return _mm_packus_epi32(low, high);  // Pack uint32 to uint16
3708
#else
3709
0
    low = _mm_add_epi32(low, _mm_set1_epi32(-32768));
3710
0
    high = _mm_add_epi32(high, _mm_set1_epi32(-32768));
3711
0
    return _mm_sub_epi16(_mm_packs_epi32(low, high), _mm_set1_epi16(-32768));
3712
0
#endif
3713
0
}
3714
#endif
3715
3716
#ifdef USE_SSE2
3717
3718
template <class T, class SSEWrapper>
3719
static void OptimizedMeanFloatSSE2(const void *const *papoSources, int nSources,
3720
                                   void *pData, int nXSize, int nYSize,
3721
                                   int nLineSpace)
3722
0
{
3723
0
    assert(nSources >= 1);
3724
0
    constexpr int VALUES_PER_REG =
3725
0
        static_cast<int>(sizeof(typename SSEWrapper::Vec) / sizeof(T));
3726
0
    const T invSources = static_cast<T>(1.0) / static_cast<T>(nSources);
3727
0
    const auto invSourcesSSE = SSEWrapper::Set1(invSources);
3728
0
    const auto signMaskSSE = SSEWrapper::Set1(static_cast<T>(-0.0));
3729
0
    const auto infSSE = SSEWrapper::Set1(std::numeric_limits<T>::infinity());
3730
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
3731
0
    {
3732
0
        T *CPL_RESTRICT pDest =
3733
0
            reinterpret_cast<T *>(static_cast<GByte *>(pData) +
3734
0
                                  static_cast<GSpacing>(nLineSpace) * iLine);
3735
0
        const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
3736
0
        int iCol = 0;
3737
0
        for (; iCol < nXSize - (2 * VALUES_PER_REG - 1);
3738
0
             iCol += 2 * VALUES_PER_REG)
3739
0
        {
3740
0
            auto reg0 = SSEWrapper::LoadU(
3741
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
3742
0
                iOffsetLine + iCol);
3743
0
            auto reg1 = SSEWrapper::LoadU(
3744
0
                static_cast<const T * CPL_RESTRICT>(papoSources[0]) +
3745
0
                iOffsetLine + iCol + VALUES_PER_REG);
3746
0
            for (int iSrc = 1; iSrc < nSources; ++iSrc)
3747
0
            {
3748
0
                const auto inputVal0 = SSEWrapper::LoadU(
3749
0
                    static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
3750
0
                    iOffsetLine + iCol);
3751
0
                const auto inputVal1 = SSEWrapper::LoadU(
3752
0
                    static_cast<const T * CPL_RESTRICT>(papoSources[iSrc]) +
3753
0
                    iOffsetLine + iCol + VALUES_PER_REG);
3754
0
                reg0 = SSEWrapper::Add(reg0, inputVal0);
3755
0
                reg1 = SSEWrapper::Add(reg1, inputVal1);
3756
0
            }
3757
0
            reg0 = SSEWrapper::Mul(reg0, invSourcesSSE);
3758
0
            reg1 = SSEWrapper::Mul(reg1, invSourcesSSE);
3759
3760
            // Detect infinity that could happen when summing huge
3761
            // values
3762
0
            if (SSEWrapper::MoveMask(SSEWrapper::Or(
3763
0
                    SSEWrapper::CmpEq(SSEWrapper::AndNot(signMaskSSE, reg0),
3764
0
                                      infSSE),
3765
0
                    SSEWrapper::CmpEq(SSEWrapper::AndNot(signMaskSSE, reg1),
3766
0
                                      infSSE))))
3767
0
            {
3768
0
                break;
3769
0
            }
3770
3771
0
            SSEWrapper::StoreU(pDest + iCol, reg0);
3772
0
            SSEWrapper::StoreU(pDest + iCol + VALUES_PER_REG, reg1);
3773
0
        }
3774
3775
        // Use numerically stable mean computation
3776
0
        for (; iCol < nXSize; ++iCol)
3777
0
        {
3778
0
            T mean = static_cast<const T * CPL_RESTRICT>(
3779
0
                papoSources[0])[iOffsetLine + iCol];
3780
0
            if (nSources >= 2)
3781
0
            {
3782
0
                T new_val = static_cast<const T * CPL_RESTRICT>(
3783
0
                    papoSources[1])[iOffsetLine + iCol];
3784
0
                if (CPL_UNLIKELY(std::isinf(new_val)))
3785
0
                {
3786
0
                    if (new_val == -mean)
3787
0
                    {
3788
0
                        pDest[iCol] = std::numeric_limits<T>::quiet_NaN();
3789
0
                        continue;
3790
0
                    }
3791
0
                }
3792
0
                else if (CPL_UNLIKELY(std::isinf(mean)))
3793
0
                {
3794
0
                    if (!std::isfinite(new_val))
3795
0
                    {
3796
0
                        pDest[iCol] = std::numeric_limits<T>::quiet_NaN();
3797
0
                        continue;
3798
0
                    }
3799
0
                }
3800
0
                else
3801
0
                {
3802
0
                    const T delta = new_val - mean;
3803
0
                    if (CPL_UNLIKELY(std::isinf(delta)))
3804
0
                        mean += new_val * static_cast<T>(0.5) -
3805
0
                                mean * static_cast<T>(0.5);
3806
0
                    else
3807
0
                        mean += delta * static_cast<T>(0.5);
3808
0
                }
3809
3810
0
                for (int iSrc = 2; iSrc < nSources; ++iSrc)
3811
0
                {
3812
0
                    new_val = static_cast<const T * CPL_RESTRICT>(
3813
0
                        papoSources[iSrc])[iOffsetLine + iCol];
3814
0
                    if (CPL_UNLIKELY(std::isinf(new_val)))
3815
0
                    {
3816
0
                        if (new_val == -mean)
3817
0
                        {
3818
0
                            mean = std::numeric_limits<T>::quiet_NaN();
3819
0
                            break;
3820
0
                        }
3821
0
                    }
3822
0
                    else if (CPL_UNLIKELY(std::isinf(mean)))
3823
0
                    {
3824
0
                        if (!std::isfinite(new_val))
3825
0
                        {
3826
0
                            mean = std::numeric_limits<T>::quiet_NaN();
3827
0
                            break;
3828
0
                        }
3829
0
                    }
3830
0
                    else
3831
0
                    {
3832
0
                        const T delta = new_val - mean;
3833
0
                        if (CPL_UNLIKELY(std::isinf(delta)))
3834
0
                            mean += new_val / static_cast<T>(iSrc + 1) -
3835
0
                                    mean / static_cast<T>(iSrc + 1);
3836
0
                        else
3837
0
                            mean += delta / static_cast<T>(iSrc + 1);
3838
0
                    }
3839
0
                }
3840
0
            }
3841
0
            pDest[iCol] = mean;
3842
0
        }
3843
0
    }
3844
0
}
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMeanFloatSSE2<float, (anonymous namespace)::SSEWrapperFloat>(void const* const*, int, void*, int, int, int)
Unexecuted instantiation: pixelfunctions.cpp:void OptimizedMeanFloatSSE2<double, (anonymous namespace)::SSEWrapperDouble>(void const* const*, int, void*, int, int, int)
3845
3846
// clang-format off
3847
namespace
3848
{
3849
#ifdef __AVX2__
3850
struct SSEWrapperFloat
3851
{
3852
    typedef __m256 Vec;
3853
3854
    static inline Vec Set1(float x) { return _mm256_set1_ps(x); }
3855
    static inline Vec LoadU(const float *x) { return _mm256_loadu_ps(x); }
3856
    static inline void StoreU(float *x, Vec y) { _mm256_storeu_ps(x, y); }
3857
    static inline Vec Add(Vec x, Vec y) { return _mm256_add_ps(x, y); }
3858
    static inline Vec Mul(Vec x, Vec y) { return _mm256_mul_ps(x, y); }
3859
    static inline Vec Or(Vec x, Vec y) { return _mm256_or_ps(x, y); }
3860
    static inline Vec AndNot(Vec x, Vec y) { return _mm256_andnot_ps(x, y); }
3861
    static inline Vec CmpEq(Vec x, Vec y) { return _mm256_cmp_ps(x, y, _CMP_EQ_OQ); }
3862
    static inline int MoveMask(Vec x) { return _mm256_movemask_ps(x); }
3863
};
3864
3865
struct SSEWrapperDouble
3866
{
3867
    typedef __m256d Vec;
3868
3869
    static inline Vec Set1(double x) { return _mm256_set1_pd(x); }
3870
    static inline Vec LoadU(const double *x) { return _mm256_loadu_pd(x); }
3871
    static inline void StoreU(double *x, Vec y) { _mm256_storeu_pd(x, y); }
3872
    static inline Vec Add(Vec x, Vec y) { return _mm256_add_pd(x, y); }
3873
    static inline Vec Mul(Vec x, Vec y) { return _mm256_mul_pd(x, y); }
3874
    static inline Vec Or(Vec x, Vec y) { return _mm256_or_pd(x, y); }
3875
    static inline Vec AndNot(Vec x, Vec y) { return _mm256_andnot_pd(x, y); }
3876
    static inline Vec CmpEq(Vec x, Vec y) { return _mm256_cmp_pd(x, y, _CMP_EQ_OQ); }
3877
    static inline int MoveMask(Vec x) { return _mm256_movemask_pd(x); }
3878
};
3879
3880
#else
3881
3882
struct SSEWrapperFloat
3883
{
3884
    typedef __m128 Vec;
3885
3886
0
    static inline Vec Set1(float x) { return _mm_set1_ps(x); }
3887
0
    static inline Vec LoadU(const float *x) { return _mm_loadu_ps(x); }
3888
0
    static inline void StoreU(float *x, Vec y) { _mm_storeu_ps(x, y); }
3889
0
    static inline Vec Add(Vec x, Vec y) { return _mm_add_ps(x, y); }
3890
0
    static inline Vec Mul(Vec x, Vec y) { return _mm_mul_ps(x, y); }
3891
0
    static inline Vec Or(Vec x, Vec y) { return _mm_or_ps(x, y); }
3892
0
    static inline Vec AndNot(Vec x, Vec y) { return _mm_andnot_ps(x, y); }
3893
0
    static inline Vec CmpEq(Vec x, Vec y) { return _mm_cmpeq_ps(x, y); }
3894
0
    static inline int MoveMask(Vec x) { return _mm_movemask_ps(x); }
3895
};
3896
3897
struct SSEWrapperDouble
3898
{
3899
    typedef __m128d Vec;
3900
3901
0
    static inline Vec Set1(double x) { return _mm_set1_pd(x); }
3902
0
    static inline Vec LoadU(const double *x) { return _mm_loadu_pd(x); }
3903
0
    static inline void StoreU(double *x, Vec y) { _mm_storeu_pd(x, y); }
3904
0
    static inline Vec Add(Vec x, Vec y) { return _mm_add_pd(x, y); }
3905
0
    static inline Vec Mul(Vec x, Vec y) { return _mm_mul_pd(x, y); }
3906
0
    static inline Vec Or(Vec x, Vec y) { return _mm_or_pd(x, y); }
3907
0
    static inline Vec AndNot(Vec x, Vec y) { return _mm_andnot_pd(x, y); }
3908
0
    static inline Vec CmpEq(Vec x, Vec y) { return _mm_cmpeq_pd(x, y); }
3909
0
    static inline int MoveMask(Vec x) { return _mm_movemask_pd(x); }
3910
};
3911
#endif
3912
}  // namespace
3913
3914
// clang-format on
3915
3916
#endif  // USE_SSE2
3917
3918
template <typename Kernel>
3919
static CPLErr BasicPixelFunc(void **papoSources, int nSources, void *pData,
3920
                             int nXSize, int nYSize, GDALDataType eSrcType,
3921
                             GDALDataType eBufType, int nPixelSpace,
3922
                             int nLineSpace, CSLConstList papszArgs)
3923
0
{
3924
    /* ---- Init ---- */
3925
0
    Kernel oKernel;
3926
3927
0
    if (GDALDataTypeIsComplex(eSrcType))
3928
0
    {
3929
0
        CPLError(CE_Failure, CPLE_AppDefined,
3930
0
                 "Complex data types not supported by %s", oKernel.pszName);
3931
0
        return CE_Failure;
3932
0
    }
3933
3934
0
    double dfNoData{0};
3935
0
    const bool bHasNoData = CSLFindName(papszArgs, "NoData") != -1;
3936
0
    if (bHasNoData && FetchDoubleArg(papszArgs, "NoData", &dfNoData) != CE_None)
3937
0
        return CE_Failure;
3938
3939
0
    const bool bPropagateNoData = CPLTestBool(
3940
0
        CSLFetchNameValueDef(papszArgs, "propagateNoData", "false"));
3941
3942
0
    if (oKernel.ProcessArguments(papszArgs) == CE_Failure)
3943
0
    {
3944
0
        return CE_Failure;
3945
0
    }
3946
3947
0
#if defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
3948
    if constexpr (std::is_same_v<Kernel, MeanKernel>)
3949
0
    {
3950
0
        if (!bHasNoData && eSrcType == GDT_UInt8 && eBufType == GDT_UInt8 &&
3951
0
            nPixelSpace == 1 &&
3952
            // We use signed int16 to accumulate
3953
0
            nSources <= std::numeric_limits<int16_t>::max() /
3954
0
                            std::numeric_limits<uint8_t>::max())
3955
0
        {
3956
0
            using T = uint8_t;
3957
0
            constexpr int VALUES_PER_REG = 16;
3958
0
            if (nSources == 2)
3959
0
            {
3960
0
                for (int iLine = 0; iLine < nYSize; ++iLine)
3961
0
                {
3962
0
                    T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
3963
0
                        static_cast<GByte *>(pData) +
3964
0
                        static_cast<GSpacing>(nLineSpace) * iLine);
3965
0
                    const size_t iOffsetLine =
3966
0
                        static_cast<size_t>(iLine) * nXSize;
3967
0
                    int iCol = 0;
3968
0
                    for (; iCol < nXSize - (VALUES_PER_REG - 1);
3969
0
                         iCol += VALUES_PER_REG)
3970
0
                    {
3971
0
                        const __m128i inputVal0 =
3972
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3973
0
                                static_cast<const T * CPL_RESTRICT>(
3974
0
                                    papoSources[0]) +
3975
0
                                iOffsetLine + iCol));
3976
0
                        const __m128i inputVal1 =
3977
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
3978
0
                                static_cast<const T * CPL_RESTRICT>(
3979
0
                                    papoSources[1]) +
3980
0
                                iOffsetLine + iCol));
3981
0
                        _mm_storeu_si128(
3982
0
                            reinterpret_cast<__m128i *>(pDest + iCol),
3983
0
                            _mm_avg_epu8(inputVal0, inputVal1));
3984
0
                    }
3985
0
                    for (; iCol < nXSize; ++iCol)
3986
0
                    {
3987
0
                        uint32_t acc = 1 +
3988
0
                                       static_cast<const T * CPL_RESTRICT>(
3989
0
                                           papoSources[0])[iOffsetLine + iCol] +
3990
0
                                       static_cast<const T * CPL_RESTRICT>(
3991
0
                                           papoSources[1])[iOffsetLine + iCol];
3992
0
                        pDest[iCol] = static_cast<T>(acc / 2);
3993
0
                    }
3994
0
                }
3995
0
            }
3996
0
            else
3997
0
            {
3998
0
                libdivide::divider<uint16_t> fast_d(
3999
0
                    static_cast<uint16_t>(nSources));
4000
0
                const auto halfConstant =
4001
0
                    _mm_set1_epi16(static_cast<int16_t>(nSources / 2));
4002
0
                for (int iLine = 0; iLine < nYSize; ++iLine)
4003
0
                {
4004
0
                    T *CPL_RESTRICT pDest =
4005
0
                        static_cast<GByte *>(pData) +
4006
0
                        static_cast<GSpacing>(nLineSpace) * iLine;
4007
0
                    const size_t iOffsetLine =
4008
0
                        static_cast<size_t>(iLine) * nXSize;
4009
0
                    int iCol = 0;
4010
0
                    for (; iCol < nXSize - (VALUES_PER_REG - 1);
4011
0
                         iCol += VALUES_PER_REG)
4012
0
                    {
4013
0
                        __m128i reg0 = halfConstant;
4014
0
                        __m128i reg1 = halfConstant;
4015
0
                        for (int iSrc = 0; iSrc < nSources; ++iSrc)
4016
0
                        {
4017
0
                            const __m128i inputVal = _mm_loadu_si128(
4018
0
                                reinterpret_cast<const __m128i *>(
4019
0
                                    static_cast<const T * CPL_RESTRICT>(
4020
0
                                        papoSources[iSrc]) +
4021
0
                                    iOffsetLine + iCol));
4022
0
                            reg0 = _mm_add_epi16(
4023
0
                                reg0, _mm_unpacklo_epi8(inputVal,
4024
0
                                                        _mm_setzero_si128()));
4025
0
                            reg1 = _mm_add_epi16(
4026
0
                                reg1, _mm_unpackhi_epi8(inputVal,
4027
0
                                                        _mm_setzero_si128()));
4028
0
                        }
4029
0
                        reg0 /= fast_d;
4030
0
                        reg1 /= fast_d;
4031
0
                        _mm_storeu_si128(
4032
0
                            reinterpret_cast<__m128i *>(pDest + iCol),
4033
0
                            _mm_packus_epi16(reg0, reg1));
4034
0
                    }
4035
0
                    for (; iCol < nXSize; ++iCol)
4036
0
                    {
4037
0
                        uint32_t acc = nSources / 2;
4038
0
                        for (int iSrc = 0; iSrc < nSources; ++iSrc)
4039
0
                        {
4040
0
                            acc += static_cast<const T * CPL_RESTRICT>(
4041
0
                                papoSources[iSrc])[iOffsetLine + iCol];
4042
0
                        }
4043
0
                        pDest[iCol] = static_cast<T>(acc / nSources);
4044
0
                    }
4045
0
                }
4046
0
            }
4047
0
            return CE_None;
4048
0
        }
4049
4050
0
        if (!bHasNoData && eSrcType == GDT_UInt8 && eBufType == GDT_UInt8 &&
4051
0
            nPixelSpace == 1 &&
4052
            // We use signed int32 to accumulate
4053
0
            nSources <= std::numeric_limits<int32_t>::max() /
4054
0
                            std::numeric_limits<uint8_t>::max())
4055
0
        {
4056
0
            using T = uint8_t;
4057
0
            constexpr int VALUES_PER_REG = 16;
4058
0
            libdivide::divider<uint32_t> fast_d(nSources);
4059
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
4060
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
4061
0
            {
4062
0
                T *CPL_RESTRICT pDest =
4063
0
                    static_cast<GByte *>(pData) +
4064
0
                    static_cast<GSpacing>(nLineSpace) * iLine;
4065
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
4066
0
                int iCol = 0;
4067
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
4068
0
                     iCol += VALUES_PER_REG)
4069
0
                {
4070
0
                    __m128i reg0 = halfConstant;
4071
0
                    __m128i reg1 = halfConstant;
4072
0
                    __m128i reg2 = halfConstant;
4073
0
                    __m128i reg3 = halfConstant;
4074
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
4075
0
                    {
4076
0
                        const __m128i inputVal =
4077
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
4078
0
                                static_cast<const T * CPL_RESTRICT>(
4079
0
                                    papoSources[iSrc]) +
4080
0
                                iOffsetLine + iCol));
4081
0
                        const __m128i low =
4082
0
                            _mm_unpacklo_epi8(inputVal, _mm_setzero_si128());
4083
0
                        const __m128i high =
4084
0
                            _mm_unpackhi_epi8(inputVal, _mm_setzero_si128());
4085
0
                        reg0 = _mm_add_epi32(
4086
0
                            reg0, _mm_unpacklo_epi16(low, _mm_setzero_si128()));
4087
0
                        reg1 = _mm_add_epi32(
4088
0
                            reg1, _mm_unpackhi_epi16(low, _mm_setzero_si128()));
4089
0
                        reg2 = _mm_add_epi32(
4090
0
                            reg2,
4091
0
                            _mm_unpacklo_epi16(high, _mm_setzero_si128()));
4092
0
                        reg3 = _mm_add_epi32(
4093
0
                            reg3,
4094
0
                            _mm_unpackhi_epi16(high, _mm_setzero_si128()));
4095
0
                    }
4096
0
                    reg0 /= fast_d;
4097
0
                    reg1 /= fast_d;
4098
0
                    reg2 /= fast_d;
4099
0
                    reg3 /= fast_d;
4100
0
                    _mm_storeu_si128(
4101
0
                        reinterpret_cast<__m128i *>(pDest + iCol),
4102
0
                        _mm_packus_epi16(packus_epi32(reg0, reg1),
4103
0
                                         packus_epi32(reg2, reg3)));
4104
0
                }
4105
0
                for (; iCol < nXSize; ++iCol)
4106
0
                {
4107
0
                    uint32_t acc = nSources / 2;
4108
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
4109
0
                    {
4110
0
                        acc += static_cast<const T * CPL_RESTRICT>(
4111
0
                            papoSources[iSrc])[iOffsetLine + iCol];
4112
0
                    }
4113
0
                    pDest[iCol] = static_cast<T>(acc / nSources);
4114
0
                }
4115
0
            }
4116
0
            return CE_None;
4117
0
        }
4118
4119
0
        if (!bHasNoData && eSrcType == GDT_UInt16 && eBufType == GDT_UInt16 &&
4120
0
            nPixelSpace == 2 &&
4121
0
            nSources <= std::numeric_limits<int32_t>::max() /
4122
0
                            std::numeric_limits<uint16_t>::max())
4123
0
        {
4124
0
            libdivide::divider<uint32_t> fast_d(nSources);
4125
0
            using T = uint16_t;
4126
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
4127
0
            constexpr int VALUES_PER_REG = 8;
4128
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
4129
0
            {
4130
0
                T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
4131
0
                    static_cast<GByte *>(pData) +
4132
0
                    static_cast<GSpacing>(nLineSpace) * iLine);
4133
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
4134
0
                int iCol = 0;
4135
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
4136
0
                     iCol += VALUES_PER_REG)
4137
0
                {
4138
0
                    __m128i reg0 = halfConstant;
4139
0
                    __m128i reg1 = halfConstant;
4140
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
4141
0
                    {
4142
0
                        const __m128i inputVal =
4143
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
4144
0
                                static_cast<const T * CPL_RESTRICT>(
4145
0
                                    papoSources[iSrc]) +
4146
0
                                iOffsetLine + iCol));
4147
0
                        reg0 = _mm_add_epi32(
4148
0
                            reg0,
4149
0
                            _mm_unpacklo_epi16(inputVal, _mm_setzero_si128()));
4150
0
                        reg1 = _mm_add_epi32(
4151
0
                            reg1,
4152
0
                            _mm_unpackhi_epi16(inputVal, _mm_setzero_si128()));
4153
0
                    }
4154
0
                    reg0 /= fast_d;
4155
0
                    reg1 /= fast_d;
4156
0
                    _mm_storeu_si128(reinterpret_cast<__m128i *>(pDest + iCol),
4157
0
                                     packus_epi32(reg0, reg1));
4158
0
                }
4159
0
                for (; iCol < nXSize; ++iCol)
4160
0
                {
4161
0
                    uint32_t acc = nSources / 2;
4162
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
4163
0
                    {
4164
0
                        acc += static_cast<const T * CPL_RESTRICT>(
4165
0
                            papoSources[iSrc])[iOffsetLine + iCol];
4166
0
                    }
4167
0
                    pDest[iCol] = static_cast<T>(acc / nSources);
4168
0
                }
4169
0
            }
4170
0
            return CE_None;
4171
0
        }
4172
4173
0
        if (!bHasNoData && eSrcType == GDT_Int16 && eBufType == GDT_Int16 &&
4174
0
            nPixelSpace == 2 &&
4175
0
            nSources <= std::numeric_limits<int32_t>::max() /
4176
0
                            std::numeric_limits<uint16_t>::max())
4177
0
        {
4178
0
            libdivide::divider<uint32_t> fast_d(nSources);
4179
0
            using T = int16_t;
4180
0
            const auto halfConstant = _mm_set1_epi32(nSources / 2);
4181
0
            const auto shift = _mm_set1_epi16(std::numeric_limits<T>::min());
4182
0
            constexpr int VALUES_PER_REG = 8;
4183
0
            for (int iLine = 0; iLine < nYSize; ++iLine)
4184
0
            {
4185
0
                T *CPL_RESTRICT pDest = reinterpret_cast<T *>(
4186
0
                    static_cast<GByte *>(pData) +
4187
0
                    static_cast<GSpacing>(nLineSpace) * iLine);
4188
0
                const size_t iOffsetLine = static_cast<size_t>(iLine) * nXSize;
4189
0
                int iCol = 0;
4190
0
                for (; iCol < nXSize - (VALUES_PER_REG - 1);
4191
0
                     iCol += VALUES_PER_REG)
4192
0
                {
4193
0
                    __m128i reg0 = halfConstant;
4194
0
                    __m128i reg1 = halfConstant;
4195
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
4196
0
                    {
4197
                        // Shift input values by 32768 to get unsigned values
4198
0
                        const __m128i inputVal = _mm_add_epi16(
4199
0
                            _mm_loadu_si128(reinterpret_cast<const __m128i *>(
4200
0
                                static_cast<const T * CPL_RESTRICT>(
4201
0
                                    papoSources[iSrc]) +
4202
0
                                iOffsetLine + iCol)),
4203
0
                            shift);
4204
0
                        reg0 = _mm_add_epi32(
4205
0
                            reg0,
4206
0
                            _mm_unpacklo_epi16(inputVal, _mm_setzero_si128()));
4207
0
                        reg1 = _mm_add_epi32(
4208
0
                            reg1,
4209
0
                            _mm_unpackhi_epi16(inputVal, _mm_setzero_si128()));
4210
0
                    }
4211
0
                    reg0 /= fast_d;
4212
0
                    reg1 /= fast_d;
4213
0
                    _mm_storeu_si128(
4214
0
                        reinterpret_cast<__m128i *>(pDest + iCol),
4215
0
                        _mm_add_epi16(packus_epi32(reg0, reg1), shift));
4216
0
                }
4217
0
                for (; iCol < nXSize; ++iCol)
4218
0
                {
4219
0
                    int32_t acc = (-std::numeric_limits<T>::min()) * nSources +
4220
0
                                  nSources / 2;
4221
0
                    for (int iSrc = 0; iSrc < nSources; ++iSrc)
4222
0
                    {
4223
0
                        acc += static_cast<const T * CPL_RESTRICT>(
4224
0
                            papoSources[iSrc])[iOffsetLine + iCol];
4225
0
                    }
4226
0
                    pDest[iCol] = static_cast<T>(acc / nSources +
4227
0
                                                 std::numeric_limits<T>::min());
4228
0
                }
4229
0
            }
4230
0
            return CE_None;
4231
0
        }
4232
0
    }
4233
0
#endif  // defined(USE_SSE2) && !defined(USE_NEON_OPTIMIZATIONS)
4234
4235
0
#if defined(USE_SSE2)
4236
    if constexpr (std::is_same_v<Kernel, MeanKernel>)
4237
0
    {
4238
0
        if (!bHasNoData && eSrcType == GDT_Float32 && eBufType == GDT_Float32 &&
4239
0
            nPixelSpace == 4 && nSources > 0)
4240
0
        {
4241
0
            OptimizedMeanFloatSSE2<float, SSEWrapperFloat>(
4242
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
4243
0
            return CE_None;
4244
0
        }
4245
4246
0
        if (!bHasNoData && eSrcType == GDT_Float64 && eBufType == GDT_Float64 &&
4247
0
            nPixelSpace == 8 && nSources > 0)
4248
0
        {
4249
0
            OptimizedMeanFloatSSE2<double, SSEWrapperDouble>(
4250
0
                papoSources, nSources, pData, nXSize, nYSize, nLineSpace);
4251
0
            return CE_None;
4252
0
        }
4253
0
    }
4254
0
#endif  // USE_SSE2
4255
4256
    /* ---- Set pixels ---- */
4257
0
    size_t ii = 0;
4258
0
    for (int iLine = 0; iLine < nYSize; ++iLine)
4259
0
    {
4260
0
        for (int iCol = 0; iCol < nXSize; ++iCol, ++ii)
4261
0
        {
4262
0
            oKernel.Reset();
4263
0
            bool bWriteNoData = false;
4264
4265
0
            for (int iSrc = 0; iSrc < nSources; ++iSrc)
4266
0
            {
4267
0
                const double dfVal = GetSrcVal(papoSources[iSrc], eSrcType, ii);
4268
4269
0
                if (bHasNoData && IsNoData(dfVal, dfNoData))
4270
0
                {
4271
0
                    if (bPropagateNoData)
4272
0
                    {
4273
0
                        bWriteNoData = true;
4274
0
                        break;
4275
0
                    }
4276
0
                }
4277
0
                else
4278
0
                {
4279
0
                    oKernel.ProcessPixel(dfVal);
4280
0
                }
4281
0
            }
4282
4283
0
            double dfPixVal{dfNoData};
4284
0
            if (!bWriteNoData && oKernel.HasValue())
4285
0
            {
4286
0
                dfPixVal = oKernel.GetValue();
4287
0
            }
4288
4289
0
            GDALCopyWords(&dfPixVal, GDT_Float64, 0,
4290
0
                          static_cast<GByte *>(pData) +
4291
0
                              static_cast<GSpacing>(nLineSpace) * iLine +
4292
0
                              iCol * nPixelSpace,
4293
0
                          eBufType, nPixelSpace, 1);
4294
0
        }
4295
0
    }
4296
4297
    /* ---- Return success ---- */
4298
0
    return CE_None;
4299
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<QuantileKernel>(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*)
4300
4301
/************************************************************************/
4302
/*                    GDALRegisterDefaultPixelFunc()                    */
4303
/************************************************************************/
4304
4305
/**
4306
 * This adds a default set of pixel functions to the global list of
4307
 * available pixel functions for derived bands:
4308
 *
4309
 * - "real": extract real part from a single raster band (just a copy if the
4310
 *           input is non-complex)
4311
 * - "imag": extract imaginary part from a single raster band (0 for
4312
 *           non-complex)
4313
 * - "complex": make a complex band merging two bands used as real and
4314
 *              imag values
4315
 * - "polar": make a complex band using input bands for amplitude and
4316
 *            phase values (b1 * exp( j * b2 ))
4317
 * - "mod": extract module from a single raster band (real or complex)
4318
 * - "phase": extract phase from a single raster band [-PI,PI] (0 or PI for
4319
              non-complex)
4320
 * - "conj": computes the complex conjugate of a single raster band (just a
4321
 *           copy if the input is non-complex)
4322
 * - "sum": sum 2 or more raster bands
4323
 * - "diff": computes the difference between 2 raster bands (b1 - b2)
4324
 * - "mul": multiply 2 or more raster bands
4325
 * - "div": divide one raster band by another (b1 / b2).
4326
 * - "min": minimum value of 2 or more raster bands
4327
 * - "max": maximum value of 2 or more raster bands
4328
 * - "norm_diff": computes the normalized difference between two raster bands:
4329
 *                ``(b1 - b2)/(b1 + b2)``.
4330
 * - "cmul": multiply the first band for the complex conjugate of the second
4331
 * - "inv": inverse (1./x).
4332
 * - "intensity": computes the intensity Re(x*conj(x)) of a single raster band
4333
 *                (real or complex)
4334
 * - "sqrt": perform the square root of a single raster band (real only)
4335
 * - "log10": compute the logarithm (base 10) of the abs of a single raster
4336
 *            band (real or complex): log10( abs( x ) )
4337
 * - "dB": perform conversion to dB of the abs of a single raster
4338
 *         band (real or complex): 20. * log10( abs( x ) ).
4339
 *         Note: the optional fact parameter can be set to 10. to get the
4340
 *         alternative formula: 10. * log10( abs( x ) )
4341
 * - "exp": computes the exponential of each element in the input band ``x``
4342
 *          (of real values): ``e ^ x``.
4343
 *          The function also accepts two optional parameters: ``base`` and
4344
 ``fact``
4345
 *          that allow to compute the generalized formula: ``base ^ ( fact *
4346
 x)``.
4347
 *          Note: this function is the recommended one to perform conversion
4348
 *          form logarithmic scale (dB): `` 10. ^ (x / 20.)``, in this case
4349
 *          ``base = 10.`` and ``fact = 1./20``
4350
 * - "dB2amp": perform scale conversion from logarithmic to linear
4351
 *             (amplitude) (i.e. 10 ^ ( x / 20 ) ) of a single raster
4352
 *             band (real only).
4353
 *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
4354
 with
4355
 *             ``base = 10.`` and ``fact = 0.05`` i.e. ``1./20``
4356
 * - "dB2pow": perform scale conversion from logarithmic to linear
4357
 *             (power) (i.e. 10 ^ ( x / 10 ) ) of a single raster
4358
 *             band (real only)
4359
 *             Deprecated in GDAL v3.5. Please use the ``exp`` pixel function
4360
 with
4361
 *             ``base = 10.`` and ``fact = 0.1`` i.e. ``1./10``
4362
 * - "pow": raise a single raster band to a constant power
4363
 * - "interpolate_linear": interpolate values between two raster bands
4364
 *                         using linear interpolation
4365
 * - "interpolate_exp": interpolate values between two raster bands using
4366
 *                      exponential interpolation
4367
 * - "scale": Apply the RasterBand metadata values of "offset" and "scale"
4368
 * - "reclassify": Reclassify values matching ranges in a table
4369
 * - "nan": Convert incoming NoData values to IEEE 754 nan
4370
 *
4371
 * @see GDALAddDerivedBandPixelFunc
4372
 *
4373
 * @return CE_None
4374
 */
4375
CPLErr GDALRegisterDefaultPixelFunc()
4376
0
{
4377
0
    GDALAddDerivedBandPixelFunc("real", RealPixelFunc);
4378
0
    GDALAddDerivedBandPixelFunc("imag", ImagPixelFunc);
4379
0
    GDALAddDerivedBandPixelFunc("complex", ComplexPixelFunc);
4380
0
    GDALAddDerivedBandPixelFuncWithArgs("polar", PolarPixelFunc,
4381
0
                                        pszPolarPixelFuncMetadata);
4382
0
    GDALAddDerivedBandPixelFuncWithArgs("mod", ModulePixelFunc,
4383
0
                                        pszModulePixelFuncMetadata);
4384
0
    GDALAddDerivedBandPixelFuncWithArgs("abs", ModulePixelFunc,
4385
0
                                        pszModulePixelFuncMetadata);
4386
0
    GDALAddDerivedBandPixelFunc("phase", PhasePixelFunc);
4387
0
    GDALAddDerivedBandPixelFunc("conj", ConjPixelFunc);
4388
0
    GDALAddDerivedBandPixelFuncWithArgs("sum", SumPixelFunc,
4389
0
                                        pszSumPixelFuncMetadata);
4390
0
    GDALAddDerivedBandPixelFuncWithArgs("diff", DiffPixelFunc,
4391
0
                                        pszDiffPixelFuncMetadata);
4392
0
    GDALAddDerivedBandPixelFuncWithArgs("mul", MulPixelFunc,
4393
0
                                        pszMulPixelFuncMetadata);
4394
0
    GDALAddDerivedBandPixelFuncWithArgs("div", DivPixelFunc,
4395
0
                                        pszDivPixelFuncMetadata);
4396
0
    GDALAddDerivedBandPixelFunc("cmul", CMulPixelFunc);
4397
0
    GDALAddDerivedBandPixelFuncWithArgs("inv", InvPixelFunc,
4398
0
                                        pszInvPixelFuncMetadata);
4399
0
    GDALAddDerivedBandPixelFunc("intensity", IntensityPixelFunc);
4400
0
    GDALAddDerivedBandPixelFuncWithArgs("sqrt", SqrtPixelFunc,
4401
0
                                        pszSqrtPixelFuncMetadata);
4402
0
    GDALAddDerivedBandPixelFuncWithArgs("log10", Log10PixelFunc,
4403
0
                                        pszLog10PixelFuncMetadata);
4404
0
    GDALAddDerivedBandPixelFuncWithArgs("dB", DBPixelFunc,
4405
0
                                        pszDBPixelFuncMetadata);
4406
0
    GDALAddDerivedBandPixelFuncWithArgs("exp", ExpPixelFunc,
4407
0
                                        pszExpPixelFuncMetadata);
4408
0
    GDALAddDerivedBandPixelFunc("dB2amp",
4409
0
                                dB2AmpPixelFunc);  // deprecated in v3.5
4410
0
    GDALAddDerivedBandPixelFunc("dB2pow",
4411
0
                                dB2PowPixelFunc);  // deprecated in v3.5
4412
0
    GDALAddDerivedBandPixelFuncWithArgs("pow", PowPixelFunc,
4413
0
                                        pszPowPixelFuncMetadata);
4414
0
    GDALAddDerivedBandPixelFuncWithArgs("interpolate_linear",
4415
0
                                        InterpolatePixelFunc<InterpolateLinear>,
4416
0
                                        pszInterpolatePixelFuncMetadata);
4417
0
    GDALAddDerivedBandPixelFuncWithArgs(
4418
0
        "interpolate_exp", InterpolatePixelFunc<InterpolateExponential>,
4419
0
        pszInterpolatePixelFuncMetadata);
4420
0
    GDALAddDerivedBandPixelFuncWithArgs("replace_nodata",
4421
0
                                        ReplaceNoDataPixelFunc,
4422
0
                                        pszReplaceNoDataPixelFuncMetadata);
4423
0
    GDALAddDerivedBandPixelFuncWithArgs("scale", ScalePixelFunc,
4424
0
                                        pszScalePixelFuncMetadata);
4425
0
    GDALAddDerivedBandPixelFuncWithArgs("norm_diff", NormDiffPixelFunc,
4426
0
                                        pszNormDiffPixelFuncMetadata);
4427
0
    GDALAddDerivedBandPixelFuncWithArgs("min", MinPixelFunc<ReturnValue>,
4428
0
                                        pszMinMaxFuncMetadataNodata);
4429
0
    GDALAddDerivedBandPixelFuncWithArgs("argmin", MinPixelFunc<ReturnIndex>,
4430
0
                                        pszArgMinMaxFuncMetadataNodata);
4431
0
    GDALAddDerivedBandPixelFuncWithArgs("max", MaxPixelFunc<ReturnValue>,
4432
0
                                        pszMinMaxFuncMetadataNodata);
4433
0
    GDALAddDerivedBandPixelFuncWithArgs("argmax", MaxPixelFunc<ReturnIndex>,
4434
0
                                        pszArgMinMaxFuncMetadataNodata);
4435
0
    GDALAddDerivedBandPixelFuncWithArgs("expression", ExprPixelFunc,
4436
0
                                        pszExprPixelFuncMetadata);
4437
0
    GDALAddDerivedBandPixelFuncWithArgs("reclassify", ReclassifyPixelFunc,
4438
0
                                        pszReclassifyPixelFuncMetadata);
4439
0
    GDALAddDerivedBandPixelFuncWithArgs("round", RoundPixelFunc,
4440
0
                                        pszRoundPixelFuncMetadata);
4441
0
    GDALAddDerivedBandPixelFuncWithArgs("mean", BasicPixelFunc<MeanKernel>,
4442
0
                                        pszBasicPixelFuncMetadata);
4443
0
    GDALAddDerivedBandPixelFuncWithArgs("geometric_mean",
4444
0
                                        BasicPixelFunc<GeoMeanKernel>,
4445
0
                                        pszBasicPixelFuncMetadata);
4446
0
    GDALAddDerivedBandPixelFuncWithArgs("harmonic_mean",
4447
0
                                        BasicPixelFunc<HarmonicMeanKernel>,
4448
0
                                        pszBasicPixelFuncMetadata);
4449
0
    GDALAddDerivedBandPixelFuncWithArgs("median", BasicPixelFunc<MedianKernel>,
4450
0
                                        pszBasicPixelFuncMetadata);
4451
0
    GDALAddDerivedBandPixelFuncWithArgs("quantile",
4452
0
                                        BasicPixelFunc<QuantileKernel>,
4453
0
                                        pszQuantilePixelFuncMetadata);
4454
0
    GDALAddDerivedBandPixelFuncWithArgs("mode", BasicPixelFunc<ModeKernel>,
4455
0
                                        pszBasicPixelFuncMetadata);
4456
0
    GDALAddDerivedBandPixelFuncWithArgs("area", AreaPixelFunc,
4457
0
                                        pszAreaPixelFuncMetadata);
4458
0
    return CE_None;
4459
0
}