Coverage Report

Created: 2026-02-14 06:52

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