Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdalrasterband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for format specific band class implementation.  This
5
 *           base class provides default implementation for many methods.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1998, Frank Warmerdam
10
 * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "cpl_float.h"
17
18
#include <cassert>
19
#include <climits>
20
#include <cmath>
21
#include <cstdarg>
22
#include <cstddef>
23
#include <cstdio>
24
#include <cstdlib>
25
#include <cstring>
26
#include <algorithm>
27
#include <limits>
28
#include <memory>
29
#include <new>
30
#include <numeric>  // std::lcm
31
#include <type_traits>
32
33
#include "cpl_conv.h"
34
#include "cpl_error.h"
35
#include "cpl_float.h"
36
#include "cpl_multiproc.h"
37
#include "cpl_progress.h"
38
#include "cpl_string.h"
39
#include "cpl_virtualmem.h"
40
#include "cpl_vsi.h"
41
#include "cpl_worker_thread_pool.h"
42
#include "gdal.h"
43
#include "gdal_abstractbandblockcache.h"
44
#include "gdalantirecursion.h"
45
#include "gdal_rat.h"
46
#include "gdal_rasterband.h"
47
#include "gdal_priv_templates.hpp"
48
#include "gdal_interpolateatpoint.h"
49
#include "gdal_minmax_element.hpp"
50
#include "gdalmultidim_priv.h"
51
#include "gdal_thread_pool.h"
52
53
#ifdef USE_NEON_OPTIMIZATIONS
54
#include "include_sse2neon.h"
55
#endif
56
57
#if defined(__AVX2__) || defined(__FMA__)
58
#include <immintrin.h>
59
#endif
60
61
/************************************************************************/
62
/*                           GDALRasterBand()                           */
63
/************************************************************************/
64
65
/*! Constructor. Applications should never create GDALRasterBands directly. */
66
67
GDALRasterBand::GDALRasterBand()
68
0
    : GDALRasterBand(
69
0
          CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
70
0
{
71
0
}
72
73
/** Constructor. Applications should never create GDALRasterBands directly.
74
 * @param bForceCachedIOIn Whether cached IO should be forced.
75
 */
76
GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
77
0
    : bForceCachedIO(bForceCachedIOIn)
78
79
0
{
80
0
}
81
82
/************************************************************************/
83
/*                          ~GDALRasterBand()                           */
84
/************************************************************************/
85
86
/*! Destructor. Applications should never destroy GDALRasterBands directly,
87
    instead destroy the GDALDataset. */
88
89
GDALRasterBand::~GDALRasterBand()
90
91
0
{
92
0
    if (poDS && poDS->IsMarkedSuppressOnClose())
93
0
    {
94
0
        if (poBandBlockCache)
95
0
            poBandBlockCache->DisableDirtyBlockWriting();
96
0
    }
97
0
    GDALRasterBand::FlushCache(true);
98
99
0
    delete poBandBlockCache;
100
101
0
    if (static_cast<GIntBig>(nBlockReads) >
102
0
            static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
103
0
        nBand == 1 && poDS != nullptr)
104
0
    {
105
0
        CPLDebug(
106
0
            "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
107
0
            nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
108
0
            poDS->GetDescription());
109
0
    }
110
111
0
    InvalidateMaskBand();
112
0
    nBand = -nBand;
113
114
0
    delete m_poPointsCache;
115
0
}
116
117
/************************************************************************/
118
/*                              RasterIO()                              */
119
/************************************************************************/
120
121
/**
122
 * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
123
 *                                int nXOff, int nYOff, int nXSize, int nYSize,
124
 *                                void * pData, int nBufXSize, int nBufYSize,
125
 *                                GDALDataType eBufType,
126
 *                                GSpacing nPixelSpace,
127
 *                                GSpacing nLineSpace,
128
 *                                GDALRasterIOExtraArg* psExtraArg )
129
 * \brief Read/write a region of image data for this band.
130
 *
131
 * This method allows reading a region of a GDALRasterBand into a buffer,
132
 * or writing data from a buffer into a region of a GDALRasterBand. It
133
 * automatically takes care of data type translation if the data type
134
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
135
 * The method also takes care of image decimation / replication if the
136
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
137
 * region being accessed (nXSize x nYSize).
138
 *
139
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
140
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
141
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
142
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
143
 * Or use nLineSpace and a possibly shifted pData value.
144
 *
145
 * The nPixelSpace and nLineSpace parameters allow reading into or
146
 * writing from unusually organized buffers. This is primarily used
147
 * for buffers containing more than one bands raster data in interleaved
148
 * format.
149
 *
150
 * Some formats may efficiently implement decimation into a buffer by
151
 * reading from lower resolution overview images. The logic of the default
152
 * implementation in the base class GDALRasterBand is the following one. It
153
 * computes a target_downscaling_factor from the window of interest and buffer
154
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
155
 * It then walks through overviews and will select the first one whose
156
 * downscaling factor is greater than target_downscaling_factor / 1.2.
157
 *
158
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
159
 * The relationship between target_downscaling_factor and the select overview
160
 * level is the following one:
161
 *
162
 * target_downscaling_factor  | selected_overview
163
 * -------------------------  | -----------------
164
 * ]0,       2 / 1.2]         | full resolution band
165
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
166
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
167
 * ]8 / 1.2, infinity[        | 8x downsampled band
168
 *
169
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
170
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
171
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
172
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
173
 * this oversampling threshold defaults to 1. Consequently if there are overviews
174
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
175
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
176
 *
177
 * For highest performance full resolution data access, read and write
178
 * on "block boundaries" as returned by GetBlockSize(), or use the
179
 * ReadBlock() and WriteBlock() methods.
180
 *
181
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
182
 * functions.
183
 *
184
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
185
 * write a region of data.
186
 *
187
 * @param nXOff The pixel offset to the top left corner of the region
188
 * of the band to be accessed. This would be zero to start from the left side.
189
 *
190
 * @param nYOff The line offset to the top left corner of the region
191
 * of the band to be accessed. This would be zero to start from the top.
192
 *
193
 * @param nXSize The width of the region of the band to be accessed in pixels.
194
 *
195
 * @param nYSize The height of the region of the band to be accessed in lines.
196
 *
197
 * @param pData The buffer into which the data should be read, or from which
198
 * it should be written. This buffer must contain at least nBufXSize *
199
 * nBufYSize words of type eBufType. It is organized in left to right,
200
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
201
 * and nLineSpace parameters.
202
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
203
 * temporarily modified during the execution of this method (and eventually
204
 * restored back to its original content), so it is not safe to use a buffer
205
 * stored in a read-only section of the calling program.
206
 *
207
 * @param nBufXSize the width of the buffer image into which the desired region
208
 * is to be read, or from which it is to be written.
209
 *
210
 * @param nBufYSize the height of the buffer image into which the desired region
211
 * is to be read, or from which it is to be written.
212
 *
213
 * @param eBufType the type of the pixel values in the pData data buffer. The
214
 * pixel values will automatically be translated to/from the GDALRasterBand
215
 * data type as needed. Most driver implementations will use GDALCopyWords64()
216
 * to perform data type translation.
217
 *
218
 * @param nPixelSpace The byte offset from the start of one pixel value in
219
 * pData to the start of the next pixel value within a scanline. If defaulted
220
 * (0) the size of the datatype eBufType is used.
221
 *
222
 * @param nLineSpace The byte offset from the start of one scanline in
223
 * pData to the start of the next. If defaulted (0) the size of the datatype
224
 * eBufType * nBufXSize is used.
225
 *
226
 * @param psExtraArg Pointer to a GDALRasterIOExtraArg
227
 * structure with additional arguments to specify resampling and progress
228
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
229
 * configuration option can also be defined to override the default resampling
230
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
231
 *
232
 * @return CE_Failure if the access fails, otherwise CE_None.
233
 */
234
235
/**
236
 * \brief Read/write a region of image data for this band.
237
 *
238
 * This method allows reading a region of a GDALRasterBand into a buffer,
239
 * or writing data from a buffer into a region of a GDALRasterBand. It
240
 * automatically takes care of data type translation if the data type
241
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
242
 * The method also takes care of image decimation / replication if the
243
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
244
 * region being accessed (nXSize x nYSize).
245
 *
246
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
247
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
248
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
249
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
250
 * Or use nLineSpace and a possibly shifted pData value.
251
 *
252
 * The nPixelSpace and nLineSpace parameters allow reading into or
253
 * writing from unusually organized buffers. This is primarily used
254
 * for buffers containing more than one bands raster data in interleaved
255
 * format.
256
 *
257
 * Some formats may efficiently implement decimation into a buffer by
258
 * reading from lower resolution overview images. The logic of the default
259
 * implementation in the base class GDALRasterBand is the following one. It
260
 * computes a target_downscaling_factor from the window of interest and buffer
261
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
262
 * It then walks through overviews and will select the first one whose
263
 * downscaling factor is greater than target_downscaling_factor / 1.2.
264
 *
265
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
266
 * The relationship between target_downscaling_factor and the select overview
267
 * level is the following one:
268
 *
269
 * target_downscaling_factor  | selected_overview
270
 * -------------------------  | -----------------
271
 * ]0,       2 / 1.2]         | full resolution band
272
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
273
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
274
 * ]8 / 1.2, infinity[        | 8x downsampled band
275
 *
276
 * For highest performance full resolution data access, read and write
277
 * on "block boundaries" as returned by GetBlockSize(), or use the
278
 * ReadBlock() and WriteBlock() methods.
279
 *
280
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
281
 * functions.
282
 *
283
 * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
284
 * more convenient to use for most common use cases.
285
 *
286
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
287
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
288
 * instance of this dataset) concurrently from several threads.
289
 *
290
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
291
 * write a region of data.
292
 *
293
 * @param nXOff The pixel offset to the top left corner of the region
294
 * of the band to be accessed. This would be zero to start from the left side.
295
 *
296
 * @param nYOff The line offset to the top left corner of the region
297
 * of the band to be accessed. This would be zero to start from the top.
298
 *
299
 * @param nXSize The width of the region of the band to be accessed in pixels.
300
 *
301
 * @param nYSize The height of the region of the band to be accessed in lines.
302
 *
303
 * @param[in,out] pData The buffer into which the data should be read, or from
304
 * which it should be written. This buffer must contain at least nBufXSize *
305
 * nBufYSize words of type eBufType. It is organized in left to right,
306
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
307
 * and nLineSpace parameters.
308
 *
309
 * @param nBufXSize the width of the buffer image into which the desired region
310
 * is to be read, or from which it is to be written.
311
 *
312
 * @param nBufYSize the height of the buffer image into which the desired region
313
 * is to be read, or from which it is to be written.
314
 *
315
 * @param eBufType the type of the pixel values in the pData data buffer. The
316
 * pixel values will automatically be translated to/from the GDALRasterBand
317
 * data type as needed.
318
 *
319
 * @param nPixelSpace The byte offset from the start of one pixel value in
320
 * pData to the start of the next pixel value within a scanline. If defaulted
321
 * (0) the size of the datatype eBufType is used.
322
 *
323
 * @param nLineSpace The byte offset from the start of one scanline in
324
 * pData to the start of the next. If defaulted (0) the size of the datatype
325
 * eBufType * nBufXSize is used.
326
 *
327
 * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
328
 * structure with additional arguments to specify resampling and progress
329
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
330
 * configuration option can also be defined to override the default resampling
331
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
332
 *
333
 * @return CE_Failure if the access fails, otherwise CE_None.
334
 *
335
 * @see GDALRasterBand::ReadRaster()
336
 */
337
338
CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
339
                                int nXSize, int nYSize, void *pData,
340
                                int nBufXSize, int nBufYSize,
341
                                GDALDataType eBufType, GSpacing nPixelSpace,
342
                                GSpacing nLineSpace,
343
                                GDALRasterIOExtraArg *psExtraArg)
344
345
0
{
346
0
    GDALRasterIOExtraArg sExtraArg;
347
0
    if (psExtraArg == nullptr)
348
0
    {
349
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
350
0
        psExtraArg = &sExtraArg;
351
0
    }
352
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
353
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
354
0
    {
355
0
        ReportError(CE_Failure, CPLE_AppDefined,
356
0
                    "Unhandled version of GDALRasterIOExtraArg");
357
0
        return CE_Failure;
358
0
    }
359
360
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
361
0
                                       nBufYSize);
362
363
0
    if (CPL_UNLIKELY(nullptr == pData))
364
0
    {
365
0
        ReportError(CE_Failure, CPLE_AppDefined,
366
0
                    "The buffer into which the data should be read is null");
367
0
        return CE_Failure;
368
0
    }
369
370
    /* -------------------------------------------------------------------- */
371
    /*      Some size values are "noop".  Lets just return to avoid         */
372
    /*      stressing lower level functions.                                */
373
    /* -------------------------------------------------------------------- */
374
0
    if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
375
0
                     nBufYSize < 1))
376
0
    {
377
0
        CPLDebug("GDAL",
378
0
                 "RasterIO() skipped for odd window or buffer size.\n"
379
0
                 "  Window = (%d,%d)x%dx%d\n"
380
0
                 "  Buffer = %dx%d\n",
381
0
                 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
382
383
0
        return CE_None;
384
0
    }
385
386
0
    if (eRWFlag == GF_Write)
387
0
    {
388
0
        if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
389
0
        {
390
0
            ReportError(eFlushBlockErr, CPLE_AppDefined,
391
0
                        "An error occurred while writing a dirty block "
392
0
                        "from GDALRasterBand::RasterIO");
393
0
            CPLErr eErr = eFlushBlockErr;
394
0
            eFlushBlockErr = CE_None;
395
0
            return eErr;
396
0
        }
397
0
        if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
398
0
        {
399
0
            return CE_Failure;
400
0
        }
401
0
    }
402
403
    /* -------------------------------------------------------------------- */
404
    /*      If pixel and line spacing are defaulted assign reasonable      */
405
    /*      value assuming a packed buffer.                                 */
406
    /* -------------------------------------------------------------------- */
407
0
    if (nPixelSpace == 0)
408
0
    {
409
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
410
0
    }
411
412
0
    if (nLineSpace == 0)
413
0
    {
414
0
        nLineSpace = nPixelSpace * nBufXSize;
415
0
    }
416
417
    /* -------------------------------------------------------------------- */
418
    /*      Do some validation of parameters.                               */
419
    /* -------------------------------------------------------------------- */
420
0
    if (CPL_UNLIKELY(nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
421
0
                     nYSize > nRasterYSize - nYOff))
422
0
    {
423
0
        ReportError(CE_Failure, CPLE_IllegalArg,
424
0
                    "Access window out of range in RasterIO().  Requested\n"
425
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
426
0
                    nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
427
0
        return CE_Failure;
428
0
    }
429
430
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
431
0
    {
432
0
        ReportError(
433
0
            CE_Failure, CPLE_IllegalArg,
434
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
435
0
            eRWFlag);
436
0
        return CE_Failure;
437
0
    }
438
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
439
0
    {
440
0
        ReportError(CE_Failure, CPLE_IllegalArg,
441
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
442
0
        return CE_Failure;
443
0
    }
444
445
0
    return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
446
0
                            nBufXSize, nBufYSize, eBufType, nPixelSpace,
447
0
                            nLineSpace, psExtraArg);
448
0
}
449
450
/************************************************************************/
451
/*                          RasterIOInternal()                          */
452
/************************************************************************/
453
454
CPLErr GDALRasterBand::RasterIOInternal(
455
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
456
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
457
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
458
0
{
459
    /* -------------------------------------------------------------------- */
460
    /*      Call the format specific function.                              */
461
    /* -------------------------------------------------------------------- */
462
463
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
464
465
0
    CPLErr eErr;
466
0
    if (bForceCachedIO)
467
0
        eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
468
0
                                         pData, nBufXSize, nBufYSize, eBufType,
469
0
                                         nPixelSpace, nLineSpace, psExtraArg);
470
0
    else
471
0
        eErr =
472
0
            IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
473
0
                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
474
475
0
    if (bCallLeaveReadWrite)
476
0
        LeaveReadWrite();
477
478
0
    return eErr;
479
0
}
480
481
/************************************************************************/
482
/*                            GDALRasterIO()                            */
483
/************************************************************************/
484
485
/**
486
 * \brief Read/write a region of image data for this band.
487
 *
488
 * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
489
 * resolution, progress callback, etc. are needed)
490
 *
491
 * @see GDALRasterBand::RasterIO()
492
 */
493
494
CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
495
                                int nXOff, int nYOff, int nXSize, int nYSize,
496
                                void *pData, int nBufXSize, int nBufYSize,
497
                                GDALDataType eBufType, int nPixelSpace,
498
                                int nLineSpace)
499
500
0
{
501
0
    VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
502
503
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
504
505
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
506
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
507
0
                             nLineSpace, nullptr));
508
0
}
509
510
/************************************************************************/
511
/*                           GDALRasterIOEx()                           */
512
/************************************************************************/
513
514
/**
515
 * \brief Read/write a region of image data for this band.
516
 *
517
 * @see GDALRasterBand::RasterIO()
518
 */
519
520
CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
521
                                  int nXOff, int nYOff, int nXSize, int nYSize,
522
                                  void *pData, int nBufXSize, int nBufYSize,
523
                                  GDALDataType eBufType, GSpacing nPixelSpace,
524
                                  GSpacing nLineSpace,
525
                                  GDALRasterIOExtraArg *psExtraArg)
526
527
0
{
528
0
    VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
529
530
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
531
532
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
533
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
534
0
                             nLineSpace, psExtraArg));
535
0
}
536
537
/************************************************************************/
538
/*                         GetGDTFromCppType()                          */
539
/************************************************************************/
540
541
namespace
542
{
543
template <class T> struct GetGDTFromCppType;
544
545
#define DEFINE_GetGDTFromCppType(T, eDT)                                       \
546
    template <> struct GetGDTFromCppType<T>                                    \
547
    {                                                                          \
548
        static constexpr GDALDataType GDT = eDT;                               \
549
    }
550
551
DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
552
DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
553
DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
554
DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
555
DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
556
DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
557
DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
558
DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
559
DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
560
DEFINE_GetGDTFromCppType(float, GDT_Float32);
561
DEFINE_GetGDTFromCppType(double, GDT_Float64);
562
// Not allowed by C++ standard
563
//DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
564
//DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
565
DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
566
DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
567
}  // namespace
568
569
/************************************************************************/
570
/*                             ReadRaster()                             */
571
/************************************************************************/
572
573
// clang-format off
574
/** Read a region of image data for this band.
575
 *
576
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
577
 * for common use cases, like reading a whole band.
578
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
579
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
580
 * float, double, std::complex<float|double>.
581
 *
582
 * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
583
 * and can allocate memory automatically.
584
 *
585
 * To read a whole band (assuming it fits into memory), as an array of double:
586
 *
587
\code{.cpp}
588
 double* myArray = static_cast<double*>(
589
     VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
590
 // TODO: check here that myArray != nullptr
591
 const size_t nArrayEltCount =
592
     static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
593
 if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
594
 {
595
     // do something
596
 }
597
 VSIFree(myArray)
598
\endcode
599
 *
600
 * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
601
 *
602
\code{.cpp}
603
 double* myArray = static_cast<double*>(
604
     VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
605
 // TODO: check here that myArray != nullptr
606
 const size_t nArrayEltCount = 128 * 128;
607
 if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
608
 {
609
     // do something
610
 }
611
 VSIFree(myArray)
612
\endcode
613
 *
614
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
615
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
616
 * instance of this dataset) concurrently from several threads.
617
 *
618
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
619
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
620
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
621
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
622
 * Or use nLineSpace and a possibly shifted pData value.
623
 *
624
 * @param[out] pData The buffer into which the data should be written.
625
 * This buffer must contain at least nBufXSize *
626
 * nBufYSize words of type T. It is organized in left to right,
627
 * top to bottom pixel order, and fully packed.
628
 * The type of the buffer does not need to be the one of GetDataType(). The
629
 * method will perform data type translation (with potential rounding, clamping)
630
 * if needed.
631
 *
632
 * @param nArrayEltCount Number of values of pData. If non zero, the method will
633
 * check that it is at least greater or equal to nBufXSize * nBufYSize, and
634
 * return in error if it is not. If set to zero, then pData is trusted to be
635
 * large enough.
636
 *
637
 * @param dfXOff The pixel offset to the top left corner of the region
638
 * of the band to be accessed. This would be zero to start from the left side.
639
 * Defaults to 0.
640
 *
641
 * @param dfYOff The line offset to the top left corner of the region
642
 * of the band to be accessed. This would be zero to start from the top.
643
 * Defaults to 0.
644
 *
645
 * @param dfXSize The width of the region of the band to be accessed in pixels.
646
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
647
 * dfXSize is set to the band width.
648
 *
649
 * @param dfYSize The height of the region of the band to be accessed in lines.
650
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
651
 * dfYSize is set to the band height.
652
 *
653
 * @param nBufXSize the width of the buffer image into which the desired region
654
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
655
 * then nBufXSize is initialized with dfXSize.
656
 *
657
 * @param nBufYSize the height of the buffer image into which the desired region
658
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
659
 * then nBufYSize is initialized with dfYSize.
660
 *
661
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
662
 *
663
 * @param pfnProgress Progress function. May be nullptr.
664
 *
665
 * @param pProgressData User data of pfnProgress. May be nullptr.
666
 *
667
 * @return CE_Failure if the access fails, otherwise CE_None.
668
 *
669
 * @see GDALRasterBand::RasterIO()
670
 * @since GDAL 3.10
671
 */
672
// clang-format on
673
674
template <class T>
675
CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
676
                                  double dfXOff, double dfYOff, double dfXSize,
677
                                  double dfYSize, size_t nBufXSize,
678
                                  size_t nBufYSize,
679
                                  GDALRIOResampleAlg eResampleAlg,
680
                                  GDALProgressFunc pfnProgress,
681
                                  void *pProgressData) const
682
0
{
683
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
684
0
    {
685
0
        return CE_Failure;
686
0
    }
687
688
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
689
0
    {
690
0
        dfXSize = nRasterXSize;
691
0
        dfYSize = nRasterYSize;
692
0
    }
693
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
694
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
695
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
696
0
             dfYOff + dfYSize > INT_MAX)
697
0
    {
698
0
        return CE_Failure;
699
0
    }
700
701
0
    GDALRasterIOExtraArg sExtraArg;
702
0
    sExtraArg.nVersion = 1;
703
0
    sExtraArg.eResampleAlg = eResampleAlg;
704
0
    sExtraArg.pfnProgress = pfnProgress;
705
0
    sExtraArg.pProgressData = pProgressData;
706
0
    sExtraArg.bFloatingPointWindowValidity = true;
707
0
    sExtraArg.dfXOff = dfXOff;
708
0
    sExtraArg.dfYOff = dfYOff;
709
0
    sExtraArg.dfXSize = dfXSize;
710
0
    sExtraArg.dfYSize = dfYSize;
711
0
    const int nXOff = static_cast<int>(dfXOff);
712
0
    const int nYOff = static_cast<int>(dfYOff);
713
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
714
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
715
0
    if (nBufXSize == 0 && nBufYSize == 0)
716
0
    {
717
0
        if (static_cast<int>(dfXSize) == dfXSize &&
718
0
            static_cast<int>(dfYSize) == dfYSize)
719
0
        {
720
0
            nBufXSize = static_cast<int>(dfXSize);
721
0
            nBufYSize = static_cast<int>(dfYSize);
722
0
        }
723
0
        else
724
0
        {
725
0
            CPLError(CE_Failure, CPLE_AppDefined,
726
0
                     "nBufXSize and nBufYSize must be provided if dfXSize or "
727
0
                     "dfYSize is not an integer value");
728
0
            return CE_Failure;
729
0
        }
730
0
    }
731
0
    if (nBufXSize == 0 || nBufYSize == 0)
732
0
    {
733
0
        CPLDebug("GDAL",
734
0
                 "RasterIO() skipped for odd window or buffer size.\n"
735
0
                 "  Window = (%d,%d)x%dx%d\n"
736
0
                 "  Buffer = %dx%d\n",
737
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
738
0
                 static_cast<int>(nBufYSize));
739
740
0
        return CE_None;
741
0
    }
742
743
0
    if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
744
0
    {
745
0
        CPLError(CE_Failure, CPLE_AppDefined,
746
0
                 "Provided array is not large enough");
747
0
        return CE_Failure;
748
0
    }
749
750
0
    constexpr GSpacing nPixelSpace = sizeof(T);
751
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
752
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
753
754
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
755
756
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
757
0
                                   static_cast<int>(nBufXSize),
758
0
                                   static_cast<int>(nBufYSize), eBufType,
759
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
760
0
}
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned char>(unsigned char*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<signed char>(signed char*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned short>(unsigned short*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<short>(short*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned int>(unsigned int*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<int>(int*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned long>(unsigned long*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<long>(long*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<cpl::Float16>(cpl::Float16*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<float>(float*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<double>(double*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<float> >(std::__1::complex<float>*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<double> >(std::__1::complex<double>*, unsigned long, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
761
762
//! @cond Doxygen_Suppress
763
764
#define INSTANTIATE_READ_RASTER(T)                                             \
765
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
766
        T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
767
        double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
768
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
769
        void *pProgressData) const;
770
771
INSTANTIATE_READ_RASTER(uint8_t)
772
INSTANTIATE_READ_RASTER(int8_t)
773
INSTANTIATE_READ_RASTER(uint16_t)
774
INSTANTIATE_READ_RASTER(int16_t)
775
INSTANTIATE_READ_RASTER(uint32_t)
776
INSTANTIATE_READ_RASTER(int32_t)
777
INSTANTIATE_READ_RASTER(uint64_t)
778
INSTANTIATE_READ_RASTER(int64_t)
779
INSTANTIATE_READ_RASTER(GFloat16)
780
INSTANTIATE_READ_RASTER(float)
781
INSTANTIATE_READ_RASTER(double)
782
// Not allowed by C++ standard
783
// INSTANTIATE_READ_RASTER(std::complex<int16_t>)
784
// INSTANTIATE_READ_RASTER(std::complex<int32_t>)
785
INSTANTIATE_READ_RASTER(std::complex<float>)
786
INSTANTIATE_READ_RASTER(std::complex<double>)
787
788
//! @endcond
789
790
/************************************************************************/
791
/*                             ReadRaster()                             */
792
/************************************************************************/
793
794
/** Read a region of image data for this band.
795
 *
796
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
797
 * for common use cases, like reading a whole band.
798
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
799
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
800
 * float, double, std::complex<float|double>.
801
 *
802
 * To read a whole band (assuming it fits into memory), as a vector of double:
803
 *
804
\code
805
 std::vector<double> myArray;
806
 if (poBand->ReadRaster(myArray) == CE_None)
807
 {
808
     // do something
809
 }
810
\endcode
811
 *
812
 * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
813
 *
814
\code{.cpp}
815
 std::vector<double> myArray;
816
 if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
817
 {
818
     // do something
819
 }
820
\endcode
821
 *
822
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
823
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
824
 * instance of this dataset) concurrently from several threads.
825
 *
826
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
827
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
828
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
829
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
830
 * Or use nLineSpace and a possibly shifted pData value.
831
 *
832
 * @param[out] vData The vector into which the data should be written.
833
 * The vector will be resized, if needed, to contain at least nBufXSize *
834
 * nBufYSize values. The values in the vector are organized in left to right,
835
 * top to bottom pixel order, and fully packed.
836
 * The type of the vector does not need to be the one of GetDataType(). The
837
 * method will perform data type translation (with potential rounding, clamping)
838
 * if needed.
839
 *
840
 * @param dfXOff The pixel offset to the top left corner of the region
841
 * of the band to be accessed. This would be zero to start from the left side.
842
 * Defaults to 0.
843
 *
844
 * @param dfYOff The line offset to the top left corner of the region
845
 * of the band to be accessed. This would be zero to start from the top.
846
 * Defaults to 0.
847
 *
848
 * @param dfXSize The width of the region of the band to be accessed in pixels.
849
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
850
 * dfXSize is set to the band width.
851
 *
852
 * @param dfYSize The height of the region of the band to be accessed in lines.
853
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
854
 * dfYSize is set to the band height.
855
 *
856
 * @param nBufXSize the width of the buffer image into which the desired region
857
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
858
 * then nBufXSize is initialized with dfXSize.
859
 *
860
 * @param nBufYSize the height of the buffer image into which the desired region
861
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
862
 * then nBufYSize is initialized with dfYSize.
863
 *
864
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
865
 *
866
 * @param pfnProgress Progress function. May be nullptr.
867
 *
868
 * @param pProgressData User data of pfnProgress. May be nullptr.
869
 *
870
 * @return CE_Failure if the access fails, otherwise CE_None.
871
 *
872
 * @see GDALRasterBand::RasterIO()
873
 * @since GDAL 3.10
874
 */
875
template <class T>
876
CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
877
                                  double dfYOff, double dfXSize, double dfYSize,
878
                                  size_t nBufXSize, size_t nBufYSize,
879
                                  GDALRIOResampleAlg eResampleAlg,
880
                                  GDALProgressFunc pfnProgress,
881
                                  void *pProgressData) const
882
0
{
883
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
884
0
    {
885
0
        return CE_Failure;
886
0
    }
887
888
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
889
0
    {
890
0
        dfXSize = nRasterXSize;
891
0
        dfYSize = nRasterYSize;
892
0
    }
893
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
894
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
895
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
896
0
             dfYOff + dfYSize > INT_MAX)
897
0
    {
898
0
        return CE_Failure;
899
0
    }
900
901
0
    GDALRasterIOExtraArg sExtraArg;
902
0
    sExtraArg.nVersion = 1;
903
0
    sExtraArg.eResampleAlg = eResampleAlg;
904
0
    sExtraArg.pfnProgress = pfnProgress;
905
0
    sExtraArg.pProgressData = pProgressData;
906
0
    sExtraArg.bFloatingPointWindowValidity = true;
907
0
    sExtraArg.dfXOff = dfXOff;
908
0
    sExtraArg.dfYOff = dfYOff;
909
0
    sExtraArg.dfXSize = dfXSize;
910
0
    sExtraArg.dfYSize = dfYSize;
911
0
    const int nXOff = static_cast<int>(dfXOff);
912
0
    const int nYOff = static_cast<int>(dfYOff);
913
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
914
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
915
0
    if (nBufXSize == 0 && nBufYSize == 0)
916
0
    {
917
0
        if (static_cast<int>(dfXSize) == dfXSize &&
918
0
            static_cast<int>(dfYSize) == dfYSize)
919
0
        {
920
0
            nBufXSize = static_cast<int>(dfXSize);
921
0
            nBufYSize = static_cast<int>(dfYSize);
922
0
        }
923
0
        else
924
0
        {
925
0
            CPLError(CE_Failure, CPLE_AppDefined,
926
0
                     "nBufXSize and nBufYSize must be provided if "
927
0
                     "dfXSize or dfYSize is not an integer value");
928
0
            return CE_Failure;
929
0
        }
930
0
    }
931
0
    if (nBufXSize == 0 || nBufYSize == 0)
932
0
    {
933
0
        CPLDebug("GDAL",
934
0
                 "RasterIO() skipped for odd window or buffer size.\n"
935
0
                 "  Window = (%d,%d)x%dx%d\n"
936
0
                 "  Buffer = %dx%d\n",
937
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
938
0
                 static_cast<int>(nBufYSize));
939
940
0
        return CE_None;
941
0
    }
942
943
    if constexpr (SIZEOF_VOIDP < 8)
944
    {
945
        if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
946
        {
947
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
948
            return CE_Failure;
949
        }
950
    }
951
952
0
    if (vData.size() < nBufXSize * nBufYSize)
953
0
    {
954
0
        try
955
0
        {
956
0
            vData.resize(nBufXSize * nBufYSize);
957
0
        }
958
0
        catch (const std::exception &)
959
0
        {
960
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
961
0
            return CE_Failure;
962
0
        }
963
0
    }
964
965
0
    constexpr GSpacing nPixelSpace = sizeof(T);
966
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
967
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
968
969
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
970
971
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
972
0
                                   vData.data(), static_cast<int>(nBufXSize),
973
0
                                   static_cast<int>(nBufYSize), eBufType,
974
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
975
0
}
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<short>(std::__1::vector<short, std::__1::allocator<short> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<int>(std::__1::vector<int, std::__1::allocator<int> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<unsigned long>(std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<long>(std::__1::vector<long, std::__1::allocator<long> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<cpl::Float16>(std::__1::vector<cpl::Float16, std::__1::allocator<cpl::Float16> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<float>(std::__1::vector<float, std::__1::allocator<float> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<double>(std::__1::vector<double, std::__1::allocator<double> >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<float> >(std::__1::vector<std::__1::complex<float>, std::__1::allocator<std::__1::complex<float> > >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
Unexecuted instantiation: CPLErr GDALRasterBand::ReadRaster<std::__1::complex<double> >(std::__1::vector<std::__1::complex<double>, std::__1::allocator<std::__1::complex<double> > >&, double, double, double, double, unsigned long, unsigned long, GDALRIOResampleAlg, int (*)(double, char const*, void*), void*) const
976
977
//! @cond Doxygen_Suppress
978
979
#define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
980
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
981
        std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
982
        double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
983
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
984
        void *pProgressData) const;
985
986
INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
987
INSTANTIATE_READ_RASTER_VECTOR(int8_t)
988
INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
989
INSTANTIATE_READ_RASTER_VECTOR(int16_t)
990
INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
991
INSTANTIATE_READ_RASTER_VECTOR(int32_t)
992
INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
993
INSTANTIATE_READ_RASTER_VECTOR(int64_t)
994
INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
995
INSTANTIATE_READ_RASTER_VECTOR(float)
996
INSTANTIATE_READ_RASTER_VECTOR(double)
997
// Not allowed by C++ standard
998
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
999
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1000
INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1001
INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1002
1003
//! @endcond
1004
1005
/************************************************************************/
1006
/*                             ReadBlock()                              */
1007
/************************************************************************/
1008
1009
/**
1010
 * \brief Read a block of image data efficiently.
1011
 *
1012
 * This method accesses a "natural" block from the raster band without
1013
 * resampling, or data type conversion.  For a more generalized, but
1014
 * potentially less efficient access use RasterIO().
1015
 *
1016
 * This method is the same as the C GDALReadBlock() function.
1017
 *
1018
 * See the GetLockedBlockRef() method for a way of accessing internally cached
1019
 * block oriented data without an extra copy into an application buffer.
1020
 *
1021
 * The following code would efficiently compute a histogram of eight bit
1022
 * raster data.  Note that the final block may be partial ... data beyond
1023
 * the edge of the underlying raster band in these edge blocks is of an
1024
 * undetermined value.
1025
 *
1026
\code{.cpp}
1027
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1028
1029
 {
1030
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1031
1032
     CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1033
1034
     int nXBlockSize, nYBlockSize;
1035
1036
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1037
     int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1038
     int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1039
1040
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1041
1042
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1043
     {
1044
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1045
         {
1046
             int        nXValid, nYValid;
1047
1048
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1049
1050
             // Compute the portion of the block that is valid
1051
             // for partial edge blocks.
1052
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1053
1054
             // Collect the histogram counts.
1055
             for( int iY = 0; iY < nYValid; iY++ )
1056
             {
1057
                 for( int iX = 0; iX < nXValid; iX++ )
1058
                 {
1059
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1060
                 }
1061
             }
1062
         }
1063
     }
1064
 }
1065
\endcode
1066
 *
1067
 * @param nXBlockOff the horizontal block offset, with zero indicating
1068
 * the left most block, 1 the next block and so forth.
1069
 *
1070
 * @param nYBlockOff the vertical block offset, with zero indicating
1071
 * the top most block, 1 the next block and so forth.
1072
 *
1073
 * @param pImage the buffer into which the data will be read.  The buffer
1074
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1075
 * of type GetRasterDataType().
1076
 *
1077
 * @return CE_None on success or CE_Failure on an error.
1078
 */
1079
1080
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1081
1082
0
{
1083
    /* -------------------------------------------------------------------- */
1084
    /*      Validate arguments.                                             */
1085
    /* -------------------------------------------------------------------- */
1086
0
    CPLAssert(pImage != nullptr);
1087
1088
0
    if (!InitBlockInfo())
1089
0
        return CE_Failure;
1090
1091
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1092
0
    {
1093
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1094
0
                    "Illegal nXBlockOff value (%d) in "
1095
0
                    "GDALRasterBand::ReadBlock()\n",
1096
0
                    nXBlockOff);
1097
1098
0
        return (CE_Failure);
1099
0
    }
1100
1101
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1102
0
    {
1103
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1104
0
                    "Illegal nYBlockOff value (%d) in "
1105
0
                    "GDALRasterBand::ReadBlock()\n",
1106
0
                    nYBlockOff);
1107
1108
0
        return (CE_Failure);
1109
0
    }
1110
1111
    /* -------------------------------------------------------------------- */
1112
    /*      Invoke underlying implementation method.                        */
1113
    /* -------------------------------------------------------------------- */
1114
1115
0
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1116
0
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1117
0
    if (bCallLeaveReadWrite)
1118
0
        LeaveReadWrite();
1119
0
    return eErr;
1120
0
}
1121
1122
/************************************************************************/
1123
/*                           GDALReadBlock()                            */
1124
/************************************************************************/
1125
1126
/**
1127
 * \brief Read a block of image data efficiently.
1128
 *
1129
 * @see GDALRasterBand::ReadBlock()
1130
 */
1131
1132
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1133
                                 void *pData)
1134
1135
0
{
1136
0
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1137
1138
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1139
0
    return (poBand->ReadBlock(nXOff, nYOff, pData));
1140
0
}
1141
1142
/************************************************************************/
1143
/*                             IReadBlock()                             */
1144
/************************************************************************/
1145
1146
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1147
 * ) \brief Read a block of data.
1148
 *
1149
 * Default internal implementation ... to be overridden by
1150
 * subclasses that support reading.
1151
 * @param nBlockXOff Block X Offset
1152
 * @param nBlockYOff Block Y Offset
1153
 * @param pData Pixel buffer into which to place read data.
1154
 * @return CE_None on success or CE_Failure on an error.
1155
 */
1156
1157
/************************************************************************/
1158
/*                            IWriteBlock()                             */
1159
/************************************************************************/
1160
1161
/**
1162
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1163
 * Write a block of data.
1164
 *
1165
 * Default internal implementation ... to be overridden by
1166
 * subclasses that support writing.
1167
 * @param nBlockXOff Block X Offset
1168
 * @param nBlockYOff Block Y Offset
1169
 * @param pData Pixel buffer to write
1170
 * @return CE_None on success or CE_Failure on an error.
1171
 */
1172
1173
/**/
1174
/**/
1175
1176
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1177
                                   void * /*pData*/)
1178
1179
0
{
1180
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1181
0
        ReportError(CE_Failure, CPLE_NotSupported,
1182
0
                    "WriteBlock() not supported for this dataset.");
1183
1184
0
    return (CE_Failure);
1185
0
}
1186
1187
/************************************************************************/
1188
/*                             WriteBlock()                             */
1189
/************************************************************************/
1190
1191
/**
1192
 * \brief Write a block of image data efficiently.
1193
 *
1194
 * This method accesses a "natural" block from the raster band without
1195
 * resampling, or data type conversion.  For a more generalized, but
1196
 * potentially less efficient access use RasterIO().
1197
 *
1198
 * This method is the same as the C GDALWriteBlock() function.
1199
 *
1200
 * See ReadBlock() for an example of block oriented data access.
1201
 *
1202
 * @param nXBlockOff the horizontal block offset, with zero indicating
1203
 * the left most block, 1 the next block and so forth.
1204
 *
1205
 * @param nYBlockOff the vertical block offset, with zero indicating
1206
 * the left most block, 1 the next block and so forth.
1207
 *
1208
 * @param pImage the buffer from which the data will be written.  The buffer
1209
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1210
 * of type GetRasterDataType(). Note that the content of the buffer might be
1211
 * temporarily modified during the execution of this method (and eventually
1212
 * restored back to its original content), so it is not safe to use a buffer
1213
 * stored in a read-only section of the calling program.
1214
 *
1215
 * @return CE_None on success or CE_Failure on an error.
1216
 */
1217
1218
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1219
1220
0
{
1221
    /* -------------------------------------------------------------------- */
1222
    /*      Validate arguments.                                             */
1223
    /* -------------------------------------------------------------------- */
1224
0
    CPLAssert(pImage != nullptr);
1225
1226
0
    if (!InitBlockInfo())
1227
0
        return CE_Failure;
1228
1229
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1230
0
    {
1231
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1232
0
                    "Illegal nXBlockOff value (%d) in "
1233
0
                    "GDALRasterBand::WriteBlock()\n",
1234
0
                    nXBlockOff);
1235
1236
0
        return (CE_Failure);
1237
0
    }
1238
1239
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1240
0
    {
1241
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1242
0
                    "Illegal nYBlockOff value (%d) in "
1243
0
                    "GDALRasterBand::WriteBlock()\n",
1244
0
                    nYBlockOff);
1245
1246
0
        return (CE_Failure);
1247
0
    }
1248
1249
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1250
0
    {
1251
0
        return CE_Failure;
1252
0
    }
1253
1254
0
    if (eFlushBlockErr != CE_None)
1255
0
    {
1256
0
        ReportError(eFlushBlockErr, CPLE_AppDefined,
1257
0
                    "An error occurred while writing a dirty block "
1258
0
                    "from GDALRasterBand::WriteBlock");
1259
0
        CPLErr eErr = eFlushBlockErr;
1260
0
        eFlushBlockErr = CE_None;
1261
0
        return eErr;
1262
0
    }
1263
1264
    /* -------------------------------------------------------------------- */
1265
    /*      Invoke underlying implementation method.                        */
1266
    /* -------------------------------------------------------------------- */
1267
1268
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1269
0
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1270
0
    if (bCallLeaveReadWrite)
1271
0
        LeaveReadWrite();
1272
1273
0
    return eErr;
1274
0
}
1275
1276
/************************************************************************/
1277
/*                           GDALWriteBlock()                           */
1278
/************************************************************************/
1279
1280
/**
1281
 * \brief Write a block of image data efficiently.
1282
 *
1283
 * @see GDALRasterBand::WriteBlock()
1284
 */
1285
1286
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1287
                                  void *pData)
1288
1289
0
{
1290
0
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1291
1292
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1293
0
    return (poBand->WriteBlock(nXOff, nYOff, pData));
1294
0
}
1295
1296
/************************************************************************/
1297
/*                EmitErrorMessageIfWriteNotSupported()                 */
1298
/************************************************************************/
1299
1300
/**
1301
 * Emit an error message if a write operation to this band is not supported.
1302
 *
1303
 * The base implementation will emit an error message if the access mode is
1304
 * read-only. Derived classes may implement it to provide a custom message.
1305
 *
1306
 * @param pszCaller Calling function.
1307
 * @return true if an error message has been emitted.
1308
 */
1309
bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1310
    const char *pszCaller) const
1311
0
{
1312
0
    if (eAccess == GA_ReadOnly)
1313
0
    {
1314
0
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1315
0
                    "%s: attempt to write to dataset opened in read-only mode.",
1316
0
                    pszCaller);
1317
1318
0
        return true;
1319
0
    }
1320
0
    return false;
1321
0
}
1322
1323
/************************************************************************/
1324
/*                         GetActualBlockSize()                         */
1325
/************************************************************************/
1326
/**
1327
 * \brief Fetch the actual block size for a given block offset.
1328
 *
1329
 * Handles partial blocks at the edges of the raster and returns the true
1330
 * number of pixels
1331
 *
1332
 * @param nXBlockOff the horizontal block offset for which to calculate the
1333
 * number of valid pixels, with zero indicating the left most block, 1 the next
1334
 * block and so forth.
1335
 *
1336
 * @param nYBlockOff the vertical block offset, with zero indicating
1337
 * the top most block, 1 the next block and so forth.
1338
 *
1339
 * @param pnXValid pointer to an integer in which the number of valid pixels in
1340
 * the x direction will be stored
1341
 *
1342
 * @param pnYValid pointer to an integer in which the number of valid pixels in
1343
 * the y direction will be stored
1344
 *
1345
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
1346
 *
1347
 */
1348
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1349
                                          int *pnXValid, int *pnYValid) const
1350
0
{
1351
0
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
1352
0
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1353
0
        nYBlockOff < 0 || nBlockYSize == 0 ||
1354
0
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1355
0
    {
1356
0
        return CE_Failure;
1357
0
    }
1358
1359
0
    const int nXPixelOff = nXBlockOff * nBlockXSize;
1360
0
    const int nYPixelOff = nYBlockOff * nBlockYSize;
1361
1362
0
    *pnXValid = nBlockXSize;
1363
0
    *pnYValid = nBlockYSize;
1364
1365
0
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
1366
0
    {
1367
0
        *pnXValid = nRasterXSize - nXPixelOff;
1368
0
    }
1369
1370
0
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
1371
0
    {
1372
0
        *pnYValid = nRasterYSize - nYPixelOff;
1373
0
    }
1374
1375
0
    return CE_None;
1376
0
}
1377
1378
/************************************************************************/
1379
/*                       GDALGetActualBlockSize()                       */
1380
/************************************************************************/
1381
1382
/**
1383
 * \brief Retrieve the actual block size for a given block offset.
1384
 *
1385
 * @see GDALRasterBand::GetActualBlockSize()
1386
 */
1387
1388
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1389
                                          int nYBlockOff, int *pnXValid,
1390
                                          int *pnYValid)
1391
1392
0
{
1393
0
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1394
1395
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1396
0
    return (
1397
0
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1398
0
}
1399
1400
/************************************************************************/
1401
/*                   GetSuggestedBlockAccessPattern()                   */
1402
/************************************************************************/
1403
1404
/**
1405
 * \brief Return the suggested/most efficient access pattern to blocks
1406
 *        (for read operations).
1407
 *
1408
 * While all GDAL drivers have to expose a block size, not all can guarantee
1409
 * efficient random access (GSBAP_RANDOM) to any block.
1410
 * Some drivers for example decompress sequentially a compressed stream from
1411
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1412
 * case best performance will be achieved while reading blocks in that order.
1413
 * (accessing blocks in random access in such rasters typically causes the
1414
 * decoding to be re-initialized from the start if accessing blocks in
1415
 * a non-sequential order)
1416
 *
1417
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1418
 * returned by drivers that expose a somewhat artificial block size, because
1419
 * they can extract any part of a raster, but in a rather inefficient way.
1420
 *
1421
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1422
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1423
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1424
 * most efficient strategy is to read as many pixels as possible in the less
1425
 * RasterIO() operations.
1426
 *
1427
 * The return of this method is for example used to determine the swath size
1428
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1429
 *
1430
 * @since GDAL 3.6
1431
 */
1432
1433
GDALSuggestedBlockAccessPattern
1434
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1435
0
{
1436
0
    return GSBAP_UNKNOWN;
1437
0
}
1438
1439
/************************************************************************/
1440
/*                         GetRasterDataType()                          */
1441
/************************************************************************/
1442
1443
/**
1444
 * \brief Fetch the pixel data type for this band.
1445
 *
1446
 * This method is the same as the C function GDALGetRasterDataType().
1447
 *
1448
 * @return the data type of pixels for this band.
1449
 */
1450
1451
GDALDataType GDALRasterBand::GetRasterDataType() const
1452
1453
0
{
1454
0
    return eDataType;
1455
0
}
1456
1457
/************************************************************************/
1458
/*                       GDALGetRasterDataType()                        */
1459
/************************************************************************/
1460
1461
/**
1462
 * \brief Fetch the pixel data type for this band.
1463
 *
1464
 * @see GDALRasterBand::GetRasterDataType()
1465
 */
1466
1467
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1468
1469
0
{
1470
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1471
1472
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1473
0
    return poBand->GetRasterDataType();
1474
0
}
1475
1476
/************************************************************************/
1477
/*                            GetBlockSize()                            */
1478
/************************************************************************/
1479
1480
/**
1481
 * \brief Fetch the "natural" block size of this band.
1482
 *
1483
 * GDAL contains a concept of the natural block size of rasters so that
1484
 * applications can organized data access efficiently for some file formats.
1485
 * The natural block size is the block size that is most efficient for
1486
 * accessing the format.  For many formats this is simple a whole scanline
1487
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1488
 *
1489
 * However, for tiled images this will typically be the tile size.
1490
 *
1491
 * Note that the X and Y block sizes don't have to divide the image size
1492
 * evenly, meaning that right and bottom edge blocks may be incomplete.
1493
 * See ReadBlock() for an example of code dealing with these issues.
1494
 *
1495
 * This method is the same as the C function GDALGetBlockSize().
1496
 *
1497
 * @param pnXSize integer to put the X block size into or NULL.
1498
 *
1499
 * @param pnYSize integer to put the Y block size into or NULL.
1500
 */
1501
1502
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1503
1504
0
{
1505
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1506
0
    {
1507
0
        ReportError(CE_Failure, CPLE_AppDefined,
1508
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1509
0
                    nBlockYSize);
1510
0
        if (pnXSize != nullptr)
1511
0
            *pnXSize = 0;
1512
0
        if (pnYSize != nullptr)
1513
0
            *pnYSize = 0;
1514
0
    }
1515
0
    else
1516
0
    {
1517
0
        if (pnXSize != nullptr)
1518
0
            *pnXSize = nBlockXSize;
1519
0
        if (pnYSize != nullptr)
1520
0
            *pnYSize = nBlockYSize;
1521
0
    }
1522
0
}
1523
1524
/************************************************************************/
1525
/*                          GDALGetBlockSize()                          */
1526
/************************************************************************/
1527
1528
/**
1529
 * \brief Fetch the "natural" block size of this band.
1530
 *
1531
 * @see GDALRasterBand::GetBlockSize()
1532
 */
1533
1534
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1535
                                  int *pnYSize)
1536
1537
0
{
1538
0
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1539
1540
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1541
0
    poBand->GetBlockSize(pnXSize, pnYSize);
1542
0
}
1543
1544
/************************************************************************/
1545
/*                           InitBlockInfo()                            */
1546
/************************************************************************/
1547
1548
//! @cond Doxygen_Suppress
1549
int GDALRasterBand::InitBlockInfo()
1550
1551
0
{
1552
0
    if (poBandBlockCache != nullptr)
1553
0
        return poBandBlockCache->IsInitOK();
1554
1555
    /* Do some validation of raster and block dimensions in case the driver */
1556
    /* would have neglected to do it itself */
1557
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1558
0
    {
1559
0
        ReportError(CE_Failure, CPLE_AppDefined,
1560
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1561
0
                    nBlockYSize);
1562
0
        return FALSE;
1563
0
    }
1564
1565
0
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
1566
0
    {
1567
0
        ReportError(CE_Failure, CPLE_AppDefined,
1568
0
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1569
0
                    nRasterYSize);
1570
0
        return FALSE;
1571
0
    }
1572
1573
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1574
0
    if (nDataTypeSize == 0)
1575
0
    {
1576
0
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1577
0
        return FALSE;
1578
0
    }
1579
1580
#if SIZEOF_VOIDP == 4
1581
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1582
    {
1583
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1584
         * multiplication in other cases */
1585
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1586
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1587
        {
1588
            ReportError(CE_Failure, CPLE_NotSupported,
1589
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1590
                        nBlockYSize);
1591
            return FALSE;
1592
        }
1593
    }
1594
#endif
1595
1596
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1597
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1598
1599
0
    const char *pszBlockStrategy =
1600
0
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1601
0
    bool bUseArray = true;
1602
0
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1603
0
    {
1604
0
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1605
0
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1606
0
        {
1607
0
            GUIntBig nBlockCount =
1608
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1609
0
            if (poDS != nullptr)
1610
0
                nBlockCount *= poDS->GetRasterCount();
1611
0
            bUseArray = (nBlockCount < 1024 * 1024);
1612
0
        }
1613
0
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1614
0
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1615
0
        {
1616
0
            bUseArray = false;
1617
0
        }
1618
0
    }
1619
0
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
1620
0
        bUseArray = false;
1621
0
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1622
0
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1623
0
                 pszBlockStrategy);
1624
1625
0
    if (bUseArray)
1626
0
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1627
0
    else
1628
0
    {
1629
0
        if (nBand == 1)
1630
0
            CPLDebug("GDAL", "Use hashset band block cache");
1631
0
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1632
0
    }
1633
0
    if (poBandBlockCache == nullptr)
1634
0
        return FALSE;
1635
0
    return poBandBlockCache->Init();
1636
0
}
1637
1638
//! @endcond
1639
1640
/************************************************************************/
1641
/*                             FlushCache()                             */
1642
/************************************************************************/
1643
1644
/**
1645
 * \brief Flush raster data cache.
1646
 *
1647
 * This call will recover memory used to cache data blocks for this raster
1648
 * band, and ensure that new requests are referred to the underlying driver.
1649
 *
1650
 * This method is the same as the C function GDALFlushRasterCache().
1651
 *
1652
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1653
 * @return CE_None on success.
1654
 */
1655
1656
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1657
1658
0
{
1659
0
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1660
0
        poBandBlockCache)
1661
0
        poBandBlockCache->DisableDirtyBlockWriting();
1662
1663
0
    CPLErr eGlobalErr = eFlushBlockErr;
1664
1665
0
    if (eFlushBlockErr != CE_None)
1666
0
    {
1667
0
        ReportError(
1668
0
            eFlushBlockErr, CPLE_AppDefined,
1669
0
            "An error occurred while writing a dirty block from FlushCache");
1670
0
        eFlushBlockErr = CE_None;
1671
0
    }
1672
1673
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1674
0
        return eGlobalErr;
1675
1676
0
    return poBandBlockCache->FlushCache();
1677
0
}
1678
1679
/************************************************************************/
1680
/*                        GDALFlushRasterCache()                        */
1681
/************************************************************************/
1682
1683
/**
1684
 * \brief Flush raster data cache.
1685
 *
1686
 * @see GDALRasterBand::FlushCache()
1687
 */
1688
1689
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1690
1691
0
{
1692
0
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1693
1694
0
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1695
0
}
1696
1697
/************************************************************************/
1698
/*                             DropCache()                              */
1699
/************************************************************************/
1700
1701
/**
1702
* \brief Drop raster data cache : data in cache will be lost.
1703
*
1704
* This call will recover memory used to cache data blocks for this raster
1705
* band, and ensure that new requests are referred to the underlying driver.
1706
*
1707
* This method is the same as the C function GDALDropRasterCache().
1708
*
1709
* @return CE_None on success.
1710
* @since 3.9
1711
*/
1712
1713
CPLErr GDALRasterBand::DropCache()
1714
1715
0
{
1716
0
    CPLErr result = CE_None;
1717
1718
0
    if (poBandBlockCache)
1719
0
        poBandBlockCache->DisableDirtyBlockWriting();
1720
1721
0
    CPLErr eGlobalErr = eFlushBlockErr;
1722
1723
0
    if (eFlushBlockErr != CE_None)
1724
0
    {
1725
0
        ReportError(
1726
0
            eFlushBlockErr, CPLE_AppDefined,
1727
0
            "An error occurred while writing a dirty block from DropCache");
1728
0
        eFlushBlockErr = CE_None;
1729
0
    }
1730
1731
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1732
0
        result = eGlobalErr;
1733
0
    else
1734
0
        result = poBandBlockCache->FlushCache();
1735
1736
0
    if (poBandBlockCache)
1737
0
        poBandBlockCache->EnableDirtyBlockWriting();
1738
1739
0
    return result;
1740
0
}
1741
1742
/************************************************************************/
1743
/*                        GDALDropRasterCache()                         */
1744
/************************************************************************/
1745
1746
/**
1747
* \brief Drop raster data cache.
1748
*
1749
* @see GDALRasterBand::DropCache()
1750
* @since 3.9
1751
*/
1752
1753
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1754
1755
0
{
1756
0
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1757
1758
0
    return GDALRasterBand::FromHandle(hBand)->DropCache();
1759
0
}
1760
1761
/************************************************************************/
1762
/*                        UnreferenceBlock()                            */
1763
/*                                                                      */
1764
/*      Unreference the block from our array of blocks                  */
1765
/*      This method should only be called by                            */
1766
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1767
/*      the block cache mutex)                                          */
1768
/************************************************************************/
1769
1770
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1771
0
{
1772
#ifdef notdef
1773
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1774
    {
1775
        if (poBandBlockCache == nullptr)
1776
            printf("poBandBlockCache == NULL\n"); /*ok*/
1777
        else
1778
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1779
        printf("caller = %s\n", pszCaller);            /*ok*/
1780
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1781
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1782
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1783
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1784
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1785
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1786
        poBlock->DumpBlock();
1787
        if (GetDataset() != nullptr)
1788
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1789
        GDALRasterBlock::Verify();
1790
        abort();
1791
    }
1792
#endif
1793
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1794
0
    return poBandBlockCache->UnreferenceBlock(poBlock);
1795
0
}
1796
1797
/************************************************************************/
1798
/*                        AddBlockToFreeList()                          */
1799
/*                                                                      */
1800
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1801
/*      finished with a block about to be free'd, they pass it to that  */
1802
/*      method.                                                         */
1803
/************************************************************************/
1804
1805
//! @cond Doxygen_Suppress
1806
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1807
0
{
1808
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1809
0
    return poBandBlockCache->AddBlockToFreeList(poBlock);
1810
0
}
1811
1812
//! @endcond
1813
1814
/************************************************************************/
1815
/*                           HasDirtyBlocks()                           */
1816
/************************************************************************/
1817
1818
//! @cond Doxygen_Suppress
1819
bool GDALRasterBand::HasDirtyBlocks() const
1820
0
{
1821
0
    return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1822
0
}
1823
1824
//! @endcond
1825
1826
/************************************************************************/
1827
/*                             FlushBlock()                             */
1828
/************************************************************************/
1829
1830
/** Flush a block out of the block cache.
1831
 * @param nXBlockOff block x offset
1832
 * @param nYBlockOff blocky offset
1833
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1834
 * @return CE_None in case of success, an error code otherwise.
1835
 */
1836
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1837
                                  int bWriteDirtyBlock)
1838
1839
0
{
1840
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1841
0
        return (CE_Failure);
1842
1843
    /* -------------------------------------------------------------------- */
1844
    /*      Validate the request                                            */
1845
    /* -------------------------------------------------------------------- */
1846
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1847
0
    {
1848
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1849
0
                    "Illegal nBlockXOff value (%d) in "
1850
0
                    "GDALRasterBand::FlushBlock()\n",
1851
0
                    nXBlockOff);
1852
1853
0
        return (CE_Failure);
1854
0
    }
1855
1856
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1857
0
    {
1858
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1859
0
                    "Illegal nBlockYOff value (%d) in "
1860
0
                    "GDALRasterBand::FlushBlock()\n",
1861
0
                    nYBlockOff);
1862
1863
0
        return (CE_Failure);
1864
0
    }
1865
1866
0
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1867
0
                                        bWriteDirtyBlock);
1868
0
}
1869
1870
/************************************************************************/
1871
/*                        TryGetLockedBlockRef()                        */
1872
/************************************************************************/
1873
1874
/**
1875
 * \brief Try fetching block ref.
1876
 *
1877
 * This method will returned the requested block (locked) if it is already
1878
 * in the block cache for the layer.  If not, nullptr is returned.
1879
 *
1880
 * If a non-NULL value is returned, then a lock for the block will have been
1881
 * acquired on behalf of the caller.  It is absolutely imperative that the
1882
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1883
 * severe problems may result.
1884
 *
1885
 * @param nXBlockOff the horizontal block offset, with zero indicating
1886
 * the left most block, 1 the next block and so forth.
1887
 *
1888
 * @param nYBlockOff the vertical block offset, with zero indicating
1889
 * the top most block, 1 the next block and so forth.
1890
 *
1891
 * @return NULL if block not available, or locked block pointer.
1892
 */
1893
1894
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1895
                                                      int nYBlockOff)
1896
1897
0
{
1898
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1899
0
        return nullptr;
1900
1901
    /* -------------------------------------------------------------------- */
1902
    /*      Validate the request                                            */
1903
    /* -------------------------------------------------------------------- */
1904
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1905
0
    {
1906
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1907
0
                    "Illegal nBlockXOff value (%d) in "
1908
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1909
0
                    nXBlockOff);
1910
1911
0
        return (nullptr);
1912
0
    }
1913
1914
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1915
0
    {
1916
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1917
0
                    "Illegal nBlockYOff value (%d) in "
1918
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1919
0
                    nYBlockOff);
1920
1921
0
        return (nullptr);
1922
0
    }
1923
1924
0
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1925
0
}
1926
1927
/************************************************************************/
1928
/*                         GetLockedBlockRef()                          */
1929
/************************************************************************/
1930
1931
/**
1932
 * \brief Fetch a pointer to an internally cached raster block.
1933
 *
1934
 * This method will returned the requested block (locked) if it is already
1935
 * in the block cache for the layer.  If not, the block will be read from
1936
 * the driver, and placed in the layer block cached, then returned.  If an
1937
 * error occurs reading the block from the driver, a NULL value will be
1938
 * returned.
1939
 *
1940
 * If a non-NULL value is returned, then a lock for the block will have been
1941
 * acquired on behalf of the caller.  It is absolutely imperative that the
1942
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1943
 * severe problems may result.
1944
 *
1945
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1946
 * enable caching.
1947
 *
1948
 * @param nXBlockOff the horizontal block offset, with zero indicating
1949
 * the left most block, 1 the next block and so forth.
1950
 *
1951
 * @param nYBlockOff the vertical block offset, with zero indicating
1952
 * the top most block, 1 the next block and so forth.
1953
 *
1954
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1955
 * but not actually read from the source.  This is useful when it will just
1956
 * be completely set and written back.
1957
 *
1958
 * @return pointer to the block object, or NULL on failure.
1959
 */
1960
1961
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1962
                                                   int nYBlockOff,
1963
                                                   int bJustInitialize)
1964
1965
0
{
1966
    /* -------------------------------------------------------------------- */
1967
    /*      Try and fetch from cache.                                       */
1968
    /* -------------------------------------------------------------------- */
1969
0
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1970
1971
    /* -------------------------------------------------------------------- */
1972
    /*      If we didn't find it in our memory cache, instantiate a         */
1973
    /*      block (potentially load from disk) and "adopt" it into the      */
1974
    /*      cache.                                                          */
1975
    /* -------------------------------------------------------------------- */
1976
0
    if (poBlock == nullptr)
1977
0
    {
1978
0
        if (!InitBlockInfo())
1979
0
            return (nullptr);
1980
1981
        /* --------------------------------------------------------------------
1982
         */
1983
        /*      Validate the request */
1984
        /* --------------------------------------------------------------------
1985
         */
1986
0
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1987
0
        {
1988
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1989
0
                        "Illegal nBlockXOff value (%d) in "
1990
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1991
0
                        nXBlockOff);
1992
1993
0
            return (nullptr);
1994
0
        }
1995
1996
0
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1997
0
        {
1998
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1999
0
                        "Illegal nBlockYOff value (%d) in "
2000
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
2001
0
                        nYBlockOff);
2002
2003
0
            return (nullptr);
2004
0
        }
2005
2006
0
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2007
0
        if (poBlock == nullptr)
2008
0
            return nullptr;
2009
2010
0
        poBlock->AddLock();
2011
2012
        /* We need to temporarily drop the read-write lock in the following */
2013
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2014
         */
2015
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2016
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2017
         */
2018
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2019
         */
2020
        /* called and attempt at taking the lock on T2 (already taken).
2021
         * Similarly */
2022
        /* for T2 with D1, hence a deadlock situation (#6163) */
2023
        /* But this may open the door to other problems... */
2024
0
        if (poDS)
2025
0
            poDS->TemporarilyDropReadWriteLock();
2026
        /* allocate data space */
2027
0
        CPLErr eErr = poBlock->Internalize();
2028
0
        if (poDS)
2029
0
            poDS->ReacquireReadWriteLock();
2030
0
        if (eErr != CE_None)
2031
0
        {
2032
0
            poBlock->DropLock();
2033
0
            delete poBlock;
2034
0
            return nullptr;
2035
0
        }
2036
2037
0
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2038
0
        {
2039
0
            poBlock->DropLock();
2040
0
            delete poBlock;
2041
0
            return nullptr;
2042
0
        }
2043
2044
0
        if (!bJustInitialize)
2045
0
        {
2046
0
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2047
0
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2048
0
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2049
0
            if (bCallLeaveReadWrite)
2050
0
                LeaveReadWrite();
2051
0
            if (eErr != CE_None)
2052
0
            {
2053
0
                poBlock->DropLock();
2054
0
                FlushBlock(nXBlockOff, nYBlockOff);
2055
0
                ReportError(CE_Failure, CPLE_AppDefined,
2056
0
                            "IReadBlock failed at X offset %d, Y offset %d%s",
2057
0
                            nXBlockOff, nYBlockOff,
2058
0
                            (nErrorCounter != CPLGetErrorCounter())
2059
0
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2060
0
                                : "");
2061
0
                return nullptr;
2062
0
            }
2063
2064
0
            nBlockReads++;
2065
0
            if (static_cast<GIntBig>(nBlockReads) ==
2066
0
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2067
0
                        1 &&
2068
0
                nBand == 1 && poDS != nullptr)
2069
0
            {
2070
0
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2071
0
                         poDS->GetDescription());
2072
0
            }
2073
0
        }
2074
0
    }
2075
2076
0
    return poBlock;
2077
0
}
2078
2079
/************************************************************************/
2080
/*                                Fill()                                */
2081
/************************************************************************/
2082
2083
/**
2084
 * \brief Fill this band with a constant value.
2085
 *
2086
 * GDAL makes no guarantees
2087
 * about what values pixels in newly created files are set to, so this
2088
 * method can be used to clear a band to a specified "default" value.
2089
 * The fill value is passed in as a double but this will be converted
2090
 * to the underlying type before writing to the file. An optional
2091
 * second argument allows the imaginary component of a complex
2092
 * constant value to be specified.
2093
 *
2094
 * This method is the same as the C function GDALFillRaster().
2095
 *
2096
 * @param dfRealValue Real component of fill value
2097
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2098
 *
2099
 * @return CE_Failure if the write fails, otherwise CE_None
2100
 */
2101
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2102
0
{
2103
2104
    // General approach is to construct a source block of the file's
2105
    // native type containing the appropriate value and then copy this
2106
    // to each block in the image via the RasterBlock cache. Using
2107
    // the cache means we avoid file I/O if it is not necessary, at the
2108
    // expense of some extra memcpy's (since we write to the
2109
    // RasterBlock cache, which is then at some point written to the
2110
    // underlying file, rather than simply directly to the underlying
2111
    // file.)
2112
2113
    // Check we can write to the file.
2114
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2115
0
    {
2116
0
        return CE_Failure;
2117
0
    }
2118
2119
    // Make sure block parameters are set.
2120
0
    if (!InitBlockInfo())
2121
0
        return CE_Failure;
2122
2123
    // Allocate the source block.
2124
0
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2125
0
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2126
0
    auto blockByteSize = blockSize * elementSize;
2127
0
    unsigned char *srcBlock =
2128
0
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2129
0
    if (srcBlock == nullptr)
2130
0
    {
2131
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
2132
0
                    "GDALRasterBand::Fill(): Out of memory "
2133
0
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
2134
0
                    static_cast<GUIntBig>(blockByteSize));
2135
0
        return CE_Failure;
2136
0
    }
2137
2138
    // Initialize the source block.
2139
0
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2140
0
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2141
0
                    elementSize, blockSize);
2142
2143
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2144
2145
    // Write block to block cache
2146
0
    for (int j = 0; j < nBlocksPerColumn; ++j)
2147
0
    {
2148
0
        for (int i = 0; i < nBlocksPerRow; ++i)
2149
0
        {
2150
0
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2151
0
            if (destBlock == nullptr)
2152
0
            {
2153
0
                ReportError(CE_Failure, CPLE_OutOfMemory,
2154
0
                            "GDALRasterBand::Fill(): Error "
2155
0
                            "while retrieving cache block.");
2156
0
                VSIFree(srcBlock);
2157
0
                return CE_Failure;
2158
0
            }
2159
0
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2160
0
            destBlock->MarkDirty();
2161
0
            destBlock->DropLock();
2162
0
        }
2163
0
    }
2164
2165
0
    if (bCallLeaveReadWrite)
2166
0
        LeaveReadWrite();
2167
2168
    // Free up the source block
2169
0
    VSIFree(srcBlock);
2170
2171
0
    return CE_None;
2172
0
}
2173
2174
/************************************************************************/
2175
/*                           GDALFillRaster()                           */
2176
/************************************************************************/
2177
2178
/**
2179
 * \brief Fill this band with a constant value.
2180
 *
2181
 * @see GDALRasterBand::Fill()
2182
 */
2183
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2184
                                  double dfImaginaryValue)
2185
0
{
2186
0
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2187
2188
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2189
0
    return poBand->Fill(dfRealValue, dfImaginaryValue);
2190
0
}
2191
2192
/************************************************************************/
2193
/*                             GetAccess()                              */
2194
/************************************************************************/
2195
2196
/**
2197
 * \brief Find out if we have update permission for this band.
2198
 *
2199
 * This method is the same as the C function GDALGetRasterAccess().
2200
 *
2201
 * @return Either GA_Update or GA_ReadOnly.
2202
 */
2203
2204
GDALAccess GDALRasterBand::GetAccess()
2205
2206
0
{
2207
0
    return eAccess;
2208
0
}
2209
2210
/************************************************************************/
2211
/*                        GDALGetRasterAccess()                         */
2212
/************************************************************************/
2213
2214
/**
2215
 * \brief Find out if we have update permission for this band.
2216
 *
2217
 * @see GDALRasterBand::GetAccess()
2218
 */
2219
2220
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2221
2222
0
{
2223
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2224
2225
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2226
0
    return poBand->GetAccess();
2227
0
}
2228
2229
/************************************************************************/
2230
/*                          GetCategoryNames()                          */
2231
/************************************************************************/
2232
2233
/**
2234
 * \brief Fetch the list of category names for this raster.
2235
 *
2236
 * The return list is a "StringList" in the sense of the CPL functions.
2237
 * That is a NULL terminated array of strings.  Raster values without
2238
 * associated names will have an empty string in the returned list.  The
2239
 * first entry in the list is for raster values of zero, and so on.
2240
 *
2241
 * The returned stringlist should not be altered or freed by the application.
2242
 * It may change on the next GDAL call, so please copy it if it is needed
2243
 * for any period of time.
2244
 *
2245
 * This method is the same as the C function GDALGetRasterCategoryNames().
2246
 *
2247
 * @return list of names, or NULL if none.
2248
 */
2249
2250
char **GDALRasterBand::GetCategoryNames()
2251
2252
0
{
2253
0
    return nullptr;
2254
0
}
2255
2256
/************************************************************************/
2257
/*                     GDALGetRasterCategoryNames()                     */
2258
/************************************************************************/
2259
2260
/**
2261
 * \brief Fetch the list of category names for this raster.
2262
 *
2263
 * @see GDALRasterBand::GetCategoryNames()
2264
 */
2265
2266
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2267
2268
0
{
2269
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2270
2271
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2272
0
    return poBand->GetCategoryNames();
2273
0
}
2274
2275
/************************************************************************/
2276
/*                          SetCategoryNames()                          */
2277
/************************************************************************/
2278
2279
/**
2280
 * \fn GDALRasterBand::SetCategoryNames(char**)
2281
 * \brief Set the category names for this band.
2282
 *
2283
 * See the GetCategoryNames() method for more on the interpretation of
2284
 * category names.
2285
 *
2286
 * This method is the same as the C function GDALSetRasterCategoryNames().
2287
 *
2288
 * @param papszNames the NULL terminated StringList of category names.  May
2289
 * be NULL to just clear the existing list.
2290
 *
2291
 * @return CE_None on success of CE_Failure on failure.  If unsupported
2292
 * by the driver CE_Failure is returned, but no error message is reported.
2293
 */
2294
2295
/**/
2296
/**/
2297
2298
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2299
0
{
2300
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2301
0
        ReportError(CE_Failure, CPLE_NotSupported,
2302
0
                    "SetCategoryNames() not supported for this dataset.");
2303
2304
0
    return CE_Failure;
2305
0
}
2306
2307
/************************************************************************/
2308
/*                        GDALSetCategoryNames()                        */
2309
/************************************************************************/
2310
2311
/**
2312
 * \brief Set the category names for this band.
2313
 *
2314
 * @see GDALRasterBand::SetCategoryNames()
2315
 */
2316
2317
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2318
                                              CSLConstList papszNames)
2319
2320
0
{
2321
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2322
2323
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2324
0
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2325
0
}
2326
2327
/************************************************************************/
2328
/*                           GetNoDataValue()                           */
2329
/************************************************************************/
2330
2331
/**
2332
 * \brief Fetch the no data value for this band.
2333
 *
2334
 * If there is no out of data value, an out of range value will generally
2335
 * be returned.  The no data value for a band is generally a special marker
2336
 * value used to mark pixels that are not valid data.  Such pixels should
2337
 * generally not be displayed, nor contribute to analysis operations.
2338
 *
2339
 * The no data value returned is 'raw', meaning that it has no offset and
2340
 * scale applied.
2341
 *
2342
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2343
 * lossy if the nodata value cannot exactly been represented by a double.
2344
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2345
 *
2346
 * This method is the same as the C function GDALGetRasterNoDataValue().
2347
 *
2348
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2349
 * is actually associated with this layer.  May be NULL (default).
2350
 *
2351
 * @return the nodata value for this band.
2352
 */
2353
2354
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2355
2356
0
{
2357
0
    if (pbSuccess != nullptr)
2358
0
        *pbSuccess = FALSE;
2359
2360
0
    return -1e10;
2361
0
}
2362
2363
/************************************************************************/
2364
/*                      GDALGetRasterNoDataValue()                      */
2365
/************************************************************************/
2366
2367
/**
2368
 * \brief Fetch the no data value for this band.
2369
 *
2370
 * @see GDALRasterBand::GetNoDataValue()
2371
 */
2372
2373
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2374
                                            int *pbSuccess)
2375
2376
0
{
2377
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2378
2379
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2380
0
    return poBand->GetNoDataValue(pbSuccess);
2381
0
}
2382
2383
/************************************************************************/
2384
/*                       GetNoDataValueAsInt64()                        */
2385
/************************************************************************/
2386
2387
/**
2388
 * \brief Fetch the no data value for this band.
2389
 *
2390
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2391
 *
2392
 * If there is no out of data value, an out of range value will generally
2393
 * be returned.  The no data value for a band is generally a special marker
2394
 * value used to mark pixels that are not valid data.  Such pixels should
2395
 * generally not be displayed, nor contribute to analysis operations.
2396
 *
2397
 * The no data value returned is 'raw', meaning that it has no offset and
2398
 * scale applied.
2399
 *
2400
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2401
 *
2402
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2403
 * is actually associated with this layer.  May be NULL (default).
2404
 *
2405
 * @return the nodata value for this band.
2406
 *
2407
 * @since GDAL 3.5
2408
 */
2409
2410
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2411
2412
0
{
2413
0
    if (pbSuccess != nullptr)
2414
0
        *pbSuccess = FALSE;
2415
2416
0
    return std::numeric_limits<int64_t>::min();
2417
0
}
2418
2419
/************************************************************************/
2420
/*                  GDALGetRasterNoDataValueAsInt64()                   */
2421
/************************************************************************/
2422
2423
/**
2424
 * \brief Fetch the no data value for this band.
2425
 *
2426
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2427
 *
2428
 * @see GDALRasterBand::GetNoDataValueAsInt64()
2429
 *
2430
 * @since GDAL 3.5
2431
 */
2432
2433
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2434
                                                    int *pbSuccess)
2435
2436
0
{
2437
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2438
0
                      std::numeric_limits<int64_t>::min());
2439
2440
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2441
0
    return poBand->GetNoDataValueAsInt64(pbSuccess);
2442
0
}
2443
2444
/************************************************************************/
2445
/*                       GetNoDataValueAsUInt64()                       */
2446
/************************************************************************/
2447
2448
/**
2449
 * \brief Fetch the no data value for this band.
2450
 *
2451
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2452
 *
2453
 * If there is no out of data value, an out of range value will generally
2454
 * be returned.  The no data value for a band is generally a special marker
2455
 * value used to mark pixels that are not valid data.  Such pixels should
2456
 * generally not be displayed, nor contribute to analysis operations.
2457
 *
2458
 * The no data value returned is 'raw', meaning that it has no offset and
2459
 * scale applied.
2460
 *
2461
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2462
 *
2463
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2464
 * is actually associated with this layer.  May be NULL (default).
2465
 *
2466
 * @return the nodata value for this band.
2467
 *
2468
 * @since GDAL 3.5
2469
 */
2470
2471
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2472
2473
0
{
2474
0
    if (pbSuccess != nullptr)
2475
0
        *pbSuccess = FALSE;
2476
2477
0
    return std::numeric_limits<uint64_t>::max();
2478
0
}
2479
2480
/************************************************************************/
2481
/*                  GDALGetRasterNoDataValueAsUInt64()                  */
2482
/************************************************************************/
2483
2484
/**
2485
 * \brief Fetch the no data value for this band.
2486
 *
2487
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2488
 *
2489
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
2490
 *
2491
 * @since GDAL 3.5
2492
 */
2493
2494
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2495
                                                      int *pbSuccess)
2496
2497
0
{
2498
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2499
0
                      std::numeric_limits<uint64_t>::max());
2500
2501
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2502
0
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
2503
0
}
2504
2505
/************************************************************************/
2506
/*                       SetNoDataValueAsString()                       */
2507
/************************************************************************/
2508
2509
/**
2510
 * \brief Set the no data value for this band.
2511
 *
2512
 * Depending on drivers, changing the no data value may or may not have an
2513
 * effect on the pixel values of a raster that has just been created. It is
2514
 * thus advised to explicitly called Fill() if the intent is to initialize
2515
 * the raster to the nodata value.
2516
 * In any case, changing an existing no data value, when one already exists and
2517
 * the dataset exists or has been initialized, has no effect on the pixel whose
2518
 * value matched the previous nodata value.
2519
 *
2520
 * To clear the nodata value, use DeleteNoDataValue().
2521
 *
2522
 * @param pszNoData the value to set.
2523
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2524
 *             If the value cannot be exactly represented on the output data
2525
 *             type, *pbCannotBeExactlyRepresented will be set to true.
2526
 *
2527
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2528
 * by the driver, CE_Failure is returned but no error message will have
2529
 * been emitted.
2530
 *
2531
 * @since 3.11
2532
 */
2533
2534
CPLErr
2535
GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2536
                                       bool *pbCannotBeExactlyRepresented)
2537
0
{
2538
0
    if (pbCannotBeExactlyRepresented)
2539
0
        *pbCannotBeExactlyRepresented = false;
2540
0
    if (eDataType == GDT_Int64)
2541
0
    {
2542
0
        if (strchr(pszNoData, '.') ||
2543
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2544
0
        {
2545
0
            char *endptr = nullptr;
2546
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2547
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2548
0
                GDALIsValueExactAs<int64_t>(dfVal))
2549
0
            {
2550
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2551
0
            }
2552
0
        }
2553
0
        else
2554
0
        {
2555
0
            try
2556
0
            {
2557
0
                const auto val = std::stoll(pszNoData);
2558
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2559
0
            }
2560
0
            catch (const std::exception &)
2561
0
            {
2562
0
            }
2563
0
        }
2564
0
    }
2565
0
    else if (eDataType == GDT_UInt64)
2566
0
    {
2567
0
        if (strchr(pszNoData, '.') ||
2568
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2569
0
        {
2570
0
            char *endptr = nullptr;
2571
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2572
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2573
0
                GDALIsValueExactAs<uint64_t>(dfVal))
2574
0
            {
2575
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2576
0
            }
2577
0
        }
2578
0
        else
2579
0
        {
2580
0
            try
2581
0
            {
2582
0
                const auto val = std::stoull(pszNoData);
2583
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2584
0
            }
2585
0
            catch (const std::exception &)
2586
0
            {
2587
0
            }
2588
0
        }
2589
0
    }
2590
0
    else if (eDataType == GDT_Float32)
2591
0
    {
2592
0
        char *endptr = nullptr;
2593
0
        const float fVal = CPLStrtof(pszNoData, &endptr);
2594
0
        if (endptr == pszNoData + strlen(pszNoData))
2595
0
        {
2596
0
            return SetNoDataValue(double(fVal));
2597
0
        }
2598
0
    }
2599
0
    else
2600
0
    {
2601
0
        char *endptr = nullptr;
2602
0
        const double dfVal = CPLStrtod(pszNoData, &endptr);
2603
0
        if (endptr == pszNoData + strlen(pszNoData) &&
2604
0
            GDALIsValueExactAs(dfVal, eDataType))
2605
0
        {
2606
0
            return SetNoDataValue(dfVal);
2607
0
        }
2608
0
    }
2609
0
    if (pbCannotBeExactlyRepresented)
2610
0
        *pbCannotBeExactlyRepresented = true;
2611
0
    return CE_Failure;
2612
0
}
2613
2614
/************************************************************************/
2615
/*                           SetNoDataValue()                           */
2616
/************************************************************************/
2617
2618
/**
2619
 * \fn GDALRasterBand::SetNoDataValue(double)
2620
 * \brief Set the no data value for this band.
2621
 *
2622
 * Depending on drivers, changing the no data value may or may not have an
2623
 * effect on the pixel values of a raster that has just been created. It is
2624
 * thus advised to explicitly called Fill() if the intent is to initialize
2625
 * the raster to the nodata value.
2626
 * In any case, changing an existing no data value, when one already exists and
2627
 * the dataset exists or has been initialized, has no effect on the pixel whose
2628
 * value matched the previous nodata value.
2629
 *
2630
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2631
 * be represented by a double, use SetNoDataValueAsInt64() or
2632
 * SetNoDataValueAsUInt64() instead.
2633
 *
2634
 * To clear the nodata value, use DeleteNoDataValue().
2635
 *
2636
 * This method is the same as the C function GDALSetRasterNoDataValue().
2637
 *
2638
 * @param dfNoData the value to set.
2639
 *
2640
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2641
 * by the driver, CE_Failure is returned but no error message will have
2642
 * been emitted.
2643
 */
2644
2645
/**/
2646
/**/
2647
2648
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2649
2650
0
{
2651
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2652
0
        ReportError(CE_Failure, CPLE_NotSupported,
2653
0
                    "SetNoDataValue() not supported for this dataset.");
2654
2655
0
    return CE_Failure;
2656
0
}
2657
2658
/************************************************************************/
2659
/*                      GDALSetRasterNoDataValue()                      */
2660
/************************************************************************/
2661
2662
/**
2663
 * \brief Set the no data value for this band.
2664
 *
2665
 * Depending on drivers, changing the no data value may or may not have an
2666
 * effect on the pixel values of a raster that has just been created. It is
2667
 * thus advised to explicitly called Fill() if the intent is to initialize
2668
 * the raster to the nodata value.
2669
 * In any case, changing an existing no data value, when one already exists and
2670
 * the dataset exists or has been initialized, has no effect on the pixel whose
2671
 * value matched the previous nodata value.
2672
 *
2673
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2674
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2675
 * GDALSetRasterNoDataValueAsUInt64() instead.
2676
 *
2677
 * @see GDALRasterBand::SetNoDataValue()
2678
 */
2679
2680
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2681
                                            double dfValue)
2682
2683
0
{
2684
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2685
2686
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2687
0
    return poBand->SetNoDataValue(dfValue);
2688
0
}
2689
2690
/************************************************************************/
2691
/*                       SetNoDataValueAsInt64()                        */
2692
/************************************************************************/
2693
2694
/**
2695
 * \brief Set the no data value for this band.
2696
 *
2697
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2698
 *
2699
 * Depending on drivers, changing the no data value may or may not have an
2700
 * effect on the pixel values of a raster that has just been created. It is
2701
 * thus advised to explicitly called Fill() if the intent is to initialize
2702
 * the raster to the nodata value.
2703
 * In ay case, changing an existing no data value, when one already exists and
2704
 * the dataset exists or has been initialized, has no effect on the pixel whose
2705
 * value matched the previous nodata value.
2706
 *
2707
 * To clear the nodata value, use DeleteNoDataValue().
2708
 *
2709
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2710
 *
2711
 * @param nNoDataValue the value to set.
2712
 *
2713
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2714
 * by the driver, CE_Failure is returned but no error message will have
2715
 * been emitted.
2716
 *
2717
 * @since GDAL 3.5
2718
 */
2719
2720
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2721
2722
0
{
2723
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2724
0
        ReportError(CE_Failure, CPLE_NotSupported,
2725
0
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2726
2727
0
    return CE_Failure;
2728
0
}
2729
2730
/************************************************************************/
2731
/*                  GDALSetRasterNoDataValueAsInt64()                   */
2732
/************************************************************************/
2733
2734
/**
2735
 * \brief Set the no data value for this band.
2736
 *
2737
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2738
 *
2739
 * Depending on drivers, changing the no data value may or may not have an
2740
 * effect on the pixel values of a raster that has just been created. It is
2741
 * thus advised to explicitly called Fill() if the intent is to initialize
2742
 * the raster to the nodata value.
2743
 * In ay case, changing an existing no data value, when one already exists and
2744
 * the dataset exists or has been initialized, has no effect on the pixel whose
2745
 * value matched the previous nodata value.
2746
 *
2747
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2748
 *
2749
 * @since GDAL 3.5
2750
 */
2751
2752
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2753
                                                   int64_t nValue)
2754
2755
0
{
2756
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2757
2758
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2759
0
    return poBand->SetNoDataValueAsInt64(nValue);
2760
0
}
2761
2762
/************************************************************************/
2763
/*                       SetNoDataValueAsUInt64()                       */
2764
/************************************************************************/
2765
2766
/**
2767
 * \brief Set the no data value for this band.
2768
 *
2769
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2770
 *
2771
 * Depending on drivers, changing the no data value may or may not have an
2772
 * effect on the pixel values of a raster that has just been created. It is
2773
 * thus advised to explicitly called Fill() if the intent is to initialize
2774
 * the raster to the nodata value.
2775
 * In ay case, changing an existing no data value, when one already exists and
2776
 * the dataset exists or has been initialized, has no effect on the pixel whose
2777
 * value matched the previous nodata value.
2778
 *
2779
 * To clear the nodata value, use DeleteNoDataValue().
2780
 *
2781
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2782
 *
2783
 * @param nNoDataValue the value to set.
2784
 *
2785
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2786
 * by the driver, CE_Failure is returned but no error message will have
2787
 * been emitted.
2788
 *
2789
 * @since GDAL 3.5
2790
 */
2791
2792
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2793
2794
0
{
2795
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2796
0
        ReportError(CE_Failure, CPLE_NotSupported,
2797
0
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2798
2799
0
    return CE_Failure;
2800
0
}
2801
2802
/************************************************************************/
2803
/*                  GDALSetRasterNoDataValueAsUInt64()                  */
2804
/************************************************************************/
2805
2806
/**
2807
 * \brief Set the no data value for this band.
2808
 *
2809
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2810
 *
2811
 * Depending on drivers, changing the no data value may or may not have an
2812
 * effect on the pixel values of a raster that has just been created. It is
2813
 * thus advised to explicitly called Fill() if the intent is to initialize
2814
 * the raster to the nodata value.
2815
 * In ay case, changing an existing no data value, when one already exists and
2816
 * the dataset exists or has been initialized, has no effect on the pixel whose
2817
 * value matched the previous nodata value.
2818
 *
2819
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2820
 *
2821
 * @since GDAL 3.5
2822
 */
2823
2824
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2825
                                                    uint64_t nValue)
2826
2827
0
{
2828
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2829
2830
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2831
0
    return poBand->SetNoDataValueAsUInt64(nValue);
2832
0
}
2833
2834
/************************************************************************/
2835
/*                         DeleteNoDataValue()                          */
2836
/************************************************************************/
2837
2838
/**
2839
 * \brief Remove the no data value for this band.
2840
 *
2841
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2842
 *
2843
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2844
 * by the driver, CE_Failure is returned but no error message will have
2845
 * been emitted.
2846
 *
2847
 */
2848
2849
CPLErr GDALRasterBand::DeleteNoDataValue()
2850
2851
0
{
2852
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2853
0
        ReportError(CE_Failure, CPLE_NotSupported,
2854
0
                    "DeleteNoDataValue() not supported for this dataset.");
2855
2856
0
    return CE_Failure;
2857
0
}
2858
2859
/************************************************************************/
2860
/*                    GDALDeleteRasterNoDataValue()                     */
2861
/************************************************************************/
2862
2863
/**
2864
 * \brief Remove the no data value for this band.
2865
 *
2866
 * @see GDALRasterBand::DeleteNoDataValue()
2867
 *
2868
 */
2869
2870
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2871
2872
0
{
2873
0
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2874
2875
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2876
0
    return poBand->DeleteNoDataValue();
2877
0
}
2878
2879
/************************************************************************/
2880
/*                             GetMaximum()                             */
2881
/************************************************************************/
2882
2883
/**
2884
 * \brief Fetch the maximum value for this band.
2885
 *
2886
 * For file formats that don't know this intrinsically, the maximum supported
2887
 * value for the data type will generally be returned.
2888
 *
2889
 * This method is the same as the C function GDALGetRasterMaximum().
2890
 *
2891
 * @param pbSuccess pointer to a boolean to use to indicate if the
2892
 * returned value is a tight maximum or not.  May be NULL (default).
2893
 *
2894
 * @return the maximum raster value (excluding no data pixels)
2895
 */
2896
2897
double GDALRasterBand::GetMaximum(int *pbSuccess)
2898
2899
0
{
2900
0
    const char *pszValue = nullptr;
2901
2902
0
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2903
0
    {
2904
0
        if (pbSuccess != nullptr)
2905
0
            *pbSuccess = TRUE;
2906
2907
0
        return CPLAtofM(pszValue);
2908
0
    }
2909
2910
0
    if (pbSuccess != nullptr)
2911
0
        *pbSuccess = FALSE;
2912
2913
0
    switch (eDataType)
2914
0
    {
2915
0
        case GDT_UInt8:
2916
0
        {
2917
0
            EnablePixelTypeSignedByteWarning(false);
2918
0
            const char *pszPixelType =
2919
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2920
0
            EnablePixelTypeSignedByteWarning(true);
2921
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2922
0
                return 127;
2923
2924
0
            return 255;
2925
0
        }
2926
2927
0
        case GDT_Int8:
2928
0
            return 127;
2929
2930
0
        case GDT_UInt16:
2931
0
            return 65535;
2932
2933
0
        case GDT_Int16:
2934
0
        case GDT_CInt16:
2935
0
            return 32767;
2936
2937
0
        case GDT_Int32:
2938
0
        case GDT_CInt32:
2939
0
            return 2147483647.0;
2940
2941
0
        case GDT_UInt32:
2942
0
            return 4294967295.0;
2943
2944
0
        case GDT_Int64:
2945
0
            return static_cast<double>(std::numeric_limits<GInt64>::max());
2946
2947
0
        case GDT_UInt64:
2948
0
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
2949
2950
0
        case GDT_Float16:
2951
0
        case GDT_CFloat16:
2952
0
            return 65504.0;
2953
2954
0
        case GDT_Float32:
2955
0
        case GDT_CFloat32:
2956
0
            return 4294967295.0;  // Not actually accurate.
2957
2958
0
        case GDT_Float64:
2959
0
        case GDT_CFloat64:
2960
0
            return 4294967295.0;  // Not actually accurate.
2961
2962
0
        case GDT_Unknown:
2963
0
        case GDT_TypeCount:
2964
0
            break;
2965
0
    }
2966
0
    return 4294967295.0;  // Not actually accurate.
2967
0
}
2968
2969
/************************************************************************/
2970
/*                        GDALGetRasterMaximum()                        */
2971
/************************************************************************/
2972
2973
/**
2974
 * \brief Fetch the maximum value for this band.
2975
 *
2976
 * @see GDALRasterBand::GetMaximum()
2977
 */
2978
2979
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2980
2981
0
{
2982
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2983
2984
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2985
0
    return poBand->GetMaximum(pbSuccess);
2986
0
}
2987
2988
/************************************************************************/
2989
/*                             GetMinimum()                             */
2990
/************************************************************************/
2991
2992
/**
2993
 * \brief Fetch the minimum value for this band.
2994
 *
2995
 * For file formats that don't know this intrinsically, the minimum supported
2996
 * value for the data type will generally be returned.
2997
 *
2998
 * This method is the same as the C function GDALGetRasterMinimum().
2999
 *
3000
 * @param pbSuccess pointer to a boolean to use to indicate if the
3001
 * returned value is a tight minimum or not.  May be NULL (default).
3002
 *
3003
 * @return the minimum raster value (excluding no data pixels)
3004
 */
3005
3006
double GDALRasterBand::GetMinimum(int *pbSuccess)
3007
3008
0
{
3009
0
    const char *pszValue = nullptr;
3010
3011
0
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3012
0
    {
3013
0
        if (pbSuccess != nullptr)
3014
0
            *pbSuccess = TRUE;
3015
3016
0
        return CPLAtofM(pszValue);
3017
0
    }
3018
3019
0
    if (pbSuccess != nullptr)
3020
0
        *pbSuccess = FALSE;
3021
3022
0
    switch (eDataType)
3023
0
    {
3024
0
        case GDT_UInt8:
3025
0
        {
3026
0
            EnablePixelTypeSignedByteWarning(false);
3027
0
            const char *pszPixelType =
3028
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3029
0
            EnablePixelTypeSignedByteWarning(true);
3030
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3031
0
                return -128;
3032
3033
0
            return 0;
3034
0
        }
3035
3036
0
        case GDT_Int8:
3037
0
            return -128;
3038
3039
0
        case GDT_UInt16:
3040
0
            return 0;
3041
3042
0
        case GDT_Int16:
3043
0
        case GDT_CInt16:
3044
0
            return -32768;
3045
3046
0
        case GDT_Int32:
3047
0
        case GDT_CInt32:
3048
0
            return -2147483648.0;
3049
3050
0
        case GDT_UInt32:
3051
0
            return 0;
3052
3053
0
        case GDT_Int64:
3054
0
            return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3055
3056
0
        case GDT_UInt64:
3057
0
            return 0;
3058
3059
0
        case GDT_Float16:
3060
0
        case GDT_CFloat16:
3061
0
            return -65504.0;
3062
3063
0
        case GDT_Float32:
3064
0
        case GDT_CFloat32:
3065
0
            return -4294967295.0;  // Not actually accurate.
3066
3067
0
        case GDT_Float64:
3068
0
        case GDT_CFloat64:
3069
0
            return -4294967295.0;  // Not actually accurate.
3070
3071
0
        case GDT_Unknown:
3072
0
        case GDT_TypeCount:
3073
0
            break;
3074
0
    }
3075
0
    return -4294967295.0;  // Not actually accurate.
3076
0
}
3077
3078
/************************************************************************/
3079
/*                        GDALGetRasterMinimum()                        */
3080
/************************************************************************/
3081
3082
/**
3083
 * \brief Fetch the minimum value for this band.
3084
 *
3085
 * @see GDALRasterBand::GetMinimum()
3086
 */
3087
3088
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3089
3090
0
{
3091
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3092
3093
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3094
0
    return poBand->GetMinimum(pbSuccess);
3095
0
}
3096
3097
/************************************************************************/
3098
/*                       GetColorInterpretation()                       */
3099
/************************************************************************/
3100
3101
/**
3102
 * \brief How should this band be interpreted as color?
3103
 *
3104
 * GCI_Undefined is returned when the format doesn't know anything
3105
 * about the color interpretation.
3106
 *
3107
 * This method is the same as the C function
3108
 * GDALGetRasterColorInterpretation().
3109
 *
3110
 * @return color interpretation value for band.
3111
 */
3112
3113
GDALColorInterp GDALRasterBand::GetColorInterpretation()
3114
3115
0
{
3116
0
    return GCI_Undefined;
3117
0
}
3118
3119
/************************************************************************/
3120
/*                  GDALGetRasterColorInterpretation()                  */
3121
/************************************************************************/
3122
3123
/**
3124
 * \brief How should this band be interpreted as color?
3125
 *
3126
 * @see GDALRasterBand::GetColorInterpretation()
3127
 */
3128
3129
GDALColorInterp CPL_STDCALL
3130
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3131
3132
0
{
3133
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3134
3135
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3136
0
    return poBand->GetColorInterpretation();
3137
0
}
3138
3139
/************************************************************************/
3140
/*                       SetColorInterpretation()                       */
3141
/************************************************************************/
3142
3143
/**
3144
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3145
 * \brief Set color interpretation of a band.
3146
 *
3147
 * This method is the same as the C function GDALSetRasterColorInterpretation().
3148
 *
3149
 * @param eColorInterp the new color interpretation to apply to this band.
3150
 *
3151
 * @return CE_None on success or CE_Failure if method is unsupported by format.
3152
 */
3153
3154
/**/
3155
/**/
3156
3157
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3158
3159
0
{
3160
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3161
0
        ReportError(CE_Failure, CPLE_NotSupported,
3162
0
                    "SetColorInterpretation() not supported for this dataset.");
3163
0
    return CE_Failure;
3164
0
}
3165
3166
/************************************************************************/
3167
/*                  GDALSetRasterColorInterpretation()                  */
3168
/************************************************************************/
3169
3170
/**
3171
 * \brief Set color interpretation of a band.
3172
 *
3173
 * @see GDALRasterBand::SetColorInterpretation()
3174
 */
3175
3176
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3177
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3178
3179
0
{
3180
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3181
3182
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3183
0
    return poBand->SetColorInterpretation(eColorInterp);
3184
0
}
3185
3186
/************************************************************************/
3187
/*                           GetColorTable()                            */
3188
/************************************************************************/
3189
3190
/**
3191
 * \brief Fetch the color table associated with band.
3192
 *
3193
 * If there is no associated color table, the return result is NULL.  The
3194
 * returned color table remains owned by the GDALRasterBand, and can't
3195
 * be depended on for long, nor should it ever be modified by the caller.
3196
 *
3197
 * This method is the same as the C function GDALGetRasterColorTable().
3198
 *
3199
 * @return internal color table, or NULL.
3200
 */
3201
3202
GDALColorTable *GDALRasterBand::GetColorTable()
3203
3204
0
{
3205
0
    return nullptr;
3206
0
}
3207
3208
/************************************************************************/
3209
/*                      GDALGetRasterColorTable()                       */
3210
/************************************************************************/
3211
3212
/**
3213
 * \brief Fetch the color table associated with band.
3214
 *
3215
 * @see GDALRasterBand::GetColorTable()
3216
 */
3217
3218
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3219
3220
0
{
3221
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3222
3223
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3224
0
    return GDALColorTable::ToHandle(poBand->GetColorTable());
3225
0
}
3226
3227
/************************************************************************/
3228
/*                           SetColorTable()                            */
3229
/************************************************************************/
3230
3231
/**
3232
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3233
 * \brief Set the raster color table.
3234
 *
3235
 * The driver will make a copy of all desired data in the colortable.  It
3236
 * remains owned by the caller after the call.
3237
 *
3238
 * This method is the same as the C function GDALSetRasterColorTable().
3239
 *
3240
 * @param poCT the color table to apply.  This may be NULL to clear the color
3241
 * table (where supported).
3242
 *
3243
 * @return CE_None on success, or CE_Failure on failure.  If the action is
3244
 * unsupported by the driver, a value of CE_Failure is returned, but no
3245
 * error is issued.
3246
 */
3247
3248
/**/
3249
/**/
3250
3251
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3252
3253
0
{
3254
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3255
0
        ReportError(CE_Failure, CPLE_NotSupported,
3256
0
                    "SetColorTable() not supported for this dataset.");
3257
0
    return CE_Failure;
3258
0
}
3259
3260
/************************************************************************/
3261
/*                      GDALSetRasterColorTable()                       */
3262
/************************************************************************/
3263
3264
/**
3265
 * \brief Set the raster color table.
3266
 *
3267
 * @see GDALRasterBand::SetColorTable()
3268
 */
3269
3270
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3271
                                           GDALColorTableH hCT)
3272
3273
0
{
3274
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3275
3276
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3277
0
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3278
0
}
3279
3280
/************************************************************************/
3281
/*                       HasArbitraryOverviews()                        */
3282
/************************************************************************/
3283
3284
/**
3285
 * \brief Check for arbitrary overviews.
3286
 *
3287
 * This returns TRUE if the underlying datastore can compute arbitrary
3288
 * overviews efficiently, such as is the case with OGDI over a network.
3289
 * Datastores with arbitrary overviews don't generally have any fixed
3290
 * overviews, but the RasterIO() method can be used in downsampling mode
3291
 * to get overview data efficiently.
3292
 *
3293
 * This method is the same as the C function GDALHasArbitraryOverviews(),
3294
 *
3295
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
3296
 * FALSE.
3297
 */
3298
3299
int GDALRasterBand::HasArbitraryOverviews()
3300
3301
0
{
3302
0
    return FALSE;
3303
0
}
3304
3305
/************************************************************************/
3306
/*                     GDALHasArbitraryOverviews()                      */
3307
/************************************************************************/
3308
3309
/**
3310
 * \brief Check for arbitrary overviews.
3311
 *
3312
 * @see GDALRasterBand::HasArbitraryOverviews()
3313
 */
3314
3315
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3316
3317
0
{
3318
0
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3319
3320
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3321
0
    return poBand->HasArbitraryOverviews();
3322
0
}
3323
3324
/************************************************************************/
3325
/*                          GetOverviewCount()                          */
3326
/************************************************************************/
3327
3328
/**
3329
 * \brief Return the number of overview layers available.
3330
 *
3331
 * This method is the same as the C function GDALGetOverviewCount().
3332
 *
3333
 * @return overview count, zero if none.
3334
 */
3335
3336
int GDALRasterBand::GetOverviewCount()
3337
3338
0
{
3339
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3340
0
        poDS->AreOverviewsEnabled())
3341
0
        return poDS->oOvManager.GetOverviewCount(nBand);
3342
3343
0
    return 0;
3344
0
}
3345
3346
/************************************************************************/
3347
/*                        GDALGetOverviewCount()                        */
3348
/************************************************************************/
3349
3350
/**
3351
 * \brief Return the number of overview layers available.
3352
 *
3353
 * @see GDALRasterBand::GetOverviewCount()
3354
 */
3355
3356
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3357
3358
0
{
3359
0
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3360
3361
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3362
0
    return poBand->GetOverviewCount();
3363
0
}
3364
3365
/************************************************************************/
3366
/*                            GetOverview()                             */
3367
/************************************************************************/
3368
3369
/**
3370
 * \brief Fetch overview raster band object.
3371
 *
3372
 * This method is the same as the C function GDALGetOverview().
3373
 *
3374
 * @param i overview index between 0 and GetOverviewCount()-1.
3375
 *
3376
 * @return overview GDALRasterBand.
3377
 */
3378
3379
GDALRasterBand *GDALRasterBand::GetOverview(int i)
3380
3381
0
{
3382
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3383
0
        poDS->AreOverviewsEnabled())
3384
0
        return poDS->oOvManager.GetOverview(nBand, i);
3385
3386
0
    return nullptr;
3387
0
}
3388
3389
/************************************************************************/
3390
/*                          GDALGetOverview()                           */
3391
/************************************************************************/
3392
3393
/**
3394
 * \brief Fetch overview raster band object.
3395
 *
3396
 * @see GDALRasterBand::GetOverview()
3397
 */
3398
3399
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3400
3401
0
{
3402
0
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3403
3404
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3405
0
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3406
0
}
3407
3408
/************************************************************************/
3409
/*                      GetRasterSampleOverview()                       */
3410
/************************************************************************/
3411
3412
/**
3413
 * \brief Fetch best sampling overview.
3414
 *
3415
 * Returns the most reduced overview of the given band that still satisfies
3416
 * the desired number of samples.  This function can be used with zero
3417
 * as the number of desired samples to fetch the most reduced overview.
3418
 * The same band as was passed in will be returned if it has not overviews,
3419
 * or if none of the overviews have enough samples.
3420
 *
3421
 * This method is the same as the C functions GDALGetRasterSampleOverview()
3422
 * and GDALGetRasterSampleOverviewEx().
3423
 *
3424
 * @param nDesiredSamples the returned band will have at least this many
3425
 * pixels.
3426
 *
3427
 * @return optimal overview or the band itself.
3428
 */
3429
3430
GDALRasterBand *
3431
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3432
3433
0
{
3434
0
    GDALRasterBand *poBestBand = this;
3435
3436
0
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3437
3438
0
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3439
0
    {
3440
0
        GDALRasterBand *poOBand = GetOverview(iOverview);
3441
3442
0
        if (poOBand == nullptr)
3443
0
            continue;
3444
3445
0
        const double dfOSamples =
3446
0
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3447
3448
0
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3449
0
        {
3450
0
            dfBestSamples = dfOSamples;
3451
0
            poBestBand = poOBand;
3452
0
        }
3453
0
    }
3454
3455
0
    return poBestBand;
3456
0
}
3457
3458
/************************************************************************/
3459
/*                    GDALGetRasterSampleOverview()                     */
3460
/************************************************************************/
3461
3462
/**
3463
 * \brief Fetch best sampling overview.
3464
 *
3465
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3466
 * billion samples.
3467
 *
3468
 * @see GDALRasterBand::GetRasterSampleOverview()
3469
 * @see GDALGetRasterSampleOverviewEx()
3470
 */
3471
3472
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3473
                                                        int nDesiredSamples)
3474
3475
0
{
3476
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3477
3478
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3479
0
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3480
0
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3481
0
}
3482
3483
/************************************************************************/
3484
/*                   GDALGetRasterSampleOverviewEx()                    */
3485
/************************************************************************/
3486
3487
/**
3488
 * \brief Fetch best sampling overview.
3489
 *
3490
 * @see GDALRasterBand::GetRasterSampleOverview()
3491
 */
3492
3493
GDALRasterBandH CPL_STDCALL
3494
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3495
3496
0
{
3497
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3498
3499
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3500
0
    return GDALRasterBand::ToHandle(
3501
0
        poBand->GetRasterSampleOverview(nDesiredSamples));
3502
0
}
3503
3504
/************************************************************************/
3505
/*                           BuildOverviews()                           */
3506
/************************************************************************/
3507
3508
/**
3509
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3510
 * GDALProgressFunc, void*) \brief Build raster overview(s)
3511
 *
3512
 * If the operation is unsupported for the indicated dataset, then
3513
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
3514
 * CPLE_NotSupported.
3515
 *
3516
 * WARNING: Most formats don't support per-band overview computation, but
3517
 * require that overviews are computed for all bands of a dataset, using
3518
 * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3519
 * is the HFA driver which supports this method.
3520
 *
3521
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3522
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3523
 * applied.
3524
 * @param nOverviews number of overviews to build.
3525
 * @param panOverviewList the list of overview decimation factors to build.
3526
 * @param pfnProgress a function to call to report progress, or NULL.
3527
 * @param pProgressData application data to pass to the progress function.
3528
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3529
 *                     key=value pairs, or NULL
3530
 *
3531
 * @return CE_None on success or CE_Failure if the operation doesn't work.
3532
 */
3533
3534
/**/
3535
/**/
3536
3537
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3538
                                      int /*nOverviews*/,
3539
                                      const int * /*panOverviewList*/,
3540
                                      GDALProgressFunc /*pfnProgress*/,
3541
                                      void * /*pProgressData*/,
3542
                                      CSLConstList /* papszOptions */)
3543
3544
0
{
3545
0
    ReportError(CE_Failure, CPLE_NotSupported,
3546
0
                "BuildOverviews() not supported for this dataset.");
3547
3548
0
    return (CE_Failure);
3549
0
}
3550
3551
/************************************************************************/
3552
/*                             GetOffset()                              */
3553
/************************************************************************/
3554
3555
/**
3556
 * \brief Fetch the raster value offset.
3557
 *
3558
 * This value (in combination with the GetScale() value) can be used to
3559
 * transform raw pixel values into the units returned by GetUnitType().
3560
 * For example this might be used to store elevations in GUInt16 bands
3561
 * with a precision of 0.1, and starting from -100.
3562
 *
3563
 * Units value = (raw value * scale) + offset
3564
 *
3565
 * Note that applying scale and offset is of the responsibility of the user,
3566
 * and is not done by methods such as RasterIO() or ReadBlock().
3567
 *
3568
 * For file formats that don't know this intrinsically a value of zero
3569
 * is returned.
3570
 *
3571
 * This method is the same as the C function GDALGetRasterOffset().
3572
 *
3573
 * @param pbSuccess pointer to a boolean to use to indicate if the
3574
 * returned value is meaningful or not.  May be NULL (default).
3575
 *
3576
 * @return the raster offset.
3577
 */
3578
3579
double GDALRasterBand::GetOffset(int *pbSuccess)
3580
3581
0
{
3582
0
    if (pbSuccess != nullptr)
3583
0
        *pbSuccess = FALSE;
3584
3585
0
    return 0.0;
3586
0
}
3587
3588
/************************************************************************/
3589
/*                        GDALGetRasterOffset()                         */
3590
/************************************************************************/
3591
3592
/**
3593
 * \brief Fetch the raster value offset.
3594
 *
3595
 * @see GDALRasterBand::GetOffset()
3596
 */
3597
3598
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3599
3600
0
{
3601
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3602
3603
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3604
0
    return poBand->GetOffset(pbSuccess);
3605
0
}
3606
3607
/************************************************************************/
3608
/*                             SetOffset()                              */
3609
/************************************************************************/
3610
3611
/**
3612
 * \fn GDALRasterBand::SetOffset(double)
3613
 * \brief Set scaling offset.
3614
 *
3615
 * Very few formats implement this method.   When not implemented it will
3616
 * issue a CPLE_NotSupported error and return CE_Failure.
3617
 *
3618
 * This method is the same as the C function GDALSetRasterOffset().
3619
 *
3620
 * @param dfNewOffset the new offset.
3621
 *
3622
 * @return CE_None or success or CE_Failure on failure.
3623
 */
3624
3625
/**/
3626
/**/
3627
3628
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3629
0
{
3630
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3631
0
        ReportError(CE_Failure, CPLE_NotSupported,
3632
0
                    "SetOffset() not supported on this raster band.");
3633
3634
0
    return CE_Failure;
3635
0
}
3636
3637
/************************************************************************/
3638
/*                        GDALSetRasterOffset()                         */
3639
/************************************************************************/
3640
3641
/**
3642
 * \brief Set scaling offset.
3643
 *
3644
 * @see GDALRasterBand::SetOffset()
3645
 */
3646
3647
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3648
                                       double dfNewOffset)
3649
3650
0
{
3651
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3652
3653
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3654
0
    return poBand->SetOffset(dfNewOffset);
3655
0
}
3656
3657
/************************************************************************/
3658
/*                              GetScale()                              */
3659
/************************************************************************/
3660
3661
/**
3662
 * \brief Fetch the raster value scale.
3663
 *
3664
 * This value (in combination with the GetOffset() value) can be used to
3665
 * transform raw pixel values into the units returned by GetUnitType().
3666
 * For example this might be used to store elevations in GUInt16 bands
3667
 * with a precision of 0.1, and starting from -100.
3668
 *
3669
 * Units value = (raw value * scale) + offset
3670
 *
3671
 * Note that applying scale and offset is of the responsibility of the user,
3672
 * and is not done by methods such as RasterIO() or ReadBlock().
3673
 *
3674
 * For file formats that don't know this intrinsically a value of one
3675
 * is returned.
3676
 *
3677
 * This method is the same as the C function GDALGetRasterScale().
3678
 *
3679
 * @param pbSuccess pointer to a boolean to use to indicate if the
3680
 * returned value is meaningful or not.  May be NULL (default).
3681
 *
3682
 * @return the raster scale.
3683
 */
3684
3685
double GDALRasterBand::GetScale(int *pbSuccess)
3686
3687
0
{
3688
0
    if (pbSuccess != nullptr)
3689
0
        *pbSuccess = FALSE;
3690
3691
0
    return 1.0;
3692
0
}
3693
3694
/************************************************************************/
3695
/*                         GDALGetRasterScale()                         */
3696
/************************************************************************/
3697
3698
/**
3699
 * \brief Fetch the raster value scale.
3700
 *
3701
 * @see GDALRasterBand::GetScale()
3702
 */
3703
3704
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3705
3706
0
{
3707
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3708
3709
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3710
0
    return poBand->GetScale(pbSuccess);
3711
0
}
3712
3713
/************************************************************************/
3714
/*                              SetScale()                              */
3715
/************************************************************************/
3716
3717
/**
3718
 * \fn GDALRasterBand::SetScale(double)
3719
 * \brief Set scaling ratio.
3720
 *
3721
 * Very few formats implement this method.   When not implemented it will
3722
 * issue a CPLE_NotSupported error and return CE_Failure.
3723
 *
3724
 * This method is the same as the C function GDALSetRasterScale().
3725
 *
3726
 * @param dfNewScale the new scale.
3727
 *
3728
 * @return CE_None or success or CE_Failure on failure.
3729
 */
3730
3731
/**/
3732
/**/
3733
3734
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3735
3736
0
{
3737
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3738
0
        ReportError(CE_Failure, CPLE_NotSupported,
3739
0
                    "SetScale() not supported on this raster band.");
3740
3741
0
    return CE_Failure;
3742
0
}
3743
3744
/************************************************************************/
3745
/*                         GDALSetRasterScale()                         */
3746
/************************************************************************/
3747
3748
/**
3749
 * \brief Set scaling ratio.
3750
 *
3751
 * @see GDALRasterBand::SetScale()
3752
 */
3753
3754
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3755
3756
0
{
3757
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3758
3759
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3760
0
    return poBand->SetScale(dfNewOffset);
3761
0
}
3762
3763
/************************************************************************/
3764
/*                            GetUnitType()                             */
3765
/************************************************************************/
3766
3767
/**
3768
 * \brief Return raster unit type.
3769
 *
3770
 * Return a name for the units of this raster's values.  For instance, it
3771
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3772
 * units are available, a value of "" will be returned.  The returned string
3773
 * should not be modified, nor freed by the calling application.
3774
 *
3775
 * This method is the same as the C function GDALGetRasterUnitType().
3776
 *
3777
 * @return unit name string.
3778
 */
3779
3780
const char *GDALRasterBand::GetUnitType()
3781
3782
0
{
3783
0
    return "";
3784
0
}
3785
3786
/************************************************************************/
3787
/*                       GDALGetRasterUnitType()                        */
3788
/************************************************************************/
3789
3790
/**
3791
 * \brief Return raster unit type.
3792
 *
3793
 * @see GDALRasterBand::GetUnitType()
3794
 */
3795
3796
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3797
3798
0
{
3799
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3800
3801
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3802
0
    return poBand->GetUnitType();
3803
0
}
3804
3805
/************************************************************************/
3806
/*                            SetUnitType()                             */
3807
/************************************************************************/
3808
3809
/**
3810
 * \fn GDALRasterBand::SetUnitType(const char*)
3811
 * \brief Set unit type.
3812
 *
3813
 * Set the unit type for a raster band.  Values should be one of
3814
 * "" (the default indicating it is unknown), "m" indicating meters,
3815
 * or "ft" indicating feet, though other nonstandard values are allowed.
3816
 *
3817
 * This method is the same as the C function GDALSetRasterUnitType().
3818
 *
3819
 * @param pszNewValue the new unit type value.
3820
 *
3821
 * @return CE_None on success or CE_Failure if not successful, or
3822
 * unsupported.
3823
 */
3824
3825
/**/
3826
/**/
3827
3828
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3829
3830
0
{
3831
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3832
0
        ReportError(CE_Failure, CPLE_NotSupported,
3833
0
                    "SetUnitType() not supported on this raster band.");
3834
0
    return CE_Failure;
3835
0
}
3836
3837
/************************************************************************/
3838
/*                       GDALSetRasterUnitType()                        */
3839
/************************************************************************/
3840
3841
/**
3842
 * \brief Set unit type.
3843
 *
3844
 * @see GDALRasterBand::SetUnitType()
3845
 *
3846
 */
3847
3848
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3849
                                         const char *pszNewValue)
3850
3851
0
{
3852
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3853
3854
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3855
0
    return poBand->SetUnitType(pszNewValue);
3856
0
}
3857
3858
/************************************************************************/
3859
/*                              GetXSize()                              */
3860
/************************************************************************/
3861
3862
/**
3863
 * \brief Fetch XSize of raster.
3864
 *
3865
 * This method is the same as the C function GDALGetRasterBandXSize().
3866
 *
3867
 * @return the width in pixels of this band.
3868
 */
3869
3870
int GDALRasterBand::GetXSize() const
3871
3872
0
{
3873
0
    return nRasterXSize;
3874
0
}
3875
3876
/************************************************************************/
3877
/*                       GDALGetRasterBandXSize()                       */
3878
/************************************************************************/
3879
3880
/**
3881
 * \brief Fetch XSize of raster.
3882
 *
3883
 * @see GDALRasterBand::GetXSize()
3884
 */
3885
3886
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3887
3888
0
{
3889
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3890
3891
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3892
0
    return poBand->GetXSize();
3893
0
}
3894
3895
/************************************************************************/
3896
/*                              GetYSize()                              */
3897
/************************************************************************/
3898
3899
/**
3900
 * \brief Fetch YSize of raster.
3901
 *
3902
 * This method is the same as the C function GDALGetRasterBandYSize().
3903
 *
3904
 * @return the height in pixels of this band.
3905
 */
3906
3907
int GDALRasterBand::GetYSize() const
3908
3909
0
{
3910
0
    return nRasterYSize;
3911
0
}
3912
3913
/************************************************************************/
3914
/*                       GDALGetRasterBandYSize()                       */
3915
/************************************************************************/
3916
3917
/**
3918
 * \brief Fetch YSize of raster.
3919
 *
3920
 * @see GDALRasterBand::GetYSize()
3921
 */
3922
3923
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3924
3925
0
{
3926
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3927
3928
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3929
0
    return poBand->GetYSize();
3930
0
}
3931
3932
/************************************************************************/
3933
/*                              GetBand()                               */
3934
/************************************************************************/
3935
3936
/**
3937
 * \brief Fetch the band number.
3938
 *
3939
 * This method returns the band that this GDALRasterBand objects represents
3940
 * within its dataset.  This method may return a value of 0 to indicate
3941
 * GDALRasterBand objects without an apparently relationship to a dataset,
3942
 * such as GDALRasterBands serving as overviews.
3943
 *
3944
 * This method is the same as the C function GDALGetBandNumber().
3945
 *
3946
 * @return band number (1+) or 0 if the band number isn't known.
3947
 */
3948
3949
int GDALRasterBand::GetBand() const
3950
3951
0
{
3952
0
    return nBand;
3953
0
}
3954
3955
/************************************************************************/
3956
/*                         GDALGetBandNumber()                          */
3957
/************************************************************************/
3958
3959
/**
3960
 * \brief Fetch the band number.
3961
 *
3962
 * @see GDALRasterBand::GetBand()
3963
 */
3964
3965
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3966
3967
0
{
3968
0
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3969
3970
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3971
0
    return poBand->GetBand();
3972
0
}
3973
3974
/************************************************************************/
3975
/*                             GetDataset()                             */
3976
/************************************************************************/
3977
3978
/**
3979
 * \brief Fetch the owning dataset handle.
3980
 *
3981
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3982
 * such as overviews or other "freestanding" bands.
3983
 *
3984
 * This method is the same as the C function GDALGetBandDataset().
3985
 *
3986
 * @return the pointer to the GDALDataset to which this band belongs, or
3987
 * NULL if this cannot be determined.
3988
 */
3989
3990
GDALDataset *GDALRasterBand::GetDataset() const
3991
3992
0
{
3993
0
    return poDS;
3994
0
}
3995
3996
/************************************************************************/
3997
/*                         GDALGetBandDataset()                         */
3998
/************************************************************************/
3999
4000
/**
4001
 * \brief Fetch the owning dataset handle.
4002
 *
4003
 * @see GDALRasterBand::GetDataset()
4004
 */
4005
4006
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4007
4008
0
{
4009
0
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4010
4011
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4012
0
    return GDALDataset::ToHandle(poBand->GetDataset());
4013
0
}
4014
4015
/************************************************************************/
4016
/*                     ComputeFloat16NoDataValue()                      */
4017
/************************************************************************/
4018
4019
static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4020
                                             double dfNoDataValue,
4021
                                             int &bGotNoDataValue,
4022
                                             GFloat16 &hfNoDataValue,
4023
                                             bool &bGotFloat16NoDataValue)
4024
0
{
4025
0
    if (eDataType == GDT_Float16 && bGotNoDataValue)
4026
0
    {
4027
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4028
0
        if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4029
0
        {
4030
0
            hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4031
0
            bGotFloat16NoDataValue = true;
4032
0
            bGotNoDataValue = false;
4033
0
        }
4034
0
    }
4035
0
}
4036
4037
/************************************************************************/
4038
/*                      ComputeFloatNoDataValue()                       */
4039
/************************************************************************/
4040
4041
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4042
                                           double dfNoDataValue,
4043
                                           int &bGotNoDataValue,
4044
                                           float &fNoDataValue,
4045
                                           bool &bGotFloatNoDataValue)
4046
0
{
4047
0
    if (eDataType == GDT_Float32 && bGotNoDataValue)
4048
0
    {
4049
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4050
0
        if (GDALIsValueInRange<float>(dfNoDataValue))
4051
0
        {
4052
0
            fNoDataValue = static_cast<float>(dfNoDataValue);
4053
0
            bGotFloatNoDataValue = true;
4054
0
            bGotNoDataValue = false;
4055
0
        }
4056
0
    }
4057
0
    else if (eDataType == GDT_Int16 && bGotNoDataValue &&
4058
0
             GDALIsValueExactAs<int16_t>(dfNoDataValue))
4059
0
    {
4060
0
        fNoDataValue = static_cast<float>(dfNoDataValue);
4061
0
        bGotFloatNoDataValue = true;
4062
0
    }
4063
0
    else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
4064
0
             GDALIsValueExactAs<uint16_t>(dfNoDataValue))
4065
0
    {
4066
0
        fNoDataValue = static_cast<float>(dfNoDataValue);
4067
0
        bGotFloatNoDataValue = true;
4068
0
    }
4069
0
    else if (eDataType == GDT_Float16 && bGotNoDataValue &&
4070
0
             GDALIsValueExactAs<GFloat16>(dfNoDataValue))
4071
0
    {
4072
0
        fNoDataValue = static_cast<float>(dfNoDataValue);
4073
0
        bGotFloatNoDataValue = true;
4074
0
    }
4075
0
}
4076
4077
/************************************************************************/
4078
/*                       struct GDALNoDataValues                        */
4079
/************************************************************************/
4080
4081
/**
4082
 * \brief No-data-values for all types
4083
 *
4084
 * The functions below pass various no-data-values around. To avoid
4085
 * long argument lists, this struct collects the no-data-values for
4086
 * all types into a single, convenient place.
4087
 **/
4088
4089
struct GDALNoDataValues
4090
{
4091
    int bGotNoDataValue;
4092
    double dfNoDataValue;
4093
4094
    bool bGotInt64NoDataValue;
4095
    int64_t nInt64NoDataValue;
4096
4097
    bool bGotUInt64NoDataValue;
4098
    uint64_t nUInt64NoDataValue;
4099
4100
    bool bGotFloatNoDataValue;
4101
    float fNoDataValue;
4102
4103
    bool bGotFloat16NoDataValue;
4104
    GFloat16 hfNoDataValue;
4105
4106
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4107
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4108
0
          bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4109
0
          bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4110
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4111
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4112
0
    {
4113
0
        if (eDataType == GDT_Int64)
4114
0
        {
4115
0
            int nGot = false;
4116
0
            nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4117
0
            bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4118
0
            if (bGotInt64NoDataValue)
4119
0
            {
4120
0
                dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4121
0
                bGotNoDataValue =
4122
0
                    nInt64NoDataValue <=
4123
0
                        std::numeric_limits<int64_t>::max() - 1024 &&
4124
0
                    static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4125
0
            }
4126
0
            else
4127
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4128
0
        }
4129
0
        else if (eDataType == GDT_UInt64)
4130
0
        {
4131
0
            int nGot = false;
4132
0
            nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4133
0
            bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4134
0
            if (bGotUInt64NoDataValue)
4135
0
            {
4136
0
                dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4137
0
                bGotNoDataValue =
4138
0
                    nUInt64NoDataValue <=
4139
0
                        std::numeric_limits<uint64_t>::max() - 2048 &&
4140
0
                    static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4141
0
            }
4142
0
            else
4143
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4144
0
        }
4145
0
        else
4146
0
        {
4147
0
            dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4148
0
            bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4149
4150
0
            ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4151
0
                                    fNoDataValue, bGotFloatNoDataValue);
4152
4153
0
            ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4154
0
                                      hfNoDataValue, bGotFloat16NoDataValue);
4155
0
        }
4156
0
    }
4157
};
4158
4159
/************************************************************************/
4160
/*                           ARE_REAL_EQUAL()                           */
4161
/************************************************************************/
4162
4163
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4164
0
{
4165
0
    using std::abs;
4166
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4167
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4168
0
                                      abs(dfVal1 + dfVal2) * ulp;
4169
0
}
4170
4171
/************************************************************************/
4172
/*                            GetHistogram()                            */
4173
/************************************************************************/
4174
4175
/**
4176
 * \brief Compute raster histogram.
4177
 *
4178
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4179
 *
4180
 * For example to compute a simple 256 entry histogram of eight bit data,
4181
 * the following would be suitable.  The unusual bounds are to ensure that
4182
 * bucket boundaries don't fall right on integer values causing possible errors
4183
 * due to rounding after scaling.
4184
\code{.cpp}
4185
    GUIntBig anHistogram[256];
4186
4187
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4188
                          GDALDummyProgress, nullptr );
4189
\endcode
4190
 *
4191
 * Note that setting bApproxOK will generally result in a subsampling of the
4192
 * file, and will utilize overviews if available.  It should generally
4193
 * produce a representative histogram for the data that is suitable for use
4194
 * in generating histogram based luts for instance.  Generally bApproxOK is
4195
 * much faster than an exactly computed histogram.
4196
 *
4197
 * This method is the same as the C functions GDALGetRasterHistogram() and
4198
 * GDALGetRasterHistogramEx().
4199
 *
4200
 * @param dfMin the lower bound of the histogram.
4201
 * @param dfMax the upper bound of the histogram.
4202
 * @param nBuckets the number of buckets in panHistogram.
4203
 * @param panHistogram array into which the histogram totals are placed.
4204
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4205
 * mapped into panHistogram[0], and values above will be mapped into
4206
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4207
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4208
 * @param pfnProgress function to report progress to completion.
4209
 * @param pProgressData application data to pass to pfnProgress.
4210
 *
4211
 * @return CE_None on success, or CE_Failure if something goes wrong.
4212
 */
4213
4214
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4215
                                    GUIntBig *panHistogram,
4216
                                    int bIncludeOutOfRange, int bApproxOK,
4217
                                    GDALProgressFunc pfnProgress,
4218
                                    void *pProgressData)
4219
4220
0
{
4221
0
    CPLAssert(nullptr != panHistogram);
4222
4223
0
    if (pfnProgress == nullptr)
4224
0
        pfnProgress = GDALDummyProgress;
4225
4226
    /* -------------------------------------------------------------------- */
4227
    /*      If we have overviews, use them for the histogram.               */
4228
    /* -------------------------------------------------------------------- */
4229
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4230
0
    {
4231
        // FIXME: should we use the most reduced overview here or use some
4232
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4233
        // does?
4234
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4235
4236
0
        if (poBestOverview != this)
4237
0
        {
4238
0
            return poBestOverview->GetHistogram(
4239
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4240
0
                bApproxOK, pfnProgress, pProgressData);
4241
0
        }
4242
0
    }
4243
4244
    /* -------------------------------------------------------------------- */
4245
    /*      Read actual data and build histogram.                           */
4246
    /* -------------------------------------------------------------------- */
4247
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4248
0
    {
4249
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4250
0
        return CE_Failure;
4251
0
    }
4252
4253
    // Written this way to deal with NaN
4254
0
    if (!(dfMax > dfMin))
4255
0
    {
4256
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4257
0
                    "dfMax should be strictly greater than dfMin");
4258
0
        return CE_Failure;
4259
0
    }
4260
4261
0
    GDALRasterIOExtraArg sExtraArg;
4262
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4263
4264
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4265
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4266
0
    {
4267
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4268
0
                    "dfMin and dfMax should be finite values such that "
4269
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4270
0
        return CE_Failure;
4271
0
    }
4272
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4273
4274
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4275
0
    GDALRasterBand *poMaskBand = nullptr;
4276
0
    if (!sNoDataValues.bGotNoDataValue)
4277
0
    {
4278
0
        const int l_nMaskFlags = GetMaskFlags();
4279
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
4280
0
            GetColorInterpretation() != GCI_AlphaBand)
4281
0
        {
4282
0
            poMaskBand = GetMaskBand();
4283
0
        }
4284
0
    }
4285
4286
0
    bool bSignedByte = false;
4287
0
    if (eDataType == GDT_UInt8)
4288
0
    {
4289
0
        EnablePixelTypeSignedByteWarning(false);
4290
0
        const char *pszPixelType =
4291
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4292
0
        EnablePixelTypeSignedByteWarning(true);
4293
0
        bSignedByte =
4294
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4295
0
    }
4296
4297
0
    if (bApproxOK && HasArbitraryOverviews())
4298
0
    {
4299
        /* --------------------------------------------------------------------
4300
         */
4301
        /*      Figure out how much the image should be reduced to get an */
4302
        /*      approximate value. */
4303
        /* --------------------------------------------------------------------
4304
         */
4305
0
        const double dfReduction =
4306
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4307
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4308
4309
0
        int nXReduced = nRasterXSize;
4310
0
        int nYReduced = nRasterYSize;
4311
0
        if (dfReduction > 1.0)
4312
0
        {
4313
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4314
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4315
4316
            // Catch the case of huge resizing ratios here
4317
0
            if (nXReduced == 0)
4318
0
                nXReduced = 1;
4319
0
            if (nYReduced == 0)
4320
0
                nYReduced = 1;
4321
0
        }
4322
4323
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4324
0
                                          nXReduced, nYReduced);
4325
0
        if (!pData)
4326
0
            return CE_Failure;
4327
4328
0
        const CPLErr eErr =
4329
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4330
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4331
0
        if (eErr != CE_None)
4332
0
        {
4333
0
            CPLFree(pData);
4334
0
            return eErr;
4335
0
        }
4336
4337
0
        GByte *pabyMaskData = nullptr;
4338
0
        if (poMaskBand)
4339
0
        {
4340
0
            pabyMaskData =
4341
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4342
0
            if (!pabyMaskData)
4343
0
            {
4344
0
                CPLFree(pData);
4345
0
                return CE_Failure;
4346
0
            }
4347
4348
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4349
0
                                     pabyMaskData, nXReduced, nYReduced,
4350
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
4351
0
            {
4352
0
                CPLFree(pData);
4353
0
                CPLFree(pabyMaskData);
4354
0
                return CE_Failure;
4355
0
            }
4356
0
        }
4357
4358
        // This isn't the fastest way to do this, but is easier for now.
4359
0
        for (int iY = 0; iY < nYReduced; iY++)
4360
0
        {
4361
0
            for (int iX = 0; iX < nXReduced; iX++)
4362
0
            {
4363
0
                const int iOffset = iX + iY * nXReduced;
4364
0
                double dfValue = 0.0;
4365
4366
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4367
0
                    continue;
4368
4369
0
                switch (eDataType)
4370
0
                {
4371
0
                    case GDT_UInt8:
4372
0
                    {
4373
0
                        if (bSignedByte)
4374
0
                            dfValue =
4375
0
                                static_cast<signed char *>(pData)[iOffset];
4376
0
                        else
4377
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4378
0
                        break;
4379
0
                    }
4380
0
                    case GDT_Int8:
4381
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4382
0
                        break;
4383
0
                    case GDT_UInt16:
4384
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4385
0
                        break;
4386
0
                    case GDT_Int16:
4387
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4388
0
                        break;
4389
0
                    case GDT_UInt32:
4390
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4391
0
                        break;
4392
0
                    case GDT_Int32:
4393
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4394
0
                        break;
4395
0
                    case GDT_UInt64:
4396
0
                        dfValue = static_cast<double>(
4397
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4398
0
                        break;
4399
0
                    case GDT_Int64:
4400
0
                        dfValue = static_cast<double>(
4401
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4402
0
                        break;
4403
0
                    case GDT_Float16:
4404
0
                    {
4405
0
                        using namespace std;
4406
0
                        const GFloat16 hfValue =
4407
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4408
0
                        if (isnan(hfValue) ||
4409
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4410
0
                             ARE_REAL_EQUAL(hfValue,
4411
0
                                            sNoDataValues.hfNoDataValue)))
4412
0
                            continue;
4413
0
                        dfValue = hfValue;
4414
0
                        break;
4415
0
                    }
4416
0
                    case GDT_Float32:
4417
0
                    {
4418
0
                        const float fValue =
4419
0
                            static_cast<float *>(pData)[iOffset];
4420
0
                        if (std::isnan(fValue) ||
4421
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4422
0
                             ARE_REAL_EQUAL(fValue,
4423
0
                                            sNoDataValues.fNoDataValue)))
4424
0
                            continue;
4425
0
                        dfValue = double(fValue);
4426
0
                        break;
4427
0
                    }
4428
0
                    case GDT_Float64:
4429
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4430
0
                        if (std::isnan(dfValue))
4431
0
                            continue;
4432
0
                        break;
4433
0
                    case GDT_CInt16:
4434
0
                    {
4435
0
                        const double dfReal =
4436
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4437
0
                        const double dfImag =
4438
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4439
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4440
0
                            continue;
4441
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4442
0
                    }
4443
0
                    break;
4444
0
                    case GDT_CInt32:
4445
0
                    {
4446
0
                        const double dfReal =
4447
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4448
0
                        const double dfImag =
4449
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4450
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4451
0
                            continue;
4452
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4453
0
                    }
4454
0
                    break;
4455
0
                    case GDT_CFloat16:
4456
0
                    {
4457
0
                        const double dfReal =
4458
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4459
0
                        const double dfImag =
4460
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4461
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4462
0
                            continue;
4463
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4464
0
                        break;
4465
0
                    }
4466
0
                    case GDT_CFloat32:
4467
0
                    {
4468
0
                        const double dfReal =
4469
0
                            double(static_cast<float *>(pData)[iOffset * 2]);
4470
0
                        const double dfImag = double(
4471
0
                            static_cast<float *>(pData)[iOffset * 2 + 1]);
4472
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4473
0
                            continue;
4474
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4475
0
                        break;
4476
0
                    }
4477
0
                    case GDT_CFloat64:
4478
0
                    {
4479
0
                        const double dfReal =
4480
0
                            static_cast<double *>(pData)[iOffset * 2];
4481
0
                        const double dfImag =
4482
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4483
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4484
0
                            continue;
4485
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4486
0
                        break;
4487
0
                    }
4488
0
                    case GDT_Unknown:
4489
0
                    case GDT_TypeCount:
4490
0
                        CPLAssert(false);
4491
0
                }
4492
4493
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4494
0
                    sNoDataValues.bGotNoDataValue &&
4495
0
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4496
0
                    continue;
4497
4498
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4499
                // finite, the result of the multiplication cannot be NaN
4500
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4501
4502
0
                if (dfIndex < 0)
4503
0
                {
4504
0
                    if (bIncludeOutOfRange)
4505
0
                        panHistogram[0]++;
4506
0
                }
4507
0
                else if (dfIndex >= nBuckets)
4508
0
                {
4509
0
                    if (bIncludeOutOfRange)
4510
0
                        ++panHistogram[nBuckets - 1];
4511
0
                }
4512
0
                else
4513
0
                {
4514
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4515
0
                }
4516
0
            }
4517
0
        }
4518
4519
0
        CPLFree(pData);
4520
0
        CPLFree(pabyMaskData);
4521
0
    }
4522
0
    else  // No arbitrary overviews.
4523
0
    {
4524
0
        if (!InitBlockInfo())
4525
0
            return CE_Failure;
4526
4527
        /* --------------------------------------------------------------------
4528
         */
4529
        /*      Figure out the ratio of blocks we will read to get an */
4530
        /*      approximate value. */
4531
        /* --------------------------------------------------------------------
4532
         */
4533
4534
0
        int nSampleRate = 1;
4535
0
        if (bApproxOK)
4536
0
        {
4537
0
            nSampleRate = static_cast<int>(std::max(
4538
0
                1.0,
4539
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4540
            // We want to avoid probing only the first column of blocks for
4541
            // a square shaped raster, because it is not unlikely that it may
4542
            // be padding only (#6378).
4543
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4544
0
                nSampleRate += 1;
4545
0
        }
4546
4547
0
        GByte *pabyMaskData = nullptr;
4548
0
        if (poMaskBand)
4549
0
        {
4550
0
            pabyMaskData = static_cast<GByte *>(
4551
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4552
0
            if (!pabyMaskData)
4553
0
            {
4554
0
                return CE_Failure;
4555
0
            }
4556
0
        }
4557
4558
        /* --------------------------------------------------------------------
4559
         */
4560
        /*      Read the blocks, and add to histogram. */
4561
        /* --------------------------------------------------------------------
4562
         */
4563
0
        for (GIntBig iSampleBlock = 0;
4564
0
             iSampleBlock <
4565
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4566
0
             iSampleBlock += nSampleRate)
4567
0
        {
4568
0
            if (!pfnProgress(
4569
0
                    static_cast<double>(iSampleBlock) /
4570
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4571
0
                    "Compute Histogram", pProgressData))
4572
0
            {
4573
0
                CPLFree(pabyMaskData);
4574
0
                return CE_Failure;
4575
0
            }
4576
4577
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4578
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4579
4580
0
            int nXCheck = 0, nYCheck = 0;
4581
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4582
4583
0
            if (poMaskBand &&
4584
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4585
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4586
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4587
0
                                     0, nBlockXSize, nullptr) != CE_None)
4588
0
            {
4589
0
                CPLFree(pabyMaskData);
4590
0
                return CE_Failure;
4591
0
            }
4592
4593
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4594
0
            if (poBlock == nullptr)
4595
0
            {
4596
0
                CPLFree(pabyMaskData);
4597
0
                return CE_Failure;
4598
0
            }
4599
4600
0
            void *pData = poBlock->GetDataRef();
4601
4602
            // this is a special case for a common situation.
4603
0
            if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4604
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4605
0
                nXCheck == nBlockXSize && nBuckets == 256)
4606
0
            {
4607
0
                const GPtrDiff_t nPixels =
4608
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4609
0
                GByte *pabyData = static_cast<GByte *>(pData);
4610
4611
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4612
0
                {
4613
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4614
0
                        continue;
4615
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4616
0
                          (pabyData[i] ==
4617
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4618
0
                    {
4619
0
                        panHistogram[pabyData[i]]++;
4620
0
                    }
4621
0
                }
4622
4623
0
                poBlock->DropLock();
4624
0
                continue;  // To next sample block.
4625
0
            }
4626
4627
            // This isn't the fastest way to do this, but is easier for now.
4628
0
            for (int iY = 0; iY < nYCheck; iY++)
4629
0
            {
4630
0
                for (int iX = 0; iX < nXCheck; iX++)
4631
0
                {
4632
0
                    const GPtrDiff_t iOffset =
4633
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4634
4635
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4636
0
                        continue;
4637
4638
0
                    double dfValue = 0.0;
4639
4640
0
                    switch (eDataType)
4641
0
                    {
4642
0
                        case GDT_UInt8:
4643
0
                        {
4644
0
                            if (bSignedByte)
4645
0
                                dfValue =
4646
0
                                    static_cast<signed char *>(pData)[iOffset];
4647
0
                            else
4648
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4649
0
                            break;
4650
0
                        }
4651
0
                        case GDT_Int8:
4652
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4653
0
                            break;
4654
0
                        case GDT_UInt16:
4655
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4656
0
                            break;
4657
0
                        case GDT_Int16:
4658
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4659
0
                            break;
4660
0
                        case GDT_UInt32:
4661
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4662
0
                            break;
4663
0
                        case GDT_Int32:
4664
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4665
0
                            break;
4666
0
                        case GDT_UInt64:
4667
0
                            dfValue = static_cast<double>(
4668
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4669
0
                            break;
4670
0
                        case GDT_Int64:
4671
0
                            dfValue = static_cast<double>(
4672
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4673
0
                            break;
4674
0
                        case GDT_Float16:
4675
0
                        {
4676
0
                            using namespace std;
4677
0
                            const GFloat16 hfValue =
4678
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4679
0
                            if (isnan(hfValue) ||
4680
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4681
0
                                 ARE_REAL_EQUAL(hfValue,
4682
0
                                                sNoDataValues.hfNoDataValue)))
4683
0
                                continue;
4684
0
                            dfValue = hfValue;
4685
0
                            break;
4686
0
                        }
4687
0
                        case GDT_Float32:
4688
0
                        {
4689
0
                            const float fValue =
4690
0
                                static_cast<float *>(pData)[iOffset];
4691
0
                            if (std::isnan(fValue) ||
4692
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4693
0
                                 ARE_REAL_EQUAL(fValue,
4694
0
                                                sNoDataValues.fNoDataValue)))
4695
0
                                continue;
4696
0
                            dfValue = double(fValue);
4697
0
                            break;
4698
0
                        }
4699
0
                        case GDT_Float64:
4700
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4701
0
                            if (std::isnan(dfValue))
4702
0
                                continue;
4703
0
                            break;
4704
0
                        case GDT_CInt16:
4705
0
                        {
4706
0
                            double dfReal =
4707
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4708
0
                            double dfImag =
4709
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4710
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4711
0
                            break;
4712
0
                        }
4713
0
                        case GDT_CInt32:
4714
0
                        {
4715
0
                            double dfReal =
4716
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4717
0
                            double dfImag =
4718
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4719
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4720
0
                            break;
4721
0
                        }
4722
0
                        case GDT_CFloat16:
4723
0
                        {
4724
0
                            double dfReal =
4725
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4726
0
                            double dfImag =
4727
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4728
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4729
0
                                continue;
4730
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4731
0
                            break;
4732
0
                        }
4733
0
                        case GDT_CFloat32:
4734
0
                        {
4735
0
                            double dfReal = double(
4736
0
                                static_cast<float *>(pData)[iOffset * 2]);
4737
0
                            double dfImag = double(
4738
0
                                static_cast<float *>(pData)[iOffset * 2 + 1]);
4739
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4740
0
                                continue;
4741
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4742
0
                            break;
4743
0
                        }
4744
0
                        case GDT_CFloat64:
4745
0
                        {
4746
0
                            double dfReal =
4747
0
                                static_cast<double *>(pData)[iOffset * 2];
4748
0
                            double dfImag =
4749
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4750
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4751
0
                                continue;
4752
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4753
0
                            break;
4754
0
                        }
4755
0
                        case GDT_Unknown:
4756
0
                        case GDT_TypeCount:
4757
0
                            CPLAssert(false);
4758
0
                            CPLFree(pabyMaskData);
4759
0
                            return CE_Failure;
4760
0
                    }
4761
4762
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4763
0
                        sNoDataValues.bGotNoDataValue &&
4764
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4765
0
                        continue;
4766
4767
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4768
                    // and finite, the result of the multiplication cannot be
4769
                    // NaN
4770
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4771
4772
0
                    if (dfIndex < 0)
4773
0
                    {
4774
0
                        if (bIncludeOutOfRange)
4775
0
                            panHistogram[0]++;
4776
0
                    }
4777
0
                    else if (dfIndex >= nBuckets)
4778
0
                    {
4779
0
                        if (bIncludeOutOfRange)
4780
0
                            ++panHistogram[nBuckets - 1];
4781
0
                    }
4782
0
                    else
4783
0
                    {
4784
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4785
0
                    }
4786
0
                }
4787
0
            }
4788
4789
0
            poBlock->DropLock();
4790
0
        }
4791
4792
0
        CPLFree(pabyMaskData);
4793
0
    }
4794
4795
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4796
4797
0
    return CE_None;
4798
0
}
4799
4800
/************************************************************************/
4801
/*                       GDALGetRasterHistogram()                       */
4802
/************************************************************************/
4803
4804
/**
4805
 * \brief Compute raster histogram.
4806
 *
4807
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4808
 * exceeding 2 billion.
4809
 *
4810
 * @see GDALRasterBand::GetHistogram()
4811
 * @see GDALGetRasterHistogramEx()
4812
 */
4813
4814
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4815
                                          double dfMax, int nBuckets,
4816
                                          int *panHistogram,
4817
                                          int bIncludeOutOfRange, int bApproxOK,
4818
                                          GDALProgressFunc pfnProgress,
4819
                                          void *pProgressData)
4820
4821
0
{
4822
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4823
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4824
4825
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4826
4827
0
    GUIntBig *panHistogramTemp =
4828
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4829
0
    if (panHistogramTemp == nullptr)
4830
0
    {
4831
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4832
0
                            "Out of memory in GDALGetRasterHistogram().");
4833
0
        return CE_Failure;
4834
0
    }
4835
4836
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4837
0
                                       bIncludeOutOfRange, bApproxOK,
4838
0
                                       pfnProgress, pProgressData);
4839
4840
0
    if (eErr == CE_None)
4841
0
    {
4842
0
        for (int i = 0; i < nBuckets; i++)
4843
0
        {
4844
0
            if (panHistogramTemp[i] > INT_MAX)
4845
0
            {
4846
0
                CPLError(CE_Warning, CPLE_AppDefined,
4847
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4848
0
                         " exceeds maximum 32 bit value",
4849
0
                         i, panHistogramTemp[i]);
4850
0
                panHistogram[i] = INT_MAX;
4851
0
            }
4852
0
            else
4853
0
            {
4854
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4855
0
            }
4856
0
        }
4857
0
    }
4858
4859
0
    CPLFree(panHistogramTemp);
4860
4861
0
    return eErr;
4862
0
}
4863
4864
/************************************************************************/
4865
/*                      GDALGetRasterHistogramEx()                      */
4866
/************************************************************************/
4867
4868
/**
4869
 * \brief Compute raster histogram.
4870
 *
4871
 * @see GDALRasterBand::GetHistogram()
4872
 *
4873
 */
4874
4875
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4876
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4877
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4878
    GDALProgressFunc pfnProgress, void *pProgressData)
4879
4880
0
{
4881
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4882
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4883
4884
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4885
4886
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4887
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4888
0
                                pProgressData);
4889
0
}
4890
4891
/************************************************************************/
4892
/*                        GetDefaultHistogram()                         */
4893
/************************************************************************/
4894
4895
/**
4896
 * \brief Fetch default raster histogram.
4897
 *
4898
 * The default method in GDALRasterBand will compute a default histogram. This
4899
 * method is overridden by derived classes (such as GDALPamRasterBand,
4900
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4901
 * stored histogram.
4902
 *
4903
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4904
 * GDALGetDefaultHistogramEx().
4905
 *
4906
 * @param pdfMin pointer to double value that will contain the lower bound of
4907
 * the histogram.
4908
 * @param pdfMax pointer to double value that will contain the upper bound of
4909
 * the histogram.
4910
 * @param pnBuckets pointer to int value that will contain the number of buckets
4911
 * in *ppanHistogram.
4912
 * @param ppanHistogram pointer to array into which the histogram totals are
4913
 * placed. To be freed with VSIFree
4914
 * @param bForce TRUE to force the computation. If FALSE and no default
4915
 * histogram is available, the method will return CE_Warning
4916
 * @param pfnProgress function to report progress to completion.
4917
 * @param pProgressData application data to pass to pfnProgress.
4918
 *
4919
 * @return CE_None on success, CE_Failure if something goes wrong, or
4920
 * CE_Warning if no default histogram is available.
4921
 */
4922
4923
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4924
                                           int *pnBuckets,
4925
                                           GUIntBig **ppanHistogram, int bForce,
4926
                                           GDALProgressFunc pfnProgress,
4927
                                           void *pProgressData)
4928
4929
0
{
4930
0
    CPLAssert(nullptr != pnBuckets);
4931
0
    CPLAssert(nullptr != ppanHistogram);
4932
0
    CPLAssert(nullptr != pdfMin);
4933
0
    CPLAssert(nullptr != pdfMax);
4934
4935
0
    *pnBuckets = 0;
4936
0
    *ppanHistogram = nullptr;
4937
4938
0
    if (!bForce)
4939
0
        return CE_Warning;
4940
4941
0
    int nBuckets = 256;
4942
4943
0
    bool bSignedByte = false;
4944
0
    if (eDataType == GDT_UInt8)
4945
0
    {
4946
0
        EnablePixelTypeSignedByteWarning(false);
4947
0
        const char *pszPixelType =
4948
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4949
0
        EnablePixelTypeSignedByteWarning(true);
4950
0
        bSignedByte =
4951
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4952
0
    }
4953
4954
0
    if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4955
0
    {
4956
0
        *pdfMin = -0.5;
4957
0
        *pdfMax = 255.5;
4958
0
    }
4959
0
    else if (GetRasterDataType() == GDT_Int8)
4960
0
    {
4961
0
        *pdfMin = -128 - 0.5;
4962
0
        *pdfMax = 127 + 0.5;
4963
0
    }
4964
0
    else
4965
0
    {
4966
4967
0
        const CPLErr eErr =
4968
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4969
0
        if (eErr != CE_None)
4970
0
            return eErr;
4971
0
        if (*pdfMin == *pdfMax)
4972
0
        {
4973
0
            nBuckets = 1;
4974
0
            *pdfMin -= 0.5;
4975
0
            *pdfMax += 0.5;
4976
0
        }
4977
0
        else
4978
0
        {
4979
0
            const double dfHalfBucket =
4980
0
                (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4981
0
            *pdfMin -= dfHalfBucket;
4982
0
            *pdfMax += dfHalfBucket;
4983
0
        }
4984
0
    }
4985
4986
0
    *ppanHistogram =
4987
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4988
0
    if (*ppanHistogram == nullptr)
4989
0
    {
4990
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
4991
0
                    "Out of memory in GetDefaultHistogram().");
4992
0
        return CE_Failure;
4993
0
    }
4994
4995
0
    *pnBuckets = nBuckets;
4996
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4997
0
                               TRUE, FALSE, pfnProgress, pProgressData);
4998
0
    if (eErr != CE_None)
4999
0
    {
5000
0
        *pnBuckets = 0;
5001
0
    }
5002
0
    return eErr;
5003
0
}
5004
5005
/************************************************************************/
5006
/*                      GDALGetDefaultHistogram()                       */
5007
/************************************************************************/
5008
5009
/**
5010
 * \brief Fetch default raster histogram.
5011
 *
5012
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5013
 * exceeding 2 billion.
5014
 *
5015
 * @see GDALRasterBand::GDALGetDefaultHistogram()
5016
 * @see GDALGetRasterHistogramEx()
5017
 */
5018
5019
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5020
                                           double *pdfMin, double *pdfMax,
5021
                                           int *pnBuckets, int **ppanHistogram,
5022
                                           int bForce,
5023
                                           GDALProgressFunc pfnProgress,
5024
                                           void *pProgressData)
5025
5026
0
{
5027
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5028
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5029
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5030
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5031
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5032
5033
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5034
0
    GUIntBig *panHistogramTemp = nullptr;
5035
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5036
0
                                              &panHistogramTemp, bForce,
5037
0
                                              pfnProgress, pProgressData);
5038
0
    if (eErr == CE_None)
5039
0
    {
5040
0
        const int nBuckets = *pnBuckets;
5041
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5042
0
        if (*ppanHistogram == nullptr)
5043
0
        {
5044
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5045
0
                                "Out of memory in GDALGetDefaultHistogram().");
5046
0
            VSIFree(panHistogramTemp);
5047
0
            return CE_Failure;
5048
0
        }
5049
5050
0
        for (int i = 0; i < nBuckets; ++i)
5051
0
        {
5052
0
            if (panHistogramTemp[i] > INT_MAX)
5053
0
            {
5054
0
                CPLError(CE_Warning, CPLE_AppDefined,
5055
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
5056
0
                         " exceeds maximum 32 bit value",
5057
0
                         i, panHistogramTemp[i]);
5058
0
                (*ppanHistogram)[i] = INT_MAX;
5059
0
            }
5060
0
            else
5061
0
            {
5062
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5063
0
            }
5064
0
        }
5065
5066
0
        CPLFree(panHistogramTemp);
5067
0
    }
5068
0
    else
5069
0
    {
5070
0
        *ppanHistogram = nullptr;
5071
0
    }
5072
5073
0
    return eErr;
5074
0
}
5075
5076
/************************************************************************/
5077
/*                     GDALGetDefaultHistogramEx()                      */
5078
/************************************************************************/
5079
5080
/**
5081
 * \brief Fetch default raster histogram.
5082
 *
5083
 * @see GDALRasterBand::GetDefaultHistogram()
5084
 *
5085
 */
5086
5087
CPLErr CPL_STDCALL
5088
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5089
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5090
                          GDALProgressFunc pfnProgress, void *pProgressData)
5091
5092
0
{
5093
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5094
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5095
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5096
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5097
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5098
5099
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5100
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5101
0
                                       bForce, pfnProgress, pProgressData);
5102
0
}
5103
5104
/************************************************************************/
5105
/*                             AdviseRead()                             */
5106
/************************************************************************/
5107
5108
/**
5109
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5110
 * \brief Advise driver of upcoming read requests.
5111
 *
5112
 * Some GDAL drivers operate more efficiently if they know in advance what
5113
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5114
 * an application to notify the driver of the region of interest,
5115
 * and at what resolution the region will be read.
5116
 *
5117
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5118
 * accelerate access via some drivers.
5119
 *
5120
 * Depending on call paths, drivers might receive several calls to
5121
 * AdviseRead() with the same parameters.
5122
 *
5123
 * @param nXOff The pixel offset to the top left corner of the region
5124
 * of the band to be accessed.  This would be zero to start from the left side.
5125
 *
5126
 * @param nYOff The line offset to the top left corner of the region
5127
 * of the band to be accessed.  This would be zero to start from the top.
5128
 *
5129
 * @param nXSize The width of the region of the band to be accessed in pixels.
5130
 *
5131
 * @param nYSize The height of the region of the band to be accessed in lines.
5132
 *
5133
 * @param nBufXSize the width of the buffer image into which the desired region
5134
 * is to be read, or from which it is to be written.
5135
 *
5136
 * @param nBufYSize the height of the buffer image into which the desired
5137
 * region is to be read, or from which it is to be written.
5138
 *
5139
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5140
 * pixel values will automatically be translated to/from the GDALRasterBand
5141
 * data type as needed.
5142
 *
5143
 * @param papszOptions a list of name=value strings with special control
5144
 * options.  Normally this is NULL.
5145
 *
5146
 * @return CE_Failure if the request is invalid and CE_None if it works or
5147
 * is ignored.
5148
 */
5149
5150
/**/
5151
/**/
5152
5153
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5154
                                  int /*nYSize*/, int /*nBufXSize*/,
5155
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5156
                                  CSLConstList /*papszOptions*/)
5157
0
{
5158
0
    return CE_None;
5159
0
}
5160
5161
/************************************************************************/
5162
/*                        GDALRasterAdviseRead()                        */
5163
/************************************************************************/
5164
5165
/**
5166
 * \brief Advise driver of upcoming read requests.
5167
 *
5168
 * @see GDALRasterBand::AdviseRead()
5169
 */
5170
5171
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5172
                                        int nYOff, int nXSize, int nYSize,
5173
                                        int nBufXSize, int nBufYSize,
5174
                                        GDALDataType eDT,
5175
                                        CSLConstList papszOptions)
5176
5177
0
{
5178
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5179
5180
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5181
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5182
0
                              nBufYSize, eDT,
5183
0
                              const_cast<char **>(papszOptions));
5184
0
}
5185
5186
/************************************************************************/
5187
/*                           GetStatistics()                            */
5188
/************************************************************************/
5189
5190
/**
5191
 * \brief Fetch image statistics.
5192
 *
5193
 * Returns the minimum, maximum, mean and standard deviation of all
5194
 * pixel values in this band.  If approximate statistics are sufficient,
5195
 * the bApproxOK flag can be set to true in which case overviews, or a
5196
 * subset of image tiles may be used in computing the statistics.
5197
 *
5198
 * If bForce is FALSE results will only be returned if it can be done
5199
 * quickly (i.e. without scanning the image, typically by using pre-existing
5200
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5201
 * returned efficiently, the method will return CE_Warning but no warning will
5202
 * be issued. This is a non-standard use of the CE_Warning return value
5203
 * to indicate "nothing done".
5204
 *
5205
 * If bForce is TRUE, and results are quickly available without scanning the
5206
 * image, they will be used. If bForce is TRUE and results are not quickly
5207
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5208
 * which will scan the image.
5209
 *
5210
 * To always force recomputation of statistics, use ComputeStatistics() instead
5211
 * of this method.
5212
 *
5213
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5214
 * will generally cache statistics in the .pam file allowing fast fetch
5215
 * after the first request.
5216
 *
5217
 * This method is the same as the C function GDALGetRasterStatistics().
5218
 *
5219
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5220
 * or a subset of all tiles.
5221
 *
5222
 * @param bForce If FALSE statistics will only be returned if it can
5223
 * be done without rescanning the image. If TRUE, statistics computation will
5224
 * be forced if pre-existing values are not quickly available.
5225
 *
5226
 * @param pdfMin Location into which to load image minimum (may be NULL).
5227
 *
5228
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5229
 *
5230
 * @param pdfMean Location into which to load image mean (may be NULL).
5231
 *
5232
 * @param pdfStdDev Location into which to load image standard deviation
5233
 * (may be NULL).
5234
 *
5235
 * @return CE_None on success, CE_Warning if no values returned,
5236
 * CE_Failure if an error occurs.
5237
 */
5238
5239
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5240
                                     double *pdfMax, double *pdfMean,
5241
                                     double *pdfStdDev)
5242
5243
0
{
5244
    /* -------------------------------------------------------------------- */
5245
    /*      Do we already have metadata items for the requested values?     */
5246
    /* -------------------------------------------------------------------- */
5247
0
    if ((pdfMin == nullptr ||
5248
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5249
0
        (pdfMax == nullptr ||
5250
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5251
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5252
0
        (pdfStdDev == nullptr ||
5253
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5254
0
    {
5255
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5256
0
        {
5257
0
            if (pdfMin != nullptr)
5258
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5259
0
            if (pdfMax != nullptr)
5260
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5261
0
            if (pdfMean != nullptr)
5262
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5263
0
            if (pdfStdDev != nullptr)
5264
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5265
5266
0
            return CE_None;
5267
0
        }
5268
0
    }
5269
5270
    /* -------------------------------------------------------------------- */
5271
    /*      Does the driver already know the min/max?                       */
5272
    /* -------------------------------------------------------------------- */
5273
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5274
0
    {
5275
0
        int bSuccessMin = FALSE;
5276
0
        int bSuccessMax = FALSE;
5277
5278
0
        const double dfMin = GetMinimum(&bSuccessMin);
5279
0
        const double dfMax = GetMaximum(&bSuccessMax);
5280
5281
0
        if (bSuccessMin && bSuccessMax)
5282
0
        {
5283
0
            if (pdfMin != nullptr)
5284
0
                *pdfMin = dfMin;
5285
0
            if (pdfMax != nullptr)
5286
0
                *pdfMax = dfMax;
5287
0
            return CE_None;
5288
0
        }
5289
0
    }
5290
5291
    /* -------------------------------------------------------------------- */
5292
    /*      Either return without results, or force computation.            */
5293
    /* -------------------------------------------------------------------- */
5294
0
    if (!bForce)
5295
0
        return CE_Warning;
5296
0
    else
5297
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5298
0
                                 GDALDummyProgress, nullptr);
5299
0
}
5300
5301
/************************************************************************/
5302
/*                      GDALGetRasterStatistics()                       */
5303
/************************************************************************/
5304
5305
/**
5306
 * \brief Fetch image statistics.
5307
 *
5308
 * @see GDALRasterBand::GetStatistics()
5309
 */
5310
5311
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5312
                                           int bForce, double *pdfMin,
5313
                                           double *pdfMax, double *pdfMean,
5314
                                           double *pdfStdDev)
5315
5316
0
{
5317
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5318
5319
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5320
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5321
0
                                 pdfStdDev);
5322
0
}
5323
5324
/************************************************************************/
5325
/*                             GDALUInt128                              */
5326
/************************************************************************/
5327
5328
#ifdef HAVE_UINT128_T
5329
class GDALUInt128
5330
{
5331
    __uint128_t val;
5332
5333
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5334
0
    {
5335
0
    }
5336
5337
  public:
5338
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5339
0
    {
5340
        // Evaluates to just a single mul on x86_64
5341
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5342
0
    }
5343
5344
    GDALUInt128 operator-(const GDALUInt128 &other) const
5345
0
    {
5346
0
        return GDALUInt128(val - other.val);
5347
0
    }
5348
5349
    operator double() const
5350
0
    {
5351
0
        return static_cast<double>(val);
5352
0
    }
5353
};
5354
#else
5355
5356
#if defined(_MSC_VER) && defined(_M_X64)
5357
#include <intrin.h>
5358
#endif
5359
5360
class GDALUInt128
5361
{
5362
    GUIntBig low, high;
5363
5364
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5365
    {
5366
    }
5367
5368
  public:
5369
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5370
    {
5371
#if defined(_MSC_VER) && defined(_M_X64)
5372
        GUIntBig highRes;
5373
        GUIntBig lowRes = _umul128(first, second, &highRes);
5374
        return GDALUInt128(lowRes, highRes);
5375
#else
5376
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5377
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5378
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5379
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5380
        GUIntBig highRes = 0;
5381
        const GUIntBig firstLowSecondHigh =
5382
            static_cast<GUIntBig>(firstLow) * secondHigh;
5383
        const GUIntBig firstHighSecondLow =
5384
            static_cast<GUIntBig>(firstHigh) * secondLow;
5385
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5386
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5387
            highRes += static_cast<GUIntBig>(1) << 32;
5388
        const GUIntBig firstLowSecondLow =
5389
            static_cast<GUIntBig>(firstLow) * secondLow;
5390
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5391
        if (lowRes < firstLowSecondLow)  // check for overflow
5392
            highRes++;
5393
        highRes +=
5394
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5395
        return GDALUInt128(lowRes, highRes);
5396
#endif
5397
    }
5398
5399
    GDALUInt128 operator-(const GDALUInt128 &other) const
5400
    {
5401
        GUIntBig highRes = high - other.high;
5402
        GUIntBig lowRes = low - other.low;
5403
        if (lowRes > low)  // check for underflow
5404
            --highRes;
5405
        return GDALUInt128(lowRes, highRes);
5406
    }
5407
5408
    operator double() const
5409
    {
5410
        const double twoPow64 = 18446744073709551616.0;
5411
        return high * twoPow64 + low;
5412
    }
5413
};
5414
#endif
5415
5416
/************************************************************************/
5417
/*                     ComputeStatisticsInternal()                      */
5418
/************************************************************************/
5419
5420
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5421
// not needed.
5422
0
#define static_cast_for_coverity_scan static_cast
5423
5424
// The rationale for below optimizations is detailed in statistics.txt
5425
5426
// Use with T = GByte or GUInt16 only !
5427
template <class T, bool COMPUTE_OTHER_STATS>
5428
struct ComputeStatisticsInternalGeneric
5429
{
5430
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5431
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5432
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5433
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5434
0
    {
5435
0
        static_assert(std::is_same<T, GByte>::value ||
5436
0
                          std::is_same<T, GUInt16>::value,
5437
0
                      "bad type for T");
5438
0
        if (bHasNoData)
5439
0
        {
5440
            // General case
5441
0
            for (int iY = 0; iY < nYCheck; iY++)
5442
0
            {
5443
0
                for (int iX = 0; iX < nXCheck; iX++)
5444
0
                {
5445
0
                    const GPtrDiff_t iOffset =
5446
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5447
0
                    const GUInt32 nValue = pData[iOffset];
5448
0
                    if (nValue == nNoDataValue)
5449
0
                        continue;
5450
0
                    if (nValue < nMin)
5451
0
                        nMin = nValue;
5452
0
                    if (nValue > nMax)
5453
0
                        nMax = nValue;
5454
                    if constexpr (COMPUTE_OTHER_STATS)
5455
0
                    {
5456
0
                        nValidCount++;
5457
0
                        nSum += nValue;
5458
0
                        nSumSquare +=
5459
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5460
0
                            nValue;
5461
0
                    }
5462
0
                }
5463
0
            }
5464
            if constexpr (COMPUTE_OTHER_STATS)
5465
0
            {
5466
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5467
0
            }
5468
0
        }
5469
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5470
0
                 nMax == std::numeric_limits<T>::max())
5471
0
        {
5472
            if constexpr (COMPUTE_OTHER_STATS)
5473
0
            {
5474
                // Optimization when there is no nodata and we know we have already
5475
                // reached the min and max
5476
0
                for (int iY = 0; iY < nYCheck; iY++)
5477
0
                {
5478
0
                    int iX;
5479
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5480
0
                    {
5481
0
                        const GPtrDiff_t iOffset =
5482
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5483
0
                        const GUIntBig nValue = pData[iOffset];
5484
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5485
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5486
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5487
0
                        nSum += nValue;
5488
0
                        nSumSquare += nValue * nValue;
5489
0
                        nSum += nValue2;
5490
0
                        nSumSquare += nValue2 * nValue2;
5491
0
                        nSum += nValue3;
5492
0
                        nSumSquare += nValue3 * nValue3;
5493
0
                        nSum += nValue4;
5494
0
                        nSumSquare += nValue4 * nValue4;
5495
0
                    }
5496
0
                    for (; iX < nXCheck; ++iX)
5497
0
                    {
5498
0
                        const GPtrDiff_t iOffset =
5499
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5500
0
                        const GUIntBig nValue = pData[iOffset];
5501
0
                        nSum += nValue;
5502
0
                        nSumSquare += nValue * nValue;
5503
0
                    }
5504
0
                }
5505
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5506
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5507
0
            }
5508
0
        }
5509
0
        else
5510
0
        {
5511
0
            for (int iY = 0; iY < nYCheck; iY++)
5512
0
            {
5513
0
                int iX;
5514
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5515
0
                {
5516
0
                    const GPtrDiff_t iOffset =
5517
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5518
0
                    const GUInt32 nValue = pData[iOffset];
5519
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5520
0
                    if (nValue < nValue2)
5521
0
                    {
5522
0
                        if (nValue < nMin)
5523
0
                            nMin = nValue;
5524
0
                        if (nValue2 > nMax)
5525
0
                            nMax = nValue2;
5526
0
                    }
5527
0
                    else
5528
0
                    {
5529
0
                        if (nValue2 < nMin)
5530
0
                            nMin = nValue2;
5531
0
                        if (nValue > nMax)
5532
0
                            nMax = nValue;
5533
0
                    }
5534
                    if constexpr (COMPUTE_OTHER_STATS)
5535
0
                    {
5536
0
                        nSum += nValue;
5537
0
                        nSumSquare +=
5538
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5539
0
                            nValue;
5540
0
                        nSum += nValue2;
5541
0
                        nSumSquare +=
5542
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5543
0
                            nValue2;
5544
0
                    }
5545
0
                }
5546
0
                if (iX < nXCheck)
5547
0
                {
5548
0
                    const GPtrDiff_t iOffset =
5549
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5550
0
                    const GUInt32 nValue = pData[iOffset];
5551
0
                    if (nValue < nMin)
5552
0
                        nMin = nValue;
5553
0
                    if (nValue > nMax)
5554
0
                        nMax = nValue;
5555
0
                    if (COMPUTE_OTHER_STATS)
5556
0
                    {
5557
0
                        nSum += nValue;
5558
0
                        nSumSquare +=
5559
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5560
0
                            nValue;
5561
0
                    }
5562
0
                }
5563
0
            }
5564
            if constexpr (COMPUTE_OTHER_STATS)
5565
0
            {
5566
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5567
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5568
0
            }
5569
0
        }
5570
0
    }
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned short, false>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned short, true>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5571
};
5572
5573
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5574
// using 64bit accumulators in internal loops. This also slightly helps in
5575
// 64bit mode.
5576
template <bool COMPUTE_OTHER_STATS>
5577
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5578
{
5579
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5580
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5581
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5582
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5583
0
    {
5584
0
        int nOuterLoops = nXCheck / 65536;
5585
0
        if (nXCheck % 65536)
5586
0
            nOuterLoops++;
5587
5588
0
        if (bHasNoData)
5589
0
        {
5590
            // General case
5591
0
            for (int iY = 0; iY < nYCheck; iY++)
5592
0
            {
5593
0
                int iX = 0;
5594
0
                for (int k = 0; k < nOuterLoops; k++)
5595
0
                {
5596
0
                    int iMax = iX + 65536;
5597
0
                    if (iMax > nXCheck)
5598
0
                        iMax = nXCheck;
5599
0
                    GUInt32 nSum32bit = 0;
5600
0
                    GUInt32 nSumSquare32bit = 0;
5601
0
                    GUInt32 nValidCount32bit = 0;
5602
0
                    GUInt32 nSampleCount32bit = 0;
5603
0
                    for (; iX < iMax; iX++)
5604
0
                    {
5605
0
                        const GPtrDiff_t iOffset =
5606
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5607
0
                        const GUInt32 nValue = pData[iOffset];
5608
5609
0
                        nSampleCount32bit++;
5610
0
                        if (nValue == nNoDataValue)
5611
0
                            continue;
5612
0
                        if (nValue < nMin)
5613
0
                            nMin = nValue;
5614
0
                        if (nValue > nMax)
5615
0
                            nMax = nValue;
5616
                        if constexpr (COMPUTE_OTHER_STATS)
5617
0
                        {
5618
0
                            nValidCount32bit++;
5619
0
                            nSum32bit += nValue;
5620
0
                            nSumSquare32bit += nValue * nValue;
5621
0
                        }
5622
0
                    }
5623
                    if constexpr (COMPUTE_OTHER_STATS)
5624
0
                    {
5625
0
                        nSampleCount += nSampleCount32bit;
5626
0
                        nValidCount += nValidCount32bit;
5627
0
                        nSum += nSum32bit;
5628
0
                        nSumSquare += nSumSquare32bit;
5629
0
                    }
5630
0
                }
5631
0
            }
5632
0
        }
5633
0
        else if (nMin == 0 && nMax == 255)
5634
0
        {
5635
            if constexpr (COMPUTE_OTHER_STATS)
5636
0
            {
5637
                // Optimization when there is no nodata and we know we have already
5638
                // reached the min and max
5639
0
                for (int iY = 0; iY < nYCheck; iY++)
5640
0
                {
5641
0
                    int iX = 0;
5642
0
                    for (int k = 0; k < nOuterLoops; k++)
5643
0
                    {
5644
0
                        int iMax = iX + 65536;
5645
0
                        if (iMax > nXCheck)
5646
0
                            iMax = nXCheck;
5647
0
                        GUInt32 nSum32bit = 0;
5648
0
                        GUInt32 nSumSquare32bit = 0;
5649
0
                        for (; iX + 3 < iMax; iX += 4)
5650
0
                        {
5651
0
                            const GPtrDiff_t iOffset =
5652
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5653
0
                            const GUInt32 nValue = pData[iOffset];
5654
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5655
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5656
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5657
0
                            nSum32bit += nValue;
5658
0
                            nSumSquare32bit += nValue * nValue;
5659
0
                            nSum32bit += nValue2;
5660
0
                            nSumSquare32bit += nValue2 * nValue2;
5661
0
                            nSum32bit += nValue3;
5662
0
                            nSumSquare32bit += nValue3 * nValue3;
5663
0
                            nSum32bit += nValue4;
5664
0
                            nSumSquare32bit += nValue4 * nValue4;
5665
0
                        }
5666
0
                        nSum += nSum32bit;
5667
0
                        nSumSquare += nSumSquare32bit;
5668
0
                    }
5669
0
                    for (; iX < nXCheck; ++iX)
5670
0
                    {
5671
0
                        const GPtrDiff_t iOffset =
5672
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673
0
                        const GUIntBig nValue = pData[iOffset];
5674
0
                        nSum += nValue;
5675
0
                        nSumSquare += nValue * nValue;
5676
0
                    }
5677
0
                }
5678
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5679
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5680
0
            }
5681
0
        }
5682
0
        else
5683
0
        {
5684
0
            for (int iY = 0; iY < nYCheck; iY++)
5685
0
            {
5686
0
                int iX = 0;
5687
0
                for (int k = 0; k < nOuterLoops; k++)
5688
0
                {
5689
0
                    int iMax = iX + 65536;
5690
0
                    if (iMax > nXCheck)
5691
0
                        iMax = nXCheck;
5692
0
                    GUInt32 nSum32bit = 0;
5693
0
                    GUInt32 nSumSquare32bit = 0;
5694
0
                    for (; iX + 1 < iMax; iX += 2)
5695
0
                    {
5696
0
                        const GPtrDiff_t iOffset =
5697
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5698
0
                        const GUInt32 nValue = pData[iOffset];
5699
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5700
0
                        if (nValue < nValue2)
5701
0
                        {
5702
0
                            if (nValue < nMin)
5703
0
                                nMin = nValue;
5704
0
                            if (nValue2 > nMax)
5705
0
                                nMax = nValue2;
5706
0
                        }
5707
0
                        else
5708
0
                        {
5709
0
                            if (nValue2 < nMin)
5710
0
                                nMin = nValue2;
5711
0
                            if (nValue > nMax)
5712
0
                                nMax = nValue;
5713
0
                        }
5714
                        if constexpr (COMPUTE_OTHER_STATS)
5715
0
                        {
5716
0
                            nSum32bit += nValue;
5717
0
                            nSumSquare32bit += nValue * nValue;
5718
0
                            nSum32bit += nValue2;
5719
0
                            nSumSquare32bit += nValue2 * nValue2;
5720
0
                        }
5721
0
                    }
5722
                    if constexpr (COMPUTE_OTHER_STATS)
5723
0
                    {
5724
0
                        nSum += nSum32bit;
5725
0
                        nSumSquare += nSumSquare32bit;
5726
0
                    }
5727
0
                }
5728
0
                if (iX < nXCheck)
5729
0
                {
5730
0
                    const GPtrDiff_t iOffset =
5731
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5732
0
                    const GUInt32 nValue = pData[iOffset];
5733
0
                    if (nValue < nMin)
5734
0
                        nMin = nValue;
5735
0
                    if (nValue > nMax)
5736
0
                        nMax = nValue;
5737
                    if constexpr (COMPUTE_OTHER_STATS)
5738
0
                    {
5739
0
                        nSum += nValue;
5740
0
                        nSumSquare +=
5741
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5742
0
                            nValue;
5743
0
                    }
5744
0
                }
5745
0
            }
5746
            if constexpr (COMPUTE_OTHER_STATS)
5747
0
            {
5748
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5749
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5750
0
            }
5751
0
        }
5752
0
    }
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned char, false>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternalGeneric<unsigned char, true>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5753
};
5754
5755
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5756
{
5757
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5758
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5759
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5760
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5761
    {
5762
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5763
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5764
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5765
    }
5766
};
5767
5768
constexpr int ALIGNMENT_AVX2_OPTIM = 32;
5769
5770
#if (defined(__x86_64__) || defined(_M_X64) ||                                 \
5771
     defined(USE_NEON_OPTIMIZATIONS)) &&                                       \
5772
    (defined(__GNUC__) || defined(_MSC_VER))
5773
5774
#include "gdal_avx2_emulation.hpp"
5775
5776
0
#define ZERO256 GDALmm256_setzero_si256()
5777
5778
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5779
static void
5780
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5781
                              // assumed to be aligned on 256 bits
5782
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5783
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5784
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5785
0
{
5786
    // 32-byte alignment may not be enforced by linker, so do it at hand
5787
0
    GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
5788
0
                             ALIGNMENT_AVX2_OPTIM +
5789
0
                             (COMPUTE_OTHER_STATS
5790
0
                                  ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
5791
0
                                  : 0)];
5792
0
    GByte *paby32ByteAligned =
5793
0
        aby32ByteUnaligned +
5794
0
        (ALIGNMENT_AVX2_OPTIM -
5795
0
         (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
5796
0
          ALIGNMENT_AVX2_OPTIM));
5797
0
    GByte *pabyMin = paby32ByteAligned;
5798
0
    GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
5799
0
    GUInt32 *panSum = COMPUTE_OTHER_STATS
5800
0
                          ? reinterpret_cast<GUInt32 *>(
5801
0
                                paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
5802
0
                          : nullptr;
5803
0
    GUInt32 *panSumSquare =
5804
0
        COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
5805
0
                                  paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
5806
0
                            : nullptr;
5807
5808
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
5809
5810
0
    GPtrDiff_t i = 0;
5811
    // Make sure that sumSquare can fit on uint32
5812
    // * 8 since we can hold 8 sums per vector register
5813
0
    const int nMaxIterationsPerInnerLoop =
5814
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5815
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5816
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5817
0
        nOuterLoops++;
5818
5819
0
    GDALm256i ymm_min =
5820
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5821
0
    GDALm256i ymm_max = ymm_min;
5822
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5823
5824
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5825
0
    {
5826
0
        const auto iMax =
5827
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5828
5829
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5830
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5831
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5832
0
            ZERO256;  // holds 8 uint32 sums
5833
0
        for (; i + 31 < iMax; i += 32)
5834
0
        {
5835
0
            const GDALm256i ymm = GDALmm256_load_si256(
5836
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5837
0
            if (COMPUTE_MIN)
5838
0
            {
5839
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5840
0
            }
5841
0
            if (COMPUTE_MAX)
5842
0
            {
5843
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5844
0
            }
5845
5846
            if constexpr (COMPUTE_OTHER_STATS)
5847
0
            {
5848
                // Extract even-8bit values
5849
0
                const GDALm256i ymm_even =
5850
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5851
                // Compute square of those 16 values as 32 bit result
5852
                // and add adjacent pairs
5853
0
                const GDALm256i ymm_even_square =
5854
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5855
                // Add to the sumsquare accumulator
5856
0
                ymm_sumsquare =
5857
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5858
5859
                // Extract odd-8bit values
5860
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5861
0
                const GDALm256i ymm_odd_square =
5862
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5863
0
                ymm_sumsquare =
5864
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5865
5866
                // Now compute the sums
5867
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5868
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5869
0
            }
5870
0
        }
5871
5872
        if constexpr (COMPUTE_OTHER_STATS)
5873
0
        {
5874
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5875
0
                                  ymm_sum);
5876
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5877
0
                                  ymm_sumsquare);
5878
5879
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5880
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5881
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5882
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5883
0
                          panSumSquare[7];
5884
0
        }
5885
0
    }
5886
5887
    if constexpr (COMPUTE_MIN)
5888
0
    {
5889
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5890
0
    }
5891
    if constexpr (COMPUTE_MAX)
5892
0
    {
5893
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5894
0
    }
5895
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5896
0
    {
5897
0
        for (int j = 0; j < 32; j++)
5898
0
        {
5899
            if constexpr (COMPUTE_MIN)
5900
0
            {
5901
0
                if (pabyMin[j] < nMin)
5902
0
                    nMin = pabyMin[j];
5903
0
            }
5904
            if constexpr (COMPUTE_MAX)
5905
0
            {
5906
0
                if (pabyMax[j] > nMax)
5907
0
                    nMax = pabyMax[j];
5908
0
            }
5909
0
        }
5910
0
    }
5911
5912
0
    for (; i < nBlockPixels; i++)
5913
0
    {
5914
0
        const GUInt32 nValue = pData[i];
5915
        if constexpr (COMPUTE_MIN)
5916
0
        {
5917
0
            if (nValue < nMin)
5918
0
                nMin = nValue;
5919
0
        }
5920
        if constexpr (COMPUTE_MAX)
5921
0
        {
5922
0
            if (nValue > nMax)
5923
0
                nMax = nValue;
5924
0
        }
5925
        if constexpr (COMPUTE_OTHER_STATS)
5926
0
        {
5927
0
            nSum += nValue;
5928
0
            nSumSquare +=
5929
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5930
0
        }
5931
0
    }
5932
5933
    if constexpr (COMPUTE_OTHER_STATS)
5934
0
    {
5935
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5936
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5937
0
    }
5938
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, true, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, false, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, true, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, false, false>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, true, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<true, false, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, true, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeStatisticsByteNoNodata<false, false, true>(long long, unsigned char const*, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
5939
5940
// SSE2/AVX2 optimization for GByte case
5941
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5942
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5943
// there are strictly equivalent to 2 parallel SSE2 streams.
5944
template <bool COMPUTE_OTHER_STATS>
5945
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5946
{
5947
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5948
                  // assumed to be aligned on 256 bits
5949
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5950
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5951
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5952
                  GUIntBig &nValidCount)
5953
0
    {
5954
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5955
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5956
0
            nMin <= nMax)
5957
0
        {
5958
            // 32-byte alignment may not be enforced by linker, so do it at hand
5959
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5960
0
            GByte *paby32ByteAligned =
5961
0
                aby32ByteUnaligned +
5962
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5963
0
            GByte *pabyMin = paby32ByteAligned;
5964
0
            GByte *pabyMax = paby32ByteAligned + 32;
5965
0
            GUInt32 *panSum =
5966
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5967
0
            GUInt32 *panSumSquare =
5968
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5969
5970
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5971
5972
0
            GPtrDiff_t i = 0;
5973
            // Make sure that sumSquare can fit on uint32
5974
            // * 8 since we can hold 8 sums per vector register
5975
0
            const int nMaxIterationsPerInnerLoop =
5976
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5977
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5978
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5979
0
                nOuterLoops++;
5980
5981
0
            const GDALm256i ymm_nodata =
5982
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5983
            // any non noData value in [min,max] would do.
5984
0
            const GDALm256i ymm_neutral =
5985
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5986
0
            GDALm256i ymm_min = ymm_neutral;
5987
0
            GDALm256i ymm_max = ymm_neutral;
5988
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5989
0
                GDALmm256_set1_epi16(0xFF);
5990
5991
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5992
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5993
0
            const bool bComputeMinMax =
5994
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
5995
5996
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5997
0
            {
5998
0
                const auto iMax =
5999
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6000
6001
                // holds 4 uint32 sums in [0], [2], [4] and [6]
6002
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
6003
                // holds 8 uint32 sums
6004
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
6005
                // holds 4 uint32 sums in [0], [2], [4] and [6]
6006
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
6007
0
                const auto iInit = i;
6008
0
                for (; i + 31 < iMax; i += 32)
6009
0
                {
6010
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6011
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6012
6013
                    // Check which values are nodata
6014
0
                    const GDALm256i ymm_eq_nodata =
6015
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6016
                    if constexpr (COMPUTE_OTHER_STATS)
6017
0
                    {
6018
                        // Count how many values are nodata (due to cmpeq
6019
                        // putting 255 when condition is met, this will actually
6020
                        // be 255 times the number of nodata value, spread in 4
6021
                        // 64 bits words). We can use add_epi32 as the counter
6022
                        // will not overflow uint32
6023
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6024
0
                            ymm_count_nodata_mul_255,
6025
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6026
0
                    }
6027
                    // Replace all nodata values by zero for the purpose of sum
6028
                    // and sumquare.
6029
0
                    const GDALm256i ymm_nodata_by_zero =
6030
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6031
0
                    if (bComputeMinMax)
6032
0
                    {
6033
                        // Replace all nodata values by a neutral value for the
6034
                        // purpose of min and max.
6035
0
                        const GDALm256i ymm_nodata_by_neutral =
6036
0
                            GDALmm256_or_si256(
6037
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6038
0
                                ymm_nodata_by_zero);
6039
6040
0
                        ymm_min =
6041
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6042
0
                        ymm_max =
6043
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6044
0
                    }
6045
6046
                    if constexpr (COMPUTE_OTHER_STATS)
6047
0
                    {
6048
                        // Extract even-8bit values
6049
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
6050
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
6051
                        // Compute square of those 16 values as 32 bit result
6052
                        // and add adjacent pairs
6053
0
                        const GDALm256i ymm_even_square =
6054
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
6055
                        // Add to the sumsquare accumulator
6056
0
                        ymm_sumsquare =
6057
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6058
6059
                        // Extract odd-8bit values
6060
0
                        const GDALm256i ymm_odd =
6061
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6062
0
                        const GDALm256i ymm_odd_square =
6063
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6064
0
                        ymm_sumsquare =
6065
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6066
6067
                        // Now compute the sums
6068
0
                        ymm_sum = GDALmm256_add_epi32(
6069
0
                            ymm_sum,
6070
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6071
0
                    }
6072
0
                }
6073
6074
                if constexpr (COMPUTE_OTHER_STATS)
6075
0
                {
6076
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
6077
0
                    GDALmm256_store_si256(
6078
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6079
0
                        ymm_count_nodata_mul_255);
6080
6081
0
                    nSampleCount += (i - iInit);
6082
6083
0
                    nValidCount +=
6084
0
                        (i - iInit) -
6085
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6086
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6087
0
                            255;
6088
6089
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6090
0
                                          ymm_sum);
6091
0
                    GDALmm256_store_si256(
6092
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
6093
0
                        ymm_sumsquare);
6094
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6095
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6096
0
                                  panSumSquare[1] + panSumSquare[2] +
6097
0
                                  panSumSquare[3] + panSumSquare[4] +
6098
0
                                  panSumSquare[5] + panSumSquare[6] +
6099
0
                                  panSumSquare[7];
6100
0
                }
6101
0
            }
6102
6103
0
            if (bComputeMinMax)
6104
0
            {
6105
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6106
0
                                      ymm_min);
6107
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6108
0
                                      ymm_max);
6109
0
                for (int j = 0; j < 32; j++)
6110
0
                {
6111
0
                    if (pabyMin[j] < nMin)
6112
0
                        nMin = pabyMin[j];
6113
0
                    if (pabyMax[j] > nMax)
6114
0
                        nMax = pabyMax[j];
6115
0
                }
6116
0
            }
6117
6118
            if constexpr (COMPUTE_OTHER_STATS)
6119
0
            {
6120
0
                nSampleCount += nBlockPixels - i;
6121
0
            }
6122
0
            for (; i < nBlockPixels; i++)
6123
0
            {
6124
0
                const GUInt32 nValue = pData[i];
6125
0
                if (nValue == nNoDataValue)
6126
0
                    continue;
6127
0
                if (nValue < nMin)
6128
0
                    nMin = nValue;
6129
0
                if (nValue > nMax)
6130
0
                    nMax = nValue;
6131
                if constexpr (COMPUTE_OTHER_STATS)
6132
0
                {
6133
0
                    nValidCount++;
6134
0
                    nSum += nValue;
6135
0
                    nSumSquare +=
6136
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6137
0
                        nValue;
6138
0
                }
6139
0
            }
6140
0
        }
6141
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6142
0
        {
6143
0
            if (nMin > 0)
6144
0
            {
6145
0
                if (nMax < 255)
6146
0
                {
6147
0
                    ComputeStatisticsByteNoNodata<true, true,
6148
0
                                                  COMPUTE_OTHER_STATS>(
6149
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6150
0
                        nSampleCount, nValidCount);
6151
0
                }
6152
0
                else
6153
0
                {
6154
0
                    ComputeStatisticsByteNoNodata<true, false,
6155
0
                                                  COMPUTE_OTHER_STATS>(
6156
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6157
0
                        nSampleCount, nValidCount);
6158
0
                }
6159
0
            }
6160
0
            else
6161
0
            {
6162
0
                if (nMax < 255)
6163
0
                {
6164
0
                    ComputeStatisticsByteNoNodata<false, true,
6165
0
                                                  COMPUTE_OTHER_STATS>(
6166
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6167
0
                        nSampleCount, nValidCount);
6168
0
                }
6169
0
                else
6170
0
                {
6171
0
                    ComputeStatisticsByteNoNodata<false, false,
6172
0
                                                  COMPUTE_OTHER_STATS>(
6173
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6174
0
                        nSampleCount, nValidCount);
6175
0
                }
6176
0
            }
6177
0
        }
6178
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6179
0
                 (nBlockXSize % 32) == 0)
6180
0
        {
6181
0
            for (int iY = 0; iY < nYCheck; iY++)
6182
0
            {
6183
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6184
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6185
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6186
0
            }
6187
0
        }
6188
0
        else
6189
0
        {
6190
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6191
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6192
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6193
0
        }
6194
0
    }
Unexecuted instantiation: ComputeStatisticsInternal<unsigned char, false>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternal<unsigned char, true>::f(int, int, int, unsigned char const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
6195
};
6196
6197
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6198
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6199
                             GUIntBig i)
6200
0
{
6201
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6202
0
}
6203
6204
// AVX2/SSE2 optimization for GUInt16 case
6205
template <bool COMPUTE_OTHER_STATS>
6206
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6207
{
6208
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6209
                  // assumed to be aligned on 128 bits
6210
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6211
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6212
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6213
                  GUIntBig &nValidCount)
6214
0
    {
6215
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6216
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6217
0
        {
6218
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6219
6220
0
            GPtrDiff_t i = 0;
6221
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6222
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6223
            // Furthermore the shift is also needed to use madd_epi16
6224
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6225
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6226
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6227
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6228
0
            GDALm256i ymm_max = ymm_min;
6229
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6230
0
                ZERO256;  // holds 4 uint64 sums
6231
6232
            // Make sure that sum can fit on uint32
6233
            // * 8 since we can hold 8 sums per vector register
6234
0
            const int nMaxIterationsPerInnerLoop =
6235
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6236
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6237
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6238
0
                nOuterLoops++;
6239
6240
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6241
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6242
0
                GDALmm256_set1_epi32(0xFFFF);
6243
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6244
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6245
6246
0
            GUIntBig nSumThis = 0;
6247
0
            for (int k = 0; k < nOuterLoops; k++)
6248
0
            {
6249
0
                const auto iMax =
6250
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6251
6252
0
                [[maybe_unused]] GDALm256i ymm_sum =
6253
0
                    ZERO256;  // holds 8 uint32 sums
6254
0
                for (; i + 15 < iMax; i += 16)
6255
0
                {
6256
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6257
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6258
0
                    const GDALm256i ymm_shifted =
6259
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6260
0
                    if (bComputeMinMax)
6261
0
                    {
6262
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6263
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6264
0
                    }
6265
6266
                    if constexpr (COMPUTE_OTHER_STATS)
6267
0
                    {
6268
                        // Note: the int32 range can overflow for (0-32768)^2 +
6269
                        // (0-32768)^2 = 0x80000000, but as we know the result
6270
                        // is positive, this is OK as we interpret is a uint32.
6271
0
                        const GDALm256i ymm_square =
6272
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6273
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6274
0
                            ymm_sumsquare,
6275
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6276
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6277
0
                            ymm_sumsquare,
6278
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6279
6280
                        // Now compute the sums
6281
0
                        ymm_sum = GDALmm256_add_epi32(
6282
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6283
0
                        ymm_sum = GDALmm256_add_epi32(
6284
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6285
0
                    }
6286
0
                }
6287
6288
                if constexpr (COMPUTE_OTHER_STATS)
6289
0
                {
6290
0
                    GUInt32 anSum[8];
6291
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6292
0
                                           ymm_sum);
6293
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6294
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6295
0
                                anSum[6] + anSum[7];
6296
0
                }
6297
0
            }
6298
6299
0
            if (bComputeMinMax)
6300
0
            {
6301
0
                GUInt16 anMin[16];
6302
0
                GUInt16 anMax[16];
6303
6304
                // Unshift the result
6305
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6306
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6307
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6308
0
                                       ymm_min);
6309
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6310
0
                                       ymm_max);
6311
0
                for (int j = 0; j < 16; j++)
6312
0
                {
6313
0
                    if (anMin[j] < nMin)
6314
0
                        nMin = anMin[j];
6315
0
                    if (anMax[j] > nMax)
6316
0
                        nMax = anMax[j];
6317
0
                }
6318
0
            }
6319
6320
            if constexpr (COMPUTE_OTHER_STATS)
6321
0
            {
6322
0
                GUIntBig anSumSquare[4];
6323
0
                GDALmm256_storeu_si256(
6324
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6325
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6326
0
                              anSumSquare[3];
6327
6328
                // Unshift the sum of squares
6329
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6330
0
                                 static_cast<GUIntBig>(i));
6331
6332
0
                nSum += nSumThis;
6333
6334
0
                for (; i < nBlockPixels; i++)
6335
0
                {
6336
0
                    const GUInt32 nValue = pData[i];
6337
0
                    if (nValue < nMin)
6338
0
                        nMin = nValue;
6339
0
                    if (nValue > nMax)
6340
0
                        nMax = nValue;
6341
0
                    nSum += nValue;
6342
0
                    nSumSquare +=
6343
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6344
0
                        nValue;
6345
0
                }
6346
6347
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6348
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6349
0
            }
6350
0
        }
6351
0
        else
6352
0
        {
6353
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6354
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6355
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6356
0
        }
6357
0
    }
Unexecuted instantiation: ComputeStatisticsInternal<unsigned short, false>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
Unexecuted instantiation: ComputeStatisticsInternal<unsigned short, true>::f(int, int, int, unsigned short const*, bool, unsigned int, unsigned int&, unsigned int&, unsigned long long&, unsigned long long&, unsigned long long&, unsigned long long&)
6358
};
6359
6360
#endif
6361
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6362
// defined(_MSC_VER))
6363
6364
/************************************************************************/
6365
/*                           GetPixelValue()                            */
6366
/************************************************************************/
6367
6368
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6369
                                   const void *pData, GPtrDiff_t iOffset,
6370
                                   const GDALNoDataValues &sNoDataValues,
6371
                                   bool &bValid)
6372
0
{
6373
0
    bValid = true;
6374
0
    double dfValue = 0;
6375
0
    switch (eDataType)
6376
0
    {
6377
0
        case GDT_UInt8:
6378
0
        {
6379
0
            if (bSignedByte)
6380
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6381
0
            else
6382
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6383
0
            break;
6384
0
        }
6385
0
        case GDT_Int8:
6386
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6387
0
            break;
6388
0
        case GDT_UInt16:
6389
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6390
0
            break;
6391
0
        case GDT_Int16:
6392
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6393
0
            break;
6394
0
        case GDT_UInt32:
6395
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6396
0
            break;
6397
0
        case GDT_Int32:
6398
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6399
0
            break;
6400
0
        case GDT_UInt64:
6401
0
            dfValue = static_cast<double>(
6402
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6403
0
            break;
6404
0
        case GDT_Int64:
6405
0
            dfValue = static_cast<double>(
6406
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6407
0
            break;
6408
0
        case GDT_Float16:
6409
0
        {
6410
0
            using namespace std;
6411
0
            const GFloat16 hfValue =
6412
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6413
0
            if (isnan(hfValue) ||
6414
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6415
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6416
0
            {
6417
0
                bValid = false;
6418
0
                return 0.0;
6419
0
            }
6420
0
            dfValue = hfValue;
6421
0
            return dfValue;
6422
0
        }
6423
0
        case GDT_Float32:
6424
0
        {
6425
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6426
0
            if (std::isnan(fValue) ||
6427
0
                (sNoDataValues.bGotFloatNoDataValue &&
6428
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6429
0
            {
6430
0
                bValid = false;
6431
0
                return 0.0;
6432
0
            }
6433
0
            dfValue = double(fValue);
6434
0
            return dfValue;
6435
0
        }
6436
0
        case GDT_Float64:
6437
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6438
0
            if (std::isnan(dfValue))
6439
0
            {
6440
0
                bValid = false;
6441
0
                return 0.0;
6442
0
            }
6443
0
            break;
6444
0
        case GDT_CInt16:
6445
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6446
0
            break;
6447
0
        case GDT_CInt32:
6448
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6449
0
            break;
6450
0
        case GDT_CFloat16:
6451
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6452
0
            if (std::isnan(dfValue))
6453
0
            {
6454
0
                bValid = false;
6455
0
                return 0.0;
6456
0
            }
6457
0
            break;
6458
0
        case GDT_CFloat32:
6459
0
            dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6460
0
            if (std::isnan(dfValue))
6461
0
            {
6462
0
                bValid = false;
6463
0
                return 0.0;
6464
0
            }
6465
0
            break;
6466
0
        case GDT_CFloat64:
6467
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6468
0
            if (std::isnan(dfValue))
6469
0
            {
6470
0
                bValid = false;
6471
0
                return 0.0;
6472
0
            }
6473
0
            break;
6474
0
        case GDT_Unknown:
6475
0
        case GDT_TypeCount:
6476
0
            CPLAssert(false);
6477
0
            break;
6478
0
    }
6479
6480
0
    if (sNoDataValues.bGotNoDataValue &&
6481
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6482
0
    {
6483
0
        bValid = false;
6484
0
        return 0.0;
6485
0
    }
6486
0
    return dfValue;
6487
0
}
6488
6489
/************************************************************************/
6490
/*                          SetValidPercent()                           */
6491
/************************************************************************/
6492
6493
//! @cond Doxygen_Suppress
6494
/**
6495
 * \brief Set percentage of valid (not nodata) pixels.
6496
 *
6497
 * Stores the percentage of valid pixels in the metadata item
6498
 * STATISTICS_VALID_PERCENT
6499
 *
6500
 * @param nSampleCount Number of sampled pixels.
6501
 *
6502
 * @param nValidCount Number of valid pixels.
6503
 */
6504
6505
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6506
                                     GUIntBig nValidCount)
6507
0
{
6508
0
    if (nValidCount == 0)
6509
0
    {
6510
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6511
0
    }
6512
0
    else if (nValidCount == nSampleCount)
6513
0
    {
6514
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6515
0
    }
6516
0
    else /* nValidCount < nSampleCount */
6517
0
    {
6518
0
        char szValue[128] = {0};
6519
6520
        /* percentage is only an indicator: limit precision */
6521
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6522
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6523
6524
0
        if (EQUAL(szValue, "100"))
6525
0
        {
6526
            /* don't set 100 percent valid
6527
             * because some of the sampled pixels were nodata */
6528
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6529
0
        }
6530
0
        else
6531
0
        {
6532
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6533
0
        }
6534
0
    }
6535
0
}
6536
6537
//! @endcond
6538
6539
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6540
6541
#ifdef __AVX2__
6542
6543
#define set1_ps _mm256_set1_ps
6544
#define loadu_ps _mm256_loadu_ps
6545
#define or_ps _mm256_or_ps
6546
#define min_ps _mm256_min_ps
6547
#define max_ps _mm256_max_ps
6548
#define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6549
#define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6550
#define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6551
#define movemask_ps _mm256_movemask_ps
6552
#define storeu_ps _mm256_storeu_ps
6553
#define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6554
#define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6555
6556
#define unpacklo_ps _mm256_unpacklo_ps
6557
#define castps_pd _mm256_castps_pd
6558
6559
inline __m256 dup_hi_ps(__m256 x)
6560
{
6561
    const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6562
    return _mm256_permutevar8x32_ps(x, idx);
6563
}
6564
6565
#define setzero_pd _mm256_setzero_pd
6566
#define set1_pd _mm256_set1_pd
6567
#define loadu_pd _mm256_loadu_pd
6568
#define or_pd _mm256_or_pd
6569
#define min_pd _mm256_min_pd
6570
#define max_pd _mm256_max_pd
6571
#define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6572
#define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6573
#define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6574
#define movemask_pd _mm256_movemask_pd
6575
#define add_pd _mm256_add_pd
6576
#define sub_pd _mm256_sub_pd
6577
#define mul_pd _mm256_mul_pd
6578
#define div_pd _mm256_div_pd
6579
#define storeu_pd _mm256_storeu_pd
6580
#define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6581
#define blendv_pd _mm256_blendv_pd
6582
#ifdef __FMA__
6583
#define fmadd_pd _mm256_fmadd_pd
6584
#else
6585
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6586
#endif
6587
6588
#else
6589
6590
0
#define set1_ps _mm_set1_ps
6591
0
#define loadu_ps _mm_loadu_ps
6592
0
#define or_ps _mm_or_ps
6593
0
#define min_ps _mm_min_ps
6594
0
#define max_ps _mm_max_ps
6595
0
#define cmpeq_ps _mm_cmpeq_ps
6596
0
#define cmpneq_ps _mm_cmpneq_ps
6597
0
#define cmpunord_ps _mm_cmpunord_ps
6598
0
#define movemask_ps _mm_movemask_ps
6599
0
#define storeu_ps _mm_storeu_ps
6600
0
#define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6601
0
#define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6602
0
#define unpacklo_ps _mm_unpacklo_ps
6603
0
#define castps_pd _mm_castps_pd
6604
0
#define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6605
6606
0
#define setzero_pd _mm_setzero_pd
6607
0
#define set1_pd _mm_set1_pd
6608
0
#define loadu_pd _mm_loadu_pd
6609
0
#define or_pd _mm_or_pd
6610
0
#define min_pd _mm_min_pd
6611
0
#define max_pd _mm_max_pd
6612
0
#define cmpeq_pd _mm_cmpeq_pd
6613
0
#define cmpneq_pd _mm_cmpneq_pd
6614
0
#define cmpunord_pd _mm_cmpunord_pd
6615
0
#define movemask_pd _mm_movemask_pd
6616
0
#define add_pd _mm_add_pd
6617
0
#define sub_pd _mm_sub_pd
6618
0
#define mul_pd _mm_mul_pd
6619
0
#define div_pd _mm_div_pd
6620
0
#define storeu_pd _mm_storeu_pd
6621
0
#define cvtsd_f64 _mm_cvtsd_f64
6622
#ifdef __FMA__
6623
#define fmadd_pd _mm_fmadd_pd
6624
#else
6625
0
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6626
#endif
6627
6628
inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6629
0
{
6630
#if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6631
    return _mm_blendv_pd(a, b, mask);
6632
#else
6633
0
    return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6634
0
#endif
6635
0
}
6636
#endif
6637
6638
0
#define dup_lo_ps(x) unpacklo_ps((x), (x))
6639
6640
/************************************************************************/
6641
/*                   ComputeStatisticsFloat32_SSE2()                    */
6642
/************************************************************************/
6643
6644
template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6645
#if defined(__GNUC__)
6646
__attribute__((noinline))
6647
#endif
6648
static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
6649
                                         [[maybe_unused]] float fNoDataValue,
6650
                                         int iX, int nCount, float &fMin,
6651
                                         float &fMax, double &dfBlockMean,
6652
                                         double &dfBlockM2,
6653
                                         double &dfBlockValidCount)
6654
0
{
6655
0
    auto vValidCount = setzero_pd();
6656
0
    const auto vOne = set1_pd(1);
6657
0
    [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6658
6659
0
    auto vMin = set1_ps(fMin);
6660
0
    auto vMax = set1_ps(fMax);
6661
6662
0
    auto vMean_lo = setzero_pd();
6663
0
    auto vM2_lo = setzero_pd();
6664
6665
0
    auto vMean_hi = setzero_pd();
6666
0
    auto vM2_hi = setzero_pd();
6667
6668
0
    constexpr int VALS_PER_LOOP =
6669
0
        static_cast<int>(sizeof(vOne) / sizeof(float));
6670
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6671
0
    {
6672
0
        const auto vValues = loadu_ps(pafData + iX);
6673
6674
        if constexpr (HAS_NAN)
6675
0
        {
6676
0
            auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6677
            if constexpr (HAS_NODATA)
6678
0
            {
6679
0
                isNaNOrNoData =
6680
0
                    or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6681
0
            }
6682
0
            if (movemask_ps(isNaNOrNoData))
6683
0
            {
6684
0
                break;
6685
0
            }
6686
        }
6687
        else if constexpr (HAS_NODATA)
6688
0
        {
6689
0
            if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6690
0
            {
6691
0
                break;
6692
0
            }
6693
0
        }
6694
6695
0
        vMin = min_ps(vMin, vValues);
6696
0
        vMax = max_ps(vMax, vValues);
6697
6698
0
        const auto vValues_lo = cvtps_lo_pd(vValues);
6699
0
        const auto vValues_hi = cvtps_hi_pd(vValues);
6700
0
        [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6701
6702
0
        vValidCount = add_pd(vValidCount, vOne);
6703
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6704
6705
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6706
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6707
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6708
0
        {
6709
0
            const auto vMinNotSameAsMax_lo =
6710
0
                castps_pd(dup_lo_ps(vMinNotSameAsMax));
6711
0
            vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6712
0
            const auto vNewM2_lo =
6713
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6714
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6715
        }
6716
        else
6717
0
        {
6718
0
            vMean_lo = vNewMean_lo;
6719
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6720
0
        }
6721
6722
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6723
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6724
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6725
0
        {
6726
0
            const auto vMinNotSameAsMax_hi =
6727
0
                castps_pd(dup_hi_ps(vMinNotSameAsMax));
6728
0
            vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6729
0
            const auto vNewM2_hi =
6730
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6731
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6732
        }
6733
        else
6734
0
        {
6735
0
            vMean_hi = vNewMean_hi;
6736
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6737
0
        }
6738
0
    }
6739
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6740
0
    if (dfValidVectorCount > 0)
6741
0
    {
6742
0
        float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6743
0
        storeu_ps(afMin, vMin);
6744
0
        storeu_ps(afMax, vMax);
6745
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6746
0
        {
6747
0
            fMin = std::min(fMin, afMin[i]);
6748
0
            fMax = std::max(fMax, afMax[i]);
6749
0
        }
6750
6751
0
        double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6752
0
        storeu_pd(adfMean, vMean_lo);
6753
0
        storeu_pd(adfM2, vM2_lo);
6754
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6755
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6756
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6757
0
        {
6758
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6759
0
            dfBlockM2 += adfM2[i];
6760
0
            if (adfMean[i] != dfBlockMean)
6761
0
            {
6762
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6763
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6764
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6765
0
                             dfValidVectorCount / dfNewValidCount;
6766
0
            }
6767
0
            dfBlockValidCount = dfNewValidCount;
6768
0
        }
6769
0
    }
6770
6771
0
    return iX;
6772
0
}
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, false, true>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, true, true>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, false, false>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, true, false>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, false, true>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, true, true>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, false, false>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, true, false>(float const*, float, int, int, float&, float&, double&, double&, double&)
6773
6774
/************************************************************************/
6775
/*                   ComputeStatisticsFloat64_SSE2()                    */
6776
/************************************************************************/
6777
6778
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6779
#if defined(__GNUC__)
6780
__attribute__((noinline))
6781
#endif
6782
static int ComputeStatisticsFloat64_SSE2(const double *padfData,
6783
                                         [[maybe_unused]] double dfNoDataValue,
6784
                                         int iX, int nCount, double &dfMin,
6785
                                         double &dfMax, double &dfBlockMean,
6786
                                         double &dfBlockM2,
6787
                                         double &dfBlockValidCount)
6788
0
{
6789
0
    auto vValidCount = setzero_pd();
6790
0
    const auto vOne = set1_pd(1);
6791
0
    [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6792
6793
0
    auto vMin_lo = set1_pd(dfMin);
6794
0
    auto vMax_lo = set1_pd(dfMax);
6795
0
    auto vMean_lo = setzero_pd();
6796
0
    auto vM2_lo = setzero_pd();
6797
6798
0
    auto vMin_hi = vMin_lo;
6799
0
    auto vMax_hi = vMax_lo;
6800
0
    auto vMean_hi = setzero_pd();
6801
0
    auto vM2_hi = setzero_pd();
6802
6803
0
    constexpr int VALS_PER_LOOP =
6804
0
        2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6805
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6806
0
    {
6807
0
        const auto vValues_lo = loadu_pd(padfData + iX);
6808
0
        const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6809
        // Check if there's at least one NaN in both vectors
6810
0
        auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6811
        if constexpr (HAS_NODATA)
6812
0
        {
6813
0
            isNaNOrNoData =
6814
0
                or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6815
0
                                           cmpeq_pd(vValues_hi, vNoData)));
6816
0
        }
6817
0
        if (movemask_pd(isNaNOrNoData))
6818
0
        {
6819
0
            break;
6820
0
        }
6821
6822
0
        vValidCount = add_pd(vValidCount, vOne);
6823
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6824
6825
0
        vMin_lo = min_pd(vMin_lo, vValues_lo);
6826
0
        vMax_lo = max_pd(vMax_lo, vValues_lo);
6827
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6828
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6829
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6830
0
        {
6831
0
            const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6832
0
            vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6833
0
            const auto vNewM2_lo =
6834
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6835
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6836
        }
6837
        else
6838
0
        {
6839
0
            vMean_lo = vNewMean_lo;
6840
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6841
0
        }
6842
6843
0
        vMin_hi = min_pd(vMin_hi, vValues_hi);
6844
0
        vMax_hi = max_pd(vMax_hi, vValues_hi);
6845
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6846
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6847
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6848
0
        {
6849
0
            const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6850
0
            vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6851
0
            const auto vNewM2_hi =
6852
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6853
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6854
        }
6855
        else
6856
0
        {
6857
0
            vMean_hi = vNewMean_hi;
6858
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6859
0
        }
6860
0
    }
6861
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6862
0
    if (dfValidVectorCount > 0)
6863
0
    {
6864
0
        double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6865
0
            adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6866
0
        storeu_pd(adfMin, vMin_lo);
6867
0
        storeu_pd(adfMax, vMax_lo);
6868
0
        storeu_pd(adfMean, vMean_lo);
6869
0
        storeu_pd(adfM2, vM2_lo);
6870
0
        storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6871
0
        storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6872
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6873
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6874
6875
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6876
0
        {
6877
0
            dfMin = std::min(dfMin, adfMin[i]);
6878
0
            dfMax = std::max(dfMax, adfMax[i]);
6879
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6880
0
            dfBlockM2 += adfM2[i];
6881
0
            if (adfMean[i] != dfBlockMean)
6882
0
            {
6883
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6884
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6885
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6886
0
                             dfValidVectorCount / dfNewValidCount;
6887
0
            }
6888
0
            dfBlockValidCount = dfNewValidCount;
6889
0
        }
6890
0
    }
6891
6892
0
    return iX;
6893
0
}
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<false, true>(double const*, double, int, int, double&, double&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<false, false>(double const*, double, int, int, double&, double&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<true, true>(double const*, double, int, int, double&, double&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat64_SSE2<true, false>(double const*, double, int, int, double&, double&, double&, double&, double&)
6894
6895
#endif
6896
6897
/************************************************************************/
6898
/*                   ComputeBlockStatisticsFloat32()                    */
6899
/************************************************************************/
6900
6901
template <bool HAS_NAN, bool HAS_NODATA>
6902
static void ComputeBlockStatisticsFloat32(
6903
    const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6904
    const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6905
    float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6906
    double &dfBlockValidCountInOut)
6907
0
{
6908
0
    float fMin = fMinInOut;
6909
0
    float fMax = fMaxInOut;
6910
0
    double dfBlockMean = dfBlockMeanInOut;
6911
0
    double dfBlockM2 = dfBlockM2InOut;
6912
0
    double dfBlockValidCount = dfBlockValidCountInOut;
6913
6914
0
    for (int iY = 0; iY < nYCheck; iY++)
6915
0
    {
6916
0
        const int iOffset = iY * nBlockXSize;
6917
0
        if (dfBlockValidCount > 0 && fMin != fMax)
6918
0
        {
6919
0
            int iX = 0;
6920
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6921
0
            iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6922
0
                                               /* bCheckMinEqMax = */ false,
6923
0
                                               HAS_NODATA>(
6924
0
                pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6925
0
                fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6926
0
#endif
6927
0
            for (; iX < nXCheck; iX++)
6928
0
            {
6929
0
                const float fValue = pafSrcData[iOffset + iX];
6930
                if constexpr (HAS_NAN)
6931
0
                {
6932
0
                    if (std::isnan(fValue))
6933
0
                        continue;
6934
0
                }
6935
                if constexpr (HAS_NODATA)
6936
0
                {
6937
0
                    if (fValue == sNoDataValues.fNoDataValue)
6938
0
                        continue;
6939
0
                }
6940
0
                fMin = std::min(fMin, fValue);
6941
0
                fMax = std::max(fMax, fValue);
6942
0
                dfBlockValidCount += 1.0;
6943
0
                const double dfValue = static_cast<double>(fValue);
6944
0
                const double dfDelta = dfValue - dfBlockMean;
6945
0
                dfBlockMean += dfDelta / dfBlockValidCount;
6946
0
                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6947
0
            }
6948
0
        }
6949
0
        else
6950
0
        {
6951
0
            int iX = 0;
6952
0
            if (dfBlockValidCount == 0)
6953
0
            {
6954
0
                while (iX < nXCheck)
6955
0
                {
6956
0
                    const float fValue = pafSrcData[iOffset + iX];
6957
0
                    ++iX;
6958
                    if constexpr (HAS_NAN)
6959
0
                    {
6960
0
                        if (std::isnan(fValue))
6961
0
                            continue;
6962
0
                    }
6963
                    if constexpr (HAS_NODATA)
6964
0
                    {
6965
0
                        if (fValue == sNoDataValues.fNoDataValue)
6966
0
                            continue;
6967
0
                    }
6968
0
                    fMin = std::min(fMin, fValue);
6969
0
                    fMax = std::max(fMax, fValue);
6970
0
                    dfBlockValidCount = 1;
6971
0
                    dfBlockMean = static_cast<double>(fValue);
6972
0
                    break;
6973
0
                }
6974
0
            }
6975
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6976
0
            iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6977
0
                                               /* bCheckMinEqMax = */ true,
6978
0
                                               HAS_NODATA>(
6979
0
                pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6980
0
                fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6981
0
#endif
6982
0
            for (; iX < nXCheck; iX++)
6983
0
            {
6984
0
                const float fValue = pafSrcData[iOffset + iX];
6985
                if constexpr (HAS_NAN)
6986
0
                {
6987
0
                    if (std::isnan(fValue))
6988
0
                        continue;
6989
0
                }
6990
                if constexpr (HAS_NODATA)
6991
0
                {
6992
0
                    if (fValue == sNoDataValues.fNoDataValue)
6993
0
                        continue;
6994
0
                }
6995
0
                fMin = std::min(fMin, fValue);
6996
0
                fMax = std::max(fMax, fValue);
6997
0
                dfBlockValidCount += 1.0;
6998
0
                if (fMin != fMax)
6999
0
                {
7000
0
                    const double dfValue = static_cast<double>(fValue);
7001
0
                    const double dfDelta = dfValue - dfBlockMean;
7002
0
                    dfBlockMean += dfDelta / dfBlockValidCount;
7003
0
                    dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7004
0
                }
7005
0
            }
7006
0
        }
7007
0
    }
7008
7009
0
    fMinInOut = fMin;
7010
0
    fMaxInOut = fMax;
7011
0
    dfBlockMeanInOut = dfBlockMean;
7012
0
    dfBlockM2InOut = dfBlockM2;
7013
0
    dfBlockValidCountInOut = dfBlockValidCount;
7014
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeBlockStatisticsFloat32<false, true>(float const*, int, int, int, GDALNoDataValues const&, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeBlockStatisticsFloat32<false, false>(float const*, int, int, int, GDALNoDataValues const&, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeBlockStatisticsFloat32<true, true>(float const*, int, int, int, GDALNoDataValues const&, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeBlockStatisticsFloat32<true, false>(float const*, int, int, int, GDALNoDataValues const&, float&, float&, double&, double&, double&)
7015
7016
/************************************************************************/
7017
/*                        StatisticsTaskFloat32                         */
7018
/************************************************************************/
7019
7020
namespace
7021
{
7022
struct StatisticsTaskFloat32
7023
{
7024
    double dfBlockMean = 0;
7025
    double dfBlockM2 = 0;
7026
    double dfBlockValidCount = 0;
7027
    GDALDataType eDataType = GDT_Unknown;
7028
    bool bHasNoData = false;
7029
    GDALNoDataValues *psNoDataValues = nullptr;
7030
    const float *pafSrcData = nullptr;
7031
    float fMin = std::numeric_limits<float>::infinity();
7032
    float fMax = -std::numeric_limits<float>::infinity();
7033
    int nChunkXSize = 0;
7034
    int nXCheck = 0;
7035
    int nYCheck = 0;
7036
7037
    void Perform()
7038
0
    {
7039
0
        if (GDALDataTypeIsInteger(eDataType))
7040
0
        {
7041
0
            if (bHasNoData)
7042
0
            {
7043
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7044
0
                                              /* HAS_NODATA = */ true>(
7045
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7046
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7047
0
            }
7048
0
            else
7049
0
            {
7050
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7051
0
                                              /* HAS_NODATA = */ false>(
7052
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7053
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7054
0
            }
7055
0
        }
7056
0
        else
7057
0
        {
7058
0
            if (bHasNoData)
7059
0
            {
7060
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7061
0
                                              /* HAS_NODATA = */ true>(
7062
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7063
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7064
0
            }
7065
0
            else
7066
0
            {
7067
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7068
0
                                              /* HAS_NODATA = */ false>(
7069
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7070
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7071
0
            }
7072
0
        }
7073
0
    }
7074
};
7075
}  // namespace
7076
7077
/************************************************************************/
7078
/*                         ComputeStatistics()                          */
7079
/************************************************************************/
7080
7081
/**
7082
 * \brief Compute image statistics.
7083
 *
7084
 * Returns the minimum, maximum, mean and standard deviation of all
7085
 * pixel values in this band.  If approximate statistics are sufficient,
7086
 * the bApproxOK flag can be set to true in which case overviews, or a
7087
 * subset of image tiles may be used in computing the statistics.
7088
 *
7089
 * Once computed, the statistics will generally be "set" back on the
7090
 * raster band using SetStatistics().
7091
 *
7092
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7093
 *
7094
 * This method is the same as the C function GDALComputeRasterStatistics().
7095
 *
7096
 * @param bApproxOK If TRUE statistics may be computed based on overviews
7097
 * or a subset of all tiles.
7098
 *
7099
 * @param pdfMin Location into which to load image minimum (may be NULL).
7100
 *
7101
 * @param pdfMax Location into which to load image maximum (may be NULL).-
7102
 *
7103
 * @param pdfMean Location into which to load image mean (may be NULL).
7104
 *
7105
 * @param pdfStdDev Location into which to load image standard deviation
7106
 * (may be NULL).
7107
 *
7108
 * @param pfnProgress a function to call to report progress, or NULL.
7109
 *
7110
 * @param pProgressData application data to pass to the progress function.
7111
 *
7112
 * @return CE_None on success, or CE_Failure if an error occurs or processing
7113
 * is terminated by the user.
7114
 */
7115
7116
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7117
                                         double *pdfMax, double *pdfMean,
7118
                                         double *pdfStdDev,
7119
                                         GDALProgressFunc pfnProgress,
7120
                                         void *pProgressData)
7121
7122
0
{
7123
0
    if (pfnProgress == nullptr)
7124
0
        pfnProgress = GDALDummyProgress;
7125
7126
    /* -------------------------------------------------------------------- */
7127
    /*      If we have overview bands, use them for statistics.             */
7128
    /* -------------------------------------------------------------------- */
7129
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7130
0
    {
7131
0
        GDALRasterBand *poBand =
7132
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7133
7134
0
        if (poBand != this)
7135
0
        {
7136
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
7137
0
                                                    pdfMean, pdfStdDev,
7138
0
                                                    pfnProgress, pProgressData);
7139
0
            if (eErr == CE_None)
7140
0
            {
7141
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7142
0
                {
7143
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7144
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7145
0
                }
7146
7147
                /* transfer metadata from overview band to this */
7148
0
                const char *pszPercentValid =
7149
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7150
7151
0
                if (pszPercentValid != nullptr)
7152
0
                {
7153
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
7154
0
                                    pszPercentValid);
7155
0
                }
7156
0
            }
7157
0
            return eErr;
7158
0
        }
7159
0
    }
7160
7161
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7162
0
    {
7163
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7164
0
        return CE_Failure;
7165
0
    }
7166
7167
    /* -------------------------------------------------------------------- */
7168
    /*      Read actual data and compute statistics.                        */
7169
    /* -------------------------------------------------------------------- */
7170
    // Using Welford algorithm:
7171
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7172
    // to compute standard deviation in a more numerically robust way than
7173
    // the difference of the sum of square values with the square of the sum.
7174
    // dfMean and dfM2 are updated at each sample.
7175
    // dfM2 is the sum of square of differences to the current mean.
7176
0
    double dfMin = std::numeric_limits<double>::infinity();
7177
0
    double dfMax = -std::numeric_limits<double>::infinity();
7178
0
    double dfMean = 0.0;
7179
0
    double dfM2 = 0.0;
7180
7181
0
    GDALRasterIOExtraArg sExtraArg;
7182
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7183
7184
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7185
0
    GDALRasterBand *poMaskBand = nullptr;
7186
0
    if (!sNoDataValues.bGotNoDataValue)
7187
0
    {
7188
0
        const int l_nMaskFlags = GetMaskFlags();
7189
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
7190
0
            GetColorInterpretation() != GCI_AlphaBand)
7191
0
        {
7192
0
            poMaskBand = GetMaskBand();
7193
0
        }
7194
0
    }
7195
7196
0
    bool bSignedByte = false;
7197
0
    if (eDataType == GDT_UInt8)
7198
0
    {
7199
0
        EnablePixelTypeSignedByteWarning(false);
7200
0
        const char *pszPixelType =
7201
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7202
0
        EnablePixelTypeSignedByteWarning(true);
7203
0
        bSignedByte =
7204
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7205
0
    }
7206
7207
0
    GUIntBig nSampleCount = 0;
7208
0
    GUIntBig nValidCount = 0;
7209
7210
0
    if (bApproxOK && HasArbitraryOverviews())
7211
0
    {
7212
        /* --------------------------------------------------------------------
7213
         */
7214
        /*      Figure out how much the image should be reduced to get an */
7215
        /*      approximate value. */
7216
        /* --------------------------------------------------------------------
7217
         */
7218
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7219
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7220
7221
0
        int nXReduced = nRasterXSize;
7222
0
        int nYReduced = nRasterYSize;
7223
0
        if (dfReduction > 1.0)
7224
0
        {
7225
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7226
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7227
7228
            // Catch the case of huge resizing ratios here
7229
0
            if (nXReduced == 0)
7230
0
                nXReduced = 1;
7231
0
            if (nYReduced == 0)
7232
0
                nYReduced = 1;
7233
0
        }
7234
7235
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
7236
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7237
7238
0
        const CPLErr eErr =
7239
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7240
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7241
0
        if (eErr != CE_None)
7242
0
        {
7243
0
            CPLFree(pData);
7244
0
            return eErr;
7245
0
        }
7246
7247
0
        GByte *pabyMaskData = nullptr;
7248
0
        if (poMaskBand)
7249
0
        {
7250
0
            pabyMaskData =
7251
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7252
0
            if (!pabyMaskData)
7253
0
            {
7254
0
                CPLFree(pData);
7255
0
                return CE_Failure;
7256
0
            }
7257
7258
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7259
0
                                     pabyMaskData, nXReduced, nYReduced,
7260
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
7261
0
            {
7262
0
                CPLFree(pData);
7263
0
                CPLFree(pabyMaskData);
7264
0
                return CE_Failure;
7265
0
            }
7266
0
        }
7267
7268
        /* this isn't the fastest way to do this, but is easier for now */
7269
0
        for (int iY = 0; iY < nYReduced; iY++)
7270
0
        {
7271
0
            for (int iX = 0; iX < nXReduced; iX++)
7272
0
            {
7273
0
                const int iOffset = iX + iY * nXReduced;
7274
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7275
0
                    continue;
7276
7277
0
                bool bValid = true;
7278
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7279
0
                                               iOffset, sNoDataValues, bValid);
7280
0
                if (!bValid)
7281
0
                    continue;
7282
7283
0
                dfMin = std::min(dfMin, dfValue);
7284
0
                dfMax = std::max(dfMax, dfValue);
7285
7286
0
                nValidCount++;
7287
0
                if (dfMin == dfMax)
7288
0
                {
7289
0
                    if (nValidCount == 1)
7290
0
                        dfMean = dfMin;
7291
0
                }
7292
0
                else
7293
0
                {
7294
0
                    const double dfDelta = dfValue - dfMean;
7295
0
                    dfMean += dfDelta / nValidCount;
7296
0
                    dfM2 += dfDelta * (dfValue - dfMean);
7297
0
                }
7298
0
            }
7299
0
        }
7300
7301
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7302
7303
0
        CPLFree(pData);
7304
0
        CPLFree(pabyMaskData);
7305
0
    }
7306
7307
0
    else  // No arbitrary overviews.
7308
0
    {
7309
0
        if (!InitBlockInfo())
7310
0
            return CE_Failure;
7311
7312
        /* --------------------------------------------------------------------
7313
         */
7314
        /*      Figure out the ratio of blocks we will read to get an */
7315
        /*      approximate value. */
7316
        /* --------------------------------------------------------------------
7317
         */
7318
0
        int nSampleRate = 1;
7319
0
        if (bApproxOK)
7320
0
        {
7321
0
            nSampleRate = static_cast<int>(std::max(
7322
0
                1.0,
7323
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7324
            // We want to avoid probing only the first column of blocks for
7325
            // a square shaped raster, because it is not unlikely that it may
7326
            // be padding only (#6378)
7327
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7328
0
                nSampleRate += 1;
7329
0
        }
7330
0
        if (nSampleRate == 1)
7331
0
            bApproxOK = false;
7332
7333
        // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7334
        // for each block, and possibly for the whole raster.
7335
0
        if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7336
0
                            eDataType == GDT_UInt16))
7337
0
        {
7338
            // We can do integer computation on the whole raster in the Byte case
7339
            // only if the number of pixels explored is lower than
7340
            // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7341
            // Should be 99.99999% of cases.
7342
            // For GUInt16, this limits to raster of 4 giga pixels
7343
7344
0
            const bool bIntegerStats =
7345
0
                ((eDataType == GDT_UInt8 &&
7346
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7347
0
                          nSampleRate <
7348
0
                      GUINTBIG_MAX / (255U * 255U) /
7349
0
                          (static_cast<GUInt64>(nBlockXSize) *
7350
0
                           static_cast<GUInt64>(nBlockYSize))) ||
7351
0
                 (eDataType == GDT_UInt16 &&
7352
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7353
0
                          nSampleRate <
7354
0
                      GUINTBIG_MAX / (65535U * 65535U) /
7355
0
                          (static_cast<GUInt64>(nBlockXSize) *
7356
0
                           static_cast<GUInt64>(nBlockYSize)))) &&
7357
                // Can be set to NO for easier debugging of the !bIntegerStats
7358
                // case which requires huge rasters to trigger
7359
0
                CPLTestBool(
7360
0
                    CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7361
7362
0
            const GUInt32 nMaxValueType =
7363
0
                (eDataType == GDT_UInt8) ? 255 : 65535;
7364
0
            GUInt32 nMin = nMaxValueType;
7365
0
            GUInt32 nMax = 0;
7366
0
            GUIntBig nSum = 0;
7367
0
            GUIntBig nSumSquare = 0;
7368
            // If no valid nodata, map to invalid value (256 for Byte)
7369
0
            const GUInt32 nNoDataValue =
7370
0
                (sNoDataValues.bGotNoDataValue &&
7371
0
                 sNoDataValues.dfNoDataValue >= 0 &&
7372
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
7373
0
                 fabs(sNoDataValues.dfNoDataValue -
7374
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7375
0
                                           1e-10)) < 1e-10)
7376
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7377
0
                    : nMaxValueType + 1;
7378
7379
0
            int nChunkXSize = nBlockXSize;
7380
0
            int nChunkYSize = nBlockYSize;
7381
0
            int nChunksPerRow = nBlocksPerRow;
7382
0
            int nChunksPerCol = nBlocksPerColumn;
7383
7384
0
            int nThreads = 1;
7385
0
            if (nChunkYSize > 1)
7386
0
            {
7387
0
                nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7388
0
                                             /* bDefaultToAllCPUs = */ false);
7389
0
            }
7390
7391
0
            int nNewChunkXSize = nChunkXSize;
7392
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
7393
0
            if (!bApproxOK && nThreads > 1 &&
7394
0
                MayMultiBlockReadingBeMultiThreaded())
7395
0
            {
7396
0
                const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7397
0
                const size_t nChunkPixels =
7398
0
                    static_cast<size_t>(nChunkXSize) * nChunkYSize;
7399
0
                if (nRAMAmount > 0 &&
7400
0
                    nChunkPixels <=
7401
0
                        std::numeric_limits<size_t>::max() / nDTSize)
7402
0
                {
7403
0
                    const size_t nBlockSize = nDTSize * nChunkPixels;
7404
0
                    const int64_t nBlockCount = nRAMAmount / nBlockSize;
7405
0
                    if (nBlockCount >= 2)
7406
0
                    {
7407
0
                        nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7408
0
                            nChunkXSize * std::min<int64_t>(
7409
0
                                              nBlockCount,
7410
0
                                              (std::numeric_limits<int>::max() -
7411
0
                                               ALIGNMENT_AVX2_OPTIM) /
7412
0
                                                  nChunkPixels),
7413
0
                            nRasterXSize));
7414
7415
0
                        CPLAssert(nChunkXSize <
7416
0
                                  std::numeric_limits<int>::max() /
7417
0
                                      nChunkYSize);
7418
0
                    }
7419
0
                }
7420
0
            }
7421
7422
0
            std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
7423
0
            GByte *pabyTemp = nullptr;
7424
0
            if (nNewChunkXSize != nBlockXSize)
7425
0
            {
7426
0
                pabyTempUnaligned.reset(static_cast<GByte *>(
7427
0
                    VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
7428
0
                              ALIGNMENT_AVX2_OPTIM)));
7429
0
                if (pabyTempUnaligned)
7430
0
                {
7431
0
                    pabyTemp = reinterpret_cast<GByte *>(
7432
0
                        reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
7433
0
                        (ALIGNMENT_AVX2_OPTIM -
7434
0
                         (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
7435
0
                          ALIGNMENT_AVX2_OPTIM)));
7436
0
                    nChunkXSize = nNewChunkXSize;
7437
0
                    nChunksPerRow =
7438
0
                        cpl::div_round_up(nRasterXSize, nChunkXSize);
7439
0
                }
7440
0
            }
7441
7442
0
            for (GIntBig iSampleBlock = 0;
7443
0
                 iSampleBlock <
7444
0
                 static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7445
0
                 iSampleBlock += nSampleRate)
7446
0
            {
7447
0
                const int iYBlock =
7448
0
                    static_cast<int>(iSampleBlock / nChunksPerRow);
7449
0
                const int iXBlock =
7450
0
                    static_cast<int>(iSampleBlock % nChunksPerRow);
7451
7452
0
                const int nXCheck =
7453
0
                    std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7454
0
                const int nYCheck =
7455
0
                    std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7456
7457
0
                GDALRasterBlock *poBlock = nullptr;
7458
0
                if (pabyTemp)
7459
0
                {
7460
0
                    if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7461
0
                                 iYBlock * nChunkYSize, nXCheck, nYCheck,
7462
0
                                 pabyTemp, nXCheck, nYCheck, eDataType, 0,
7463
0
                                 static_cast<GSpacing>(nChunkXSize * nDTSize),
7464
0
                                 nullptr) != CE_None)
7465
0
                    {
7466
0
                        return CE_Failure;
7467
0
                    }
7468
0
                }
7469
0
                else
7470
0
                {
7471
0
                    poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7472
0
                    if (poBlock == nullptr)
7473
0
                    {
7474
0
                        return CE_Failure;
7475
0
                    }
7476
0
                }
7477
7478
0
                const void *const pData =
7479
0
                    poBlock ? poBlock->GetDataRef() : pabyTemp;
7480
7481
0
                GUIntBig nBlockSum = 0;
7482
0
                GUIntBig nBlockSumSquare = 0;
7483
0
                GUIntBig nBlockSampleCount = 0;
7484
0
                GUIntBig nBlockValidCount = 0;
7485
0
                GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7486
0
                GUIntBig &nBlockSumSquareRef =
7487
0
                    bIntegerStats ? nSumSquare : nBlockSumSquare;
7488
0
                GUIntBig &nBlockSampleCountRef =
7489
0
                    bIntegerStats ? nSampleCount : nBlockSampleCount;
7490
0
                GUIntBig &nBlockValidCountRef =
7491
0
                    bIntegerStats ? nValidCount : nBlockValidCount;
7492
7493
0
                if (eDataType == GDT_UInt8)
7494
0
                {
7495
0
                    ComputeStatisticsInternal<
7496
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
7497
0
                        f(nXCheck, nChunkXSize, nYCheck,
7498
0
                          static_cast<const GByte *>(pData),
7499
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7500
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7501
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7502
0
                }
7503
0
                else
7504
0
                {
7505
0
                    ComputeStatisticsInternal<
7506
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7507
0
                        f(nXCheck, nChunkXSize, nYCheck,
7508
0
                          static_cast<const GUInt16 *>(pData),
7509
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7510
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7511
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7512
0
                }
7513
7514
0
                if (poBlock)
7515
0
                    poBlock->DropLock();
7516
7517
0
                if (!bIntegerStats)
7518
0
                {
7519
0
                    nSampleCount += nBlockSampleCount;
7520
0
                    if (nBlockValidCount)
7521
0
                    {
7522
                        // Update the global mean and M2 (the difference of the
7523
                        // square to the mean) from the values of the block
7524
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7525
0
                        const double dfBlockValidCount =
7526
0
                            static_cast<double>(nBlockValidCount);
7527
0
                        const double dfBlockMean =
7528
0
                            static_cast<double>(nBlockSum) / dfBlockValidCount;
7529
0
                        const double dfBlockM2 =
7530
0
                            static_cast<double>(
7531
0
                                GDALUInt128::Mul(nBlockSumSquare,
7532
0
                                                 nBlockValidCount) -
7533
0
                                GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7534
0
                            dfBlockValidCount;
7535
0
                        const double dfDelta = dfBlockMean - dfMean;
7536
0
                        const auto nNewValidCount =
7537
0
                            nValidCount + nBlockValidCount;
7538
0
                        const double dfNewValidCount =
7539
0
                            static_cast<double>(nNewValidCount);
7540
0
                        dfMean +=
7541
0
                            dfDelta * (dfBlockValidCount / dfNewValidCount);
7542
0
                        dfM2 +=
7543
0
                            dfBlockM2 + dfDelta * dfDelta *
7544
0
                                            static_cast<double>(nValidCount) *
7545
0
                                            dfBlockValidCount / dfNewValidCount;
7546
0
                        nValidCount = nNewValidCount;
7547
0
                    }
7548
0
                }
7549
7550
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
7551
0
                                     (static_cast<double>(nChunksPerRow) *
7552
0
                                      nChunksPerCol),
7553
0
                                 "Compute Statistics", pProgressData))
7554
0
                {
7555
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
7556
0
                                "User terminated");
7557
0
                    return CE_Failure;
7558
0
                }
7559
0
            }
7560
7561
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7562
0
            {
7563
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7564
0
                return CE_Failure;
7565
0
            }
7566
7567
0
            double dfStdDev = 0;
7568
0
            if (bIntegerStats)
7569
0
            {
7570
0
                if (nValidCount)
7571
0
                    dfMean = static_cast<double>(nSum) / nValidCount;
7572
7573
                // To avoid potential precision issues when doing the difference,
7574
                // we need to do that computation on 128 bit rather than casting
7575
                // to double
7576
0
                const GDALUInt128 nTmpForStdDev(
7577
0
                    GDALUInt128::Mul(nSumSquare, nValidCount) -
7578
0
                    GDALUInt128::Mul(nSum, nSum));
7579
0
                dfStdDev =
7580
0
                    nValidCount > 0
7581
0
                        ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7582
0
                        : 0.0;
7583
0
            }
7584
0
            else if (nValidCount > 0)
7585
0
            {
7586
0
                dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7587
0
            }
7588
7589
            /// Save computed information
7590
0
            if (nValidCount > 0)
7591
0
            {
7592
0
                if (bApproxOK)
7593
0
                {
7594
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7595
0
                }
7596
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7597
0
                {
7598
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7599
0
                }
7600
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
7601
0
            }
7602
7603
0
            SetValidPercent(nSampleCount, nValidCount);
7604
7605
            /* --------------------------------------------------------------------
7606
             */
7607
            /*      Record results. */
7608
            /* --------------------------------------------------------------------
7609
             */
7610
0
            if (pdfMin != nullptr)
7611
0
                *pdfMin = nValidCount ? nMin : 0;
7612
0
            if (pdfMax != nullptr)
7613
0
                *pdfMax = nValidCount ? nMax : 0;
7614
7615
0
            if (pdfMean != nullptr)
7616
0
                *pdfMean = dfMean;
7617
7618
0
            if (pdfStdDev != nullptr)
7619
0
                *pdfStdDev = dfStdDev;
7620
7621
0
            if (nValidCount > 0)
7622
0
                return CE_None;
7623
7624
0
            ReportError(CE_Failure, CPLE_AppDefined,
7625
0
                        "Failed to compute statistics, no valid pixels found "
7626
0
                        "in sampling.");
7627
0
            return CE_Failure;
7628
0
        }
7629
7630
0
        GByte *pabyMaskData = nullptr;
7631
0
        if (poMaskBand)
7632
0
        {
7633
0
            pabyMaskData = static_cast<GByte *>(
7634
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7635
0
            if (!pabyMaskData)
7636
0
            {
7637
0
                return CE_Failure;
7638
0
            }
7639
0
        }
7640
7641
0
        float fMin = std::numeric_limits<float>::infinity();
7642
0
        float fMax = -std::numeric_limits<float>::infinity();
7643
0
        bool bFloat32Optim =
7644
0
            (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7645
0
             eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7646
0
            !pabyMaskData &&
7647
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7648
0
            CPLTestBool(
7649
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7650
0
        std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7651
7652
0
        int nChunkXSize = nBlockXSize;
7653
0
        int nChunkYSize = nBlockYSize;
7654
0
        int nChunksPerRow = nBlocksPerRow;
7655
0
        int nChunksPerCol = nBlocksPerColumn;
7656
7657
0
#define nBlockXSize use_nChunkXSize_instead
7658
0
#define nBlockYSize use_nChunkYSize_instead
7659
0
#define nBlocksPerRow use_nChunksPerRow_instead
7660
0
#define nBlocksPerColumn use_nChunksPerCol_instead
7661
7662
0
        int nThreads = 1;
7663
0
        CPLWorkerThreadPool *psThreadPool = nullptr;
7664
0
        if (bFloat32Optim)
7665
0
        {
7666
0
            if (nChunkYSize > 1)
7667
0
            {
7668
0
                nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7669
0
                                             /* bDefaultToAllCPUs = */ false);
7670
0
            }
7671
7672
0
            int nNewChunkXSize = nChunkXSize;
7673
0
            if (!bApproxOK && nThreads > 1 &&
7674
0
                MayMultiBlockReadingBeMultiThreaded())
7675
0
            {
7676
0
                const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7677
0
                const size_t nChunkPixels =
7678
0
                    static_cast<size_t>(nChunkXSize) * nChunkYSize;
7679
0
                if (nRAMAmount > 0 &&
7680
0
                    nChunkPixels <=
7681
0
                        std::numeric_limits<size_t>::max() / sizeof(float))
7682
0
                {
7683
0
                    const size_t nBlockSizeAsFloat32 =
7684
0
                        sizeof(float) * nChunkPixels;
7685
0
                    const int64_t nBlockCount =
7686
0
                        nRAMAmount / nBlockSizeAsFloat32;
7687
0
                    if (nBlockCount >= 2)
7688
0
                    {
7689
0
                        nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7690
0
                            nChunkXSize * std::min<int64_t>(
7691
0
                                              nBlockCount,
7692
0
                                              std::numeric_limits<int>::max() /
7693
0
                                                  nChunkPixels),
7694
0
                            nRasterXSize));
7695
7696
0
                        CPLAssert(nChunkXSize <
7697
0
                                  std::numeric_limits<int>::max() /
7698
0
                                      nChunkYSize);
7699
0
                    }
7700
0
                }
7701
0
            }
7702
0
            if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7703
0
            {
7704
0
                pafTemp.reset(static_cast<float *>(
7705
0
                    VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7706
0
                bFloat32Optim = pafTemp != nullptr;
7707
0
                if (bFloat32Optim)
7708
0
                {
7709
0
                    nChunkXSize = nNewChunkXSize;
7710
0
                    nChunksPerRow =
7711
0
                        cpl::div_round_up(nRasterXSize, nChunkXSize);
7712
0
                }
7713
0
            }
7714
0
            CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7715
0
                     nChunkXSize, nChunkYSize);
7716
0
        }
7717
7718
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7719
0
        const bool bFloat64Optim =
7720
0
            eDataType == GDT_Float64 && !pabyMaskData &&
7721
0
            nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7722
0
            CPLTestBool(
7723
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7724
0
#endif
7725
7726
0
        std::vector<StatisticsTaskFloat32> tasksFloat32;
7727
7728
0
        for (GIntBig iSampleBlock = 0;
7729
0
             iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7730
0
             iSampleBlock += nSampleRate)
7731
0
        {
7732
0
            const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7733
0
            const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7734
7735
0
            const int nXCheck =
7736
0
                std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7737
0
            const int nYCheck =
7738
0
                std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7739
7740
0
            if (poMaskBand &&
7741
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7742
0
                                     iYBlock * nChunkYSize, nXCheck, nYCheck,
7743
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7744
0
                                     0, nChunkXSize, nullptr) != CE_None)
7745
0
            {
7746
0
                CPLFree(pabyMaskData);
7747
0
                return CE_Failure;
7748
0
            }
7749
7750
0
            GDALRasterBlock *poBlock = nullptr;
7751
0
            if (pafTemp)
7752
0
            {
7753
0
                if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7754
0
                             iYBlock * nChunkYSize, nXCheck, nYCheck,
7755
0
                             pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7756
0
                             static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7757
0
                             nullptr) != CE_None)
7758
0
                {
7759
0
                    CPLFree(pabyMaskData);
7760
0
                    return CE_Failure;
7761
0
                }
7762
0
            }
7763
0
            else
7764
0
            {
7765
0
                poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7766
0
                if (poBlock == nullptr)
7767
0
                {
7768
0
                    CPLFree(pabyMaskData);
7769
0
                    return CE_Failure;
7770
0
                }
7771
0
            }
7772
7773
0
            const void *const pData =
7774
0
                poBlock ? poBlock->GetDataRef() : pafTemp.get();
7775
7776
0
            if (bFloat32Optim)
7777
0
            {
7778
0
                const float *const pafSrcData =
7779
0
                    static_cast<const float *>(pData);
7780
7781
0
                const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7782
0
                                        !std::isnan(sNoDataValues.fNoDataValue);
7783
0
                const int nTasks = std::min(nYCheck, nThreads);
7784
0
                const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7785
0
                tasksFloat32.clear();
7786
0
                for (int i = 0; i < nTasks; ++i)
7787
0
                {
7788
0
                    StatisticsTaskFloat32 task;
7789
0
                    task.eDataType = eDataType;
7790
0
                    task.bHasNoData = bHasNoData;
7791
0
                    task.psNoDataValues = &sNoDataValues;
7792
0
                    task.nChunkXSize = nChunkXSize;
7793
0
                    task.fMin = fMin;
7794
0
                    task.fMax = fMax;
7795
0
                    task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7796
0
                                                       nRowsPerTask *
7797
0
                                                       nChunkXSize;
7798
0
                    task.nXCheck = nXCheck;
7799
0
                    task.nYCheck =
7800
0
                        std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7801
0
                    tasksFloat32.emplace_back(std::move(task));
7802
0
                }
7803
0
                if (psThreadPool)
7804
0
                {
7805
0
                    auto poJobQueue = psThreadPool->CreateJobQueue();
7806
0
                    for (auto &task : tasksFloat32)
7807
0
                    {
7808
0
                        poJobQueue->SubmitJob([&task]() { task.Perform(); });
7809
0
                    }
7810
0
                    poJobQueue->WaitCompletion();
7811
0
                }
7812
0
                else
7813
0
                {
7814
0
                    tasksFloat32[0].Perform();
7815
0
                }
7816
7817
0
                for (const auto &task : tasksFloat32)
7818
0
                {
7819
0
                    if (task.dfBlockValidCount > 0)
7820
0
                    {
7821
0
                        fMin = std::min(fMin, task.fMin);
7822
0
                        fMax = std::max(fMax, task.fMax);
7823
7824
                        // Update the global mean and M2 (the difference of the
7825
                        // square to the mean) from the values of the block
7826
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7827
0
                        const auto nNewValidCount =
7828
0
                            nValidCount +
7829
0
                            static_cast<int>(task.dfBlockValidCount);
7830
0
                        dfM2 += task.dfBlockM2;
7831
0
                        if (task.dfBlockMean != dfMean)
7832
0
                        {
7833
0
                            if (nValidCount == 0)
7834
0
                            {
7835
0
                                dfMean = task.dfBlockMean;
7836
0
                            }
7837
0
                            else
7838
0
                            {
7839
0
                                const double dfDelta =
7840
0
                                    task.dfBlockMean - dfMean;
7841
0
                                const double dfNewValidCount =
7842
0
                                    static_cast<double>(nNewValidCount);
7843
0
                                dfMean += dfDelta * (task.dfBlockValidCount /
7844
0
                                                     dfNewValidCount);
7845
0
                                dfM2 += dfDelta * dfDelta *
7846
0
                                        static_cast<double>(nValidCount) *
7847
0
                                        task.dfBlockValidCount /
7848
0
                                        dfNewValidCount;
7849
0
                            }
7850
0
                        }
7851
0
                        nValidCount = nNewValidCount;
7852
0
                    }
7853
0
                }
7854
0
            }
7855
7856
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7857
0
            else if (bFloat64Optim)
7858
0
            {
7859
0
                const bool bHasNoData =
7860
0
                    sNoDataValues.bGotNoDataValue &&
7861
0
                    !std::isnan(sNoDataValues.dfNoDataValue);
7862
0
                double dfBlockMean = 0;
7863
0
                double dfBlockM2 = 0;
7864
0
                double dfBlockValidCount = 0;
7865
0
                for (int iY = 0; iY < nYCheck; iY++)
7866
0
                {
7867
0
                    const int iOffset = iY * nChunkXSize;
7868
0
                    if (dfBlockValidCount != 0 && dfMin != dfMax)
7869
0
                    {
7870
0
                        int iX = 0;
7871
0
                        if (bHasNoData)
7872
0
                        {
7873
0
                            iX = ComputeStatisticsFloat64_SSE2<
7874
0
                                /* bCheckMinEqMax = */ false,
7875
0
                                /* bHasNoData = */ true>(
7876
0
                                static_cast<const double *>(pData) + iOffset,
7877
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7878
0
                                dfMax, dfBlockMean, dfBlockM2,
7879
0
                                dfBlockValidCount);
7880
0
                        }
7881
0
                        else
7882
0
                        {
7883
0
                            iX = ComputeStatisticsFloat64_SSE2<
7884
0
                                /* bCheckMinEqMax = */ false,
7885
0
                                /* bHasNoData = */ false>(
7886
0
                                static_cast<const double *>(pData) + iOffset,
7887
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7888
0
                                dfMax, dfBlockMean, dfBlockM2,
7889
0
                                dfBlockValidCount);
7890
0
                        }
7891
0
                        for (; iX < nXCheck; iX++)
7892
0
                        {
7893
0
                            const double dfValue = static_cast<const double *>(
7894
0
                                pData)[iOffset + iX];
7895
0
                            if (std::isnan(dfValue) ||
7896
0
                                (bHasNoData &&
7897
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7898
0
                                continue;
7899
0
                            dfMin = std::min(dfMin, dfValue);
7900
0
                            dfMax = std::max(dfMax, dfValue);
7901
0
                            dfBlockValidCount += 1.0;
7902
0
                            const double dfDelta = dfValue - dfBlockMean;
7903
0
                            dfBlockMean += dfDelta / dfBlockValidCount;
7904
0
                            dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7905
0
                        }
7906
0
                    }
7907
0
                    else
7908
0
                    {
7909
0
                        int iX = 0;
7910
0
                        if (dfBlockValidCount == 0)
7911
0
                        {
7912
0
                            for (; iX < nXCheck; iX++)
7913
0
                            {
7914
0
                                const double dfValue =
7915
0
                                    static_cast<const double *>(
7916
0
                                        pData)[iOffset + iX];
7917
0
                                if (std::isnan(dfValue) ||
7918
0
                                    (bHasNoData &&
7919
0
                                     dfValue == sNoDataValues.dfNoDataValue))
7920
0
                                    continue;
7921
0
                                dfMin = std::min(dfMin, dfValue);
7922
0
                                dfMax = std::max(dfMax, dfValue);
7923
0
                                dfBlockValidCount = 1;
7924
0
                                dfBlockMean = dfValue;
7925
0
                                iX++;
7926
0
                                break;
7927
0
                            }
7928
0
                        }
7929
0
                        if (bHasNoData)
7930
0
                        {
7931
0
                            iX = ComputeStatisticsFloat64_SSE2<
7932
0
                                /* bCheckMinEqMax = */ true,
7933
0
                                /* bHasNoData = */ true>(
7934
0
                                static_cast<const double *>(pData) + iOffset,
7935
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7936
0
                                dfMax, dfBlockMean, dfBlockM2,
7937
0
                                dfBlockValidCount);
7938
0
                        }
7939
0
                        else
7940
0
                        {
7941
0
                            iX = ComputeStatisticsFloat64_SSE2<
7942
0
                                /* bCheckMinEqMax = */ true,
7943
0
                                /* bHasNoData = */ false>(
7944
0
                                static_cast<const double *>(pData) + iOffset,
7945
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7946
0
                                dfMax, dfBlockMean, dfBlockM2,
7947
0
                                dfBlockValidCount);
7948
0
                        }
7949
0
                        for (; iX < nXCheck; iX++)
7950
0
                        {
7951
0
                            const double dfValue = static_cast<const double *>(
7952
0
                                pData)[iOffset + iX];
7953
0
                            if (std::isnan(dfValue) ||
7954
0
                                (bHasNoData &&
7955
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7956
0
                                continue;
7957
0
                            dfMin = std::min(dfMin, dfValue);
7958
0
                            dfMax = std::max(dfMax, dfValue);
7959
0
                            dfBlockValidCount += 1.0;
7960
0
                            if (dfMin != dfMax)
7961
0
                            {
7962
0
                                const double dfDelta = dfValue - dfBlockMean;
7963
0
                                dfBlockMean += dfDelta / dfBlockValidCount;
7964
0
                                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7965
0
                            }
7966
0
                        }
7967
0
                    }
7968
0
                }
7969
7970
0
                if (dfBlockValidCount > 0)
7971
0
                {
7972
                    // Update the global mean and M2 (the difference of the
7973
                    // square to the mean) from the values of the block
7974
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7975
0
                    const auto nNewValidCount =
7976
0
                        nValidCount + static_cast<int>(dfBlockValidCount);
7977
0
                    dfM2 += dfBlockM2;
7978
0
                    if (dfBlockMean != dfMean)
7979
0
                    {
7980
0
                        if (nValidCount == 0)
7981
0
                        {
7982
0
                            dfMean = dfBlockMean;
7983
0
                        }
7984
0
                        else
7985
0
                        {
7986
0
                            const double dfDelta = dfBlockMean - dfMean;
7987
0
                            const double dfNewValidCount =
7988
0
                                static_cast<double>(nNewValidCount);
7989
0
                            dfMean +=
7990
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
7991
0
                            dfM2 += dfDelta * dfDelta *
7992
0
                                    static_cast<double>(nValidCount) *
7993
0
                                    dfBlockValidCount / dfNewValidCount;
7994
0
                        }
7995
0
                    }
7996
0
                    nValidCount = nNewValidCount;
7997
0
                }
7998
0
            }
7999
0
#endif  // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
8000
8001
0
            else
8002
0
            {
8003
                // This isn't the fastest way to do this, but is easier for now.
8004
0
                for (int iY = 0; iY < nYCheck; iY++)
8005
0
                {
8006
0
                    if (nValidCount && dfMin != dfMax)
8007
0
                    {
8008
0
                        for (int iX = 0; iX < nXCheck; iX++)
8009
0
                        {
8010
0
                            const GPtrDiff_t iOffset =
8011
0
                                iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8012
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8013
0
                                continue;
8014
8015
0
                            bool bValid = true;
8016
0
                            double dfValue =
8017
0
                                GetPixelValue(eDataType, bSignedByte, pData,
8018
0
                                              iOffset, sNoDataValues, bValid);
8019
8020
0
                            if (!bValid)
8021
0
                                continue;
8022
8023
0
                            dfMin = std::min(dfMin, dfValue);
8024
0
                            dfMax = std::max(dfMax, dfValue);
8025
8026
0
                            nValidCount++;
8027
0
                            const double dfDelta = dfValue - dfMean;
8028
0
                            dfMean += dfDelta / nValidCount;
8029
0
                            dfM2 += dfDelta * (dfValue - dfMean);
8030
0
                        }
8031
0
                    }
8032
0
                    else
8033
0
                    {
8034
0
                        int iX = 0;
8035
0
                        if (nValidCount == 0)
8036
0
                        {
8037
0
                            for (; iX < nXCheck; iX++)
8038
0
                            {
8039
0
                                const GPtrDiff_t iOffset =
8040
0
                                    iX +
8041
0
                                    static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8042
0
                                if (pabyMaskData && pabyMaskData[iOffset] == 0)
8043
0
                                    continue;
8044
8045
0
                                bool bValid = true;
8046
0
                                double dfValue = GetPixelValue(
8047
0
                                    eDataType, bSignedByte, pData, iOffset,
8048
0
                                    sNoDataValues, bValid);
8049
8050
0
                                if (!bValid)
8051
0
                                    continue;
8052
8053
0
                                dfMin = dfValue;
8054
0
                                dfMax = dfValue;
8055
0
                                dfMean = dfValue;
8056
0
                                nValidCount = 1;
8057
0
                                iX++;
8058
0
                                break;
8059
0
                            }
8060
0
                        }
8061
0
                        for (; iX < nXCheck; iX++)
8062
0
                        {
8063
0
                            const GPtrDiff_t iOffset =
8064
0
                                iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8065
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8066
0
                                continue;
8067
8068
0
                            bool bValid = true;
8069
0
                            double dfValue =
8070
0
                                GetPixelValue(eDataType, bSignedByte, pData,
8071
0
                                              iOffset, sNoDataValues, bValid);
8072
8073
0
                            if (!bValid)
8074
0
                                continue;
8075
8076
0
                            dfMin = std::min(dfMin, dfValue);
8077
0
                            dfMax = std::max(dfMax, dfValue);
8078
8079
0
                            nValidCount++;
8080
0
                            if (dfMin != dfMax)
8081
0
                            {
8082
0
                                const double dfDelta = dfValue - dfMean;
8083
0
                                dfMean += dfDelta / nValidCount;
8084
0
                                dfM2 += dfDelta * (dfValue - dfMean);
8085
0
                            }
8086
0
                        }
8087
0
                    }
8088
0
                }
8089
0
            }
8090
8091
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8092
8093
0
            if (poBlock)
8094
0
                poBlock->DropLock();
8095
8096
0
            if (!pfnProgress(
8097
0
                    static_cast<double>(iSampleBlock) /
8098
0
                        (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8099
0
                    "Compute Statistics", pProgressData))
8100
0
            {
8101
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8102
0
                CPLFree(pabyMaskData);
8103
0
                return CE_Failure;
8104
0
            }
8105
0
        }
8106
8107
0
#undef nBlockXSize
8108
0
#undef nBlockYSize
8109
0
#undef nBlocksPerRow
8110
0
#undef nBlocksPerColumn
8111
8112
0
        if (bFloat32Optim)
8113
0
        {
8114
0
            dfMin = static_cast<double>(fMin);
8115
0
            dfMax = static_cast<double>(fMax);
8116
0
        }
8117
0
        CPLFree(pabyMaskData);
8118
0
    }
8119
8120
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8121
0
    {
8122
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8123
0
        return CE_Failure;
8124
0
    }
8125
8126
    /* -------------------------------------------------------------------- */
8127
    /*      Save computed information.                                      */
8128
    /* -------------------------------------------------------------------- */
8129
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8130
8131
0
    if (nValidCount > 0)
8132
0
    {
8133
0
        if (bApproxOK)
8134
0
        {
8135
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8136
0
        }
8137
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8138
0
        {
8139
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8140
0
        }
8141
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8142
0
    }
8143
0
    else
8144
0
    {
8145
0
        dfMin = 0.0;
8146
0
        dfMax = 0.0;
8147
0
    }
8148
8149
0
    SetValidPercent(nSampleCount, nValidCount);
8150
8151
    /* -------------------------------------------------------------------- */
8152
    /*      Record results.                                                 */
8153
    /* -------------------------------------------------------------------- */
8154
0
    if (pdfMin != nullptr)
8155
0
        *pdfMin = dfMin;
8156
0
    if (pdfMax != nullptr)
8157
0
        *pdfMax = dfMax;
8158
8159
0
    if (pdfMean != nullptr)
8160
0
        *pdfMean = dfMean;
8161
8162
0
    if (pdfStdDev != nullptr)
8163
0
        *pdfStdDev = dfStdDev;
8164
8165
0
    if (nValidCount > 0)
8166
0
        return CE_None;
8167
8168
0
    ReportError(
8169
0
        CE_Failure, CPLE_AppDefined,
8170
0
        "Failed to compute statistics, no valid pixels found in sampling.");
8171
0
    return CE_Failure;
8172
0
}
8173
8174
/************************************************************************/
8175
/*                    GDALComputeRasterStatistics()                     */
8176
/************************************************************************/
8177
8178
/**
8179
 * \brief Compute image statistics.
8180
 *
8181
 * @see GDALRasterBand::ComputeStatistics()
8182
 */
8183
8184
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8185
                                               int bApproxOK, double *pdfMin,
8186
                                               double *pdfMax, double *pdfMean,
8187
                                               double *pdfStdDev,
8188
                                               GDALProgressFunc pfnProgress,
8189
                                               void *pProgressData)
8190
8191
0
{
8192
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8193
8194
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8195
8196
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8197
0
                                     pdfStdDev, pfnProgress, pProgressData);
8198
0
}
8199
8200
/************************************************************************/
8201
/*                           SetStatistics()                            */
8202
/************************************************************************/
8203
8204
/**
8205
 * \brief Set statistics on band.
8206
 *
8207
 * This method can be used to store min/max/mean/standard deviation
8208
 * statistics on a raster band.
8209
 *
8210
 * The default implementation stores them as metadata, and will only work
8211
 * on formats that can save arbitrary metadata.  This method cannot detect
8212
 * whether metadata will be properly saved and so may return CE_None even
8213
 * if the statistics will never be saved.
8214
 *
8215
 * This method is the same as the C function GDALSetRasterStatistics().
8216
 *
8217
 * @param dfMin minimum pixel value.
8218
 *
8219
 * @param dfMax maximum pixel value.
8220
 *
8221
 * @param dfMean mean (average) of all pixel values.
8222
 *
8223
 * @param dfStdDev Standard deviation of all pixel values.
8224
 *
8225
 * @return CE_None on success or CE_Failure on failure.
8226
 */
8227
8228
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8229
                                     double dfStdDev)
8230
8231
0
{
8232
0
    char szValue[128] = {0};
8233
8234
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8235
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
8236
8237
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8238
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8239
8240
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8241
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
8242
8243
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8244
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
8245
8246
0
    return CE_None;
8247
0
}
8248
8249
/************************************************************************/
8250
/*                      GDALSetRasterStatistics()                       */
8251
/************************************************************************/
8252
8253
/**
8254
 * \brief Set statistics on band.
8255
 *
8256
 * @see GDALRasterBand::SetStatistics()
8257
 */
8258
8259
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8260
                                           double dfMax, double dfMean,
8261
                                           double dfStdDev)
8262
8263
0
{
8264
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8265
8266
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8267
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8268
0
}
8269
8270
/************************************************************************/
8271
/*                        ComputeRasterMinMax()                         */
8272
/************************************************************************/
8273
8274
template <class T, bool HAS_NODATA>
8275
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8276
                          T *pMax)
8277
0
{
8278
0
    T min0 = *pMin;
8279
0
    T max0 = *pMax;
8280
0
    T min1 = *pMin;
8281
0
    T max1 = *pMax;
8282
0
    size_t i;
8283
0
    for (i = 0; i + 1 < nElts; i += 2)
8284
0
    {
8285
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
8286
0
        {
8287
0
            min0 = std::min(min0, buffer[i]);
8288
0
            max0 = std::max(max0, buffer[i]);
8289
0
        }
8290
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8291
0
        {
8292
0
            min1 = std::min(min1, buffer[i + 1]);
8293
0
            max1 = std::max(max1, buffer[i + 1]);
8294
0
        }
8295
0
    }
8296
0
    T min = std::min(min0, min1);
8297
0
    T max = std::max(max0, max1);
8298
0
    if (i < nElts)
8299
0
    {
8300
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
8301
0
        {
8302
0
            min = std::min(min, buffer[i]);
8303
0
            max = std::max(max, buffer[i]);
8304
0
        }
8305
0
    }
8306
0
    *pMin = min;
8307
0
    *pMax = max;
8308
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMax<short, true>(short const*, unsigned long, short, short*, short*)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMax<short, false>(short const*, unsigned long, short, short*, short*)
8309
8310
template <GDALDataType eDataType, bool bSignedByte>
8311
static void
8312
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8313
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8314
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
8315
0
{
8316
0
    double dfLocalMin = dfMin;
8317
0
    double dfLocalMax = dfMax;
8318
8319
0
    for (int iY = 0; iY < nYCheck; iY++)
8320
0
    {
8321
0
        for (int iX = 0; iX < nXCheck; iX++)
8322
0
        {
8323
0
            const GPtrDiff_t iOffset =
8324
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8325
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8326
0
                continue;
8327
0
            bool bValid = true;
8328
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8329
0
                                           iOffset, sNoDataValues, bValid);
8330
0
            if (!bValid)
8331
0
                continue;
8332
8333
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
8334
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
8335
0
        }
8336
0
    }
8337
8338
0
    dfMin = dfLocalMin;
8339
0
    dfMax = dfLocalMax;
8340
0
}
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)1, true>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)1, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)14, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)2, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)3, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)4, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)5, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)12, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)13, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)15, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)6, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)7, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)8, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)9, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)16, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)10, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:void ComputeMinMaxGeneric<(GDALDataType)11, false>(void const*, int, int, int, GDALNoDataValues const&, unsigned char const*, double&, double&)
8341
8342
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8343
                                 bool bSignedByte, int nXCheck, int nYCheck,
8344
                                 int nBlockXSize,
8345
                                 const GDALNoDataValues &sNoDataValues,
8346
                                 const GByte *pabyMaskData, double &dfMin,
8347
                                 double &dfMax)
8348
0
{
8349
0
    switch (eDataType)
8350
0
    {
8351
0
        case GDT_Unknown:
8352
0
            CPLAssert(false);
8353
0
            break;
8354
0
        case GDT_UInt8:
8355
0
            if (bSignedByte)
8356
0
            {
8357
0
                ComputeMinMaxGeneric<GDT_UInt8, true>(
8358
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8359
0
                    pabyMaskData, dfMin, dfMax);
8360
0
            }
8361
0
            else
8362
0
            {
8363
0
                ComputeMinMaxGeneric<GDT_UInt8, false>(
8364
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8365
0
                    pabyMaskData, dfMin, dfMax);
8366
0
            }
8367
0
            break;
8368
0
        case GDT_Int8:
8369
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8370
0
                                                  nBlockXSize, sNoDataValues,
8371
0
                                                  pabyMaskData, dfMin, dfMax);
8372
0
            break;
8373
0
        case GDT_UInt16:
8374
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8375
0
                                                    nBlockXSize, sNoDataValues,
8376
0
                                                    pabyMaskData, dfMin, dfMax);
8377
0
            break;
8378
0
        case GDT_Int16:
8379
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8380
0
                                                   nBlockXSize, sNoDataValues,
8381
0
                                                   pabyMaskData, dfMin, dfMax);
8382
0
            break;
8383
0
        case GDT_UInt32:
8384
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8385
0
                                                    nBlockXSize, sNoDataValues,
8386
0
                                                    pabyMaskData, dfMin, dfMax);
8387
0
            break;
8388
0
        case GDT_Int32:
8389
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8390
0
                                                   nBlockXSize, sNoDataValues,
8391
0
                                                   pabyMaskData, dfMin, dfMax);
8392
0
            break;
8393
0
        case GDT_UInt64:
8394
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8395
0
                                                    nBlockXSize, sNoDataValues,
8396
0
                                                    pabyMaskData, dfMin, dfMax);
8397
0
            break;
8398
0
        case GDT_Int64:
8399
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8400
0
                                                   nBlockXSize, sNoDataValues,
8401
0
                                                   pabyMaskData, dfMin, dfMax);
8402
0
            break;
8403
0
        case GDT_Float16:
8404
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
8405
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8406
0
                pabyMaskData, dfMin, dfMax);
8407
0
            break;
8408
0
        case GDT_Float32:
8409
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
8410
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8411
0
                pabyMaskData, dfMin, dfMax);
8412
0
            break;
8413
0
        case GDT_Float64:
8414
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
8415
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8416
0
                pabyMaskData, dfMin, dfMax);
8417
0
            break;
8418
0
        case GDT_CInt16:
8419
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8420
0
                                                    nBlockXSize, sNoDataValues,
8421
0
                                                    pabyMaskData, dfMin, dfMax);
8422
0
            break;
8423
0
        case GDT_CInt32:
8424
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8425
0
                                                    nBlockXSize, sNoDataValues,
8426
0
                                                    pabyMaskData, dfMin, dfMax);
8427
0
            break;
8428
0
        case GDT_CFloat16:
8429
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
8430
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8431
0
                pabyMaskData, dfMin, dfMax);
8432
0
            break;
8433
0
        case GDT_CFloat32:
8434
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
8435
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8436
0
                pabyMaskData, dfMin, dfMax);
8437
0
            break;
8438
0
        case GDT_CFloat64:
8439
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
8440
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8441
0
                pabyMaskData, dfMin, dfMax);
8442
0
            break;
8443
0
        case GDT_TypeCount:
8444
0
            CPLAssert(false);
8445
0
            break;
8446
0
    }
8447
0
}
8448
8449
static bool ComputeMinMaxGenericIterBlocks(
8450
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8451
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8452
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8453
    double &dfMin, double &dfMax)
8454
8455
0
{
8456
0
    GByte *pabyMaskData = nullptr;
8457
0
    int nBlockXSize, nBlockYSize;
8458
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8459
8460
0
    if (poMaskBand)
8461
0
    {
8462
0
        pabyMaskData =
8463
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8464
0
        if (!pabyMaskData)
8465
0
        {
8466
0
            return false;
8467
0
        }
8468
0
    }
8469
8470
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8471
0
         iSampleBlock += nSampleRate)
8472
0
    {
8473
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8474
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8475
8476
0
        int nXCheck = 0, nYCheck = 0;
8477
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8478
8479
0
        if (poMaskBand &&
8480
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8481
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8482
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8483
0
                                 nBlockXSize, nullptr) != CE_None)
8484
0
        {
8485
0
            CPLFree(pabyMaskData);
8486
0
            return false;
8487
0
        }
8488
8489
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8490
0
        if (poBlock == nullptr)
8491
0
        {
8492
0
            CPLFree(pabyMaskData);
8493
0
            return false;
8494
0
        }
8495
8496
0
        void *const pData = poBlock->GetDataRef();
8497
8498
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8499
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8500
0
                             dfMax);
8501
8502
0
        poBlock->DropLock();
8503
0
    }
8504
8505
0
    CPLFree(pabyMaskData);
8506
0
    return true;
8507
0
}
8508
8509
/**
8510
 * \brief Compute the min/max values for a band.
8511
 *
8512
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8513
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
8514
 * get an approximate min/max.  If the band has a nodata value it will
8515
 * be excluded from the minimum and maximum.
8516
 *
8517
 * If bApprox is FALSE, then all pixels will be read and used to compute
8518
 * an exact range.
8519
 *
8520
 * This method is the same as the C function GDALComputeRasterMinMax().
8521
 *
8522
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8523
 * FALSE.
8524
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8525
 * maximum (adfMinMax[1]) are returned.
8526
 *
8527
 * @return CE_None on success or CE_Failure on failure.
8528
 */
8529
8530
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8531
0
{
8532
    /* -------------------------------------------------------------------- */
8533
    /*      Does the driver already know the min/max?                       */
8534
    /* -------------------------------------------------------------------- */
8535
0
    if (bApproxOK)
8536
0
    {
8537
0
        int bSuccessMin = FALSE;
8538
0
        int bSuccessMax = FALSE;
8539
8540
0
        double dfMin = GetMinimum(&bSuccessMin);
8541
0
        double dfMax = GetMaximum(&bSuccessMax);
8542
8543
0
        if (bSuccessMin && bSuccessMax)
8544
0
        {
8545
0
            adfMinMax[0] = dfMin;
8546
0
            adfMinMax[1] = dfMax;
8547
0
            return CE_None;
8548
0
        }
8549
0
    }
8550
8551
    /* -------------------------------------------------------------------- */
8552
    /*      If we have overview bands, use them for min/max.                */
8553
    /* -------------------------------------------------------------------- */
8554
    // cppcheck-suppress knownConditionTrueFalse
8555
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8556
0
    {
8557
0
        GDALRasterBand *poBand =
8558
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8559
8560
0
        if (poBand != this)
8561
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8562
0
    }
8563
8564
    /* -------------------------------------------------------------------- */
8565
    /*      Read actual data and compute minimum and maximum.               */
8566
    /* -------------------------------------------------------------------- */
8567
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8568
0
    GDALRasterBand *poMaskBand = nullptr;
8569
0
    if (!sNoDataValues.bGotNoDataValue)
8570
0
    {
8571
0
        const int l_nMaskFlags = GetMaskFlags();
8572
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8573
0
            GetColorInterpretation() != GCI_AlphaBand)
8574
0
        {
8575
0
            poMaskBand = GetMaskBand();
8576
0
        }
8577
0
    }
8578
8579
0
    if (!bApproxOK &&
8580
0
        (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8581
0
         eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8582
0
         eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8583
0
         eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8584
0
         eDataType == GDT_Float64) &&
8585
0
        !poMaskBand)
8586
0
    {
8587
0
        CPLErr eErr = ComputeRasterMinMaxLocation(
8588
0
            &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8589
0
        if (eErr == CE_Warning)
8590
0
        {
8591
0
            ReportError(CE_Failure, CPLE_AppDefined,
8592
0
                        "Failed to compute min/max, no valid pixels found in "
8593
0
                        "sampling.");
8594
0
            eErr = CE_Failure;
8595
0
        }
8596
0
        return eErr;
8597
0
    }
8598
8599
0
    bool bSignedByte = false;
8600
0
    if (eDataType == GDT_UInt8)
8601
0
    {
8602
0
        EnablePixelTypeSignedByteWarning(false);
8603
0
        const char *pszPixelType =
8604
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8605
0
        EnablePixelTypeSignedByteWarning(true);
8606
0
        bSignedByte =
8607
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8608
0
    }
8609
8610
0
    GDALRasterIOExtraArg sExtraArg;
8611
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8612
8613
0
    GUInt32 nMin = (eDataType == GDT_UInt8)
8614
0
                       ? 255
8615
0
                       : 65535;  // used for GByte & GUInt16 cases
8616
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
8617
0
    GInt16 nMinInt16 =
8618
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
8619
0
    GInt16 nMaxInt16 =
8620
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
8621
0
    double dfMin =
8622
0
        std::numeric_limits<double>::infinity();  // used for generic code path
8623
0
    double dfMax =
8624
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
8625
0
    const bool bUseOptimizedPath =
8626
0
        !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8627
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8628
8629
0
    const auto ComputeMinMaxForBlock =
8630
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8631
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8632
0
                     int nYCheck)
8633
0
    {
8634
0
        if (eDataType == GDT_UInt8 && !bSignedByte)
8635
0
        {
8636
0
            const bool bHasNoData =
8637
0
                sNoDataValues.bGotNoDataValue &&
8638
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8639
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8640
0
                    sNoDataValues.dfNoDataValue;
8641
0
            const GUInt32 nNoDataValue =
8642
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8643
0
                           : 0;
8644
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8645
0
            ComputeStatisticsInternal<GByte,
8646
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8647
0
                f(nXCheck, nBufferWidth, nYCheck,
8648
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8649
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8650
0
        }
8651
0
        else if (eDataType == GDT_UInt16)
8652
0
        {
8653
0
            const bool bHasNoData =
8654
0
                sNoDataValues.bGotNoDataValue &&
8655
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8656
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8657
0
                    sNoDataValues.dfNoDataValue;
8658
0
            const GUInt32 nNoDataValue =
8659
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8660
0
                           : 0;
8661
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8662
0
            ComputeStatisticsInternal<GUInt16,
8663
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8664
0
                f(nXCheck, nBufferWidth, nYCheck,
8665
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8666
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8667
0
        }
8668
0
        else if (eDataType == GDT_Int16)
8669
0
        {
8670
0
            const bool bHasNoData =
8671
0
                sNoDataValues.bGotNoDataValue &&
8672
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8673
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8674
0
                    sNoDataValues.dfNoDataValue;
8675
0
            if (bHasNoData)
8676
0
            {
8677
0
                const int16_t nNoDataValue =
8678
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8679
0
                for (int iY = 0; iY < nYCheck; iY++)
8680
0
                {
8681
0
                    ComputeMinMax<int16_t, true>(
8682
0
                        static_cast<const int16_t *>(pData) +
8683
0
                            static_cast<size_t>(iY) * nBufferWidth,
8684
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8685
0
                }
8686
0
            }
8687
0
            else
8688
0
            {
8689
0
                for (int iY = 0; iY < nYCheck; iY++)
8690
0
                {
8691
0
                    ComputeMinMax<int16_t, false>(
8692
0
                        static_cast<const int16_t *>(pData) +
8693
0
                            static_cast<size_t>(iY) * nBufferWidth,
8694
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
8695
0
                }
8696
0
            }
8697
0
        }
8698
0
    };
8699
8700
0
    if (bApproxOK && HasArbitraryOverviews())
8701
0
    {
8702
        /* --------------------------------------------------------------------
8703
         */
8704
        /*      Figure out how much the image should be reduced to get an */
8705
        /*      approximate value. */
8706
        /* --------------------------------------------------------------------
8707
         */
8708
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8709
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8710
8711
0
        int nXReduced = nRasterXSize;
8712
0
        int nYReduced = nRasterYSize;
8713
0
        if (dfReduction > 1.0)
8714
0
        {
8715
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8716
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8717
8718
            // Catch the case of huge resizing ratios here
8719
0
            if (nXReduced == 0)
8720
0
                nXReduced = 1;
8721
0
            if (nYReduced == 0)
8722
0
                nYReduced = 1;
8723
0
        }
8724
8725
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
8726
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8727
8728
0
        const CPLErr eErr =
8729
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8730
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8731
0
        if (eErr != CE_None)
8732
0
        {
8733
0
            CPLFree(pData);
8734
0
            return eErr;
8735
0
        }
8736
8737
0
        GByte *pabyMaskData = nullptr;
8738
0
        if (poMaskBand)
8739
0
        {
8740
0
            pabyMaskData =
8741
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8742
0
            if (!pabyMaskData)
8743
0
            {
8744
0
                CPLFree(pData);
8745
0
                return CE_Failure;
8746
0
            }
8747
8748
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8749
0
                                     pabyMaskData, nXReduced, nYReduced,
8750
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
8751
0
            {
8752
0
                CPLFree(pData);
8753
0
                CPLFree(pabyMaskData);
8754
0
                return CE_Failure;
8755
0
            }
8756
0
        }
8757
8758
0
        if (bUseOptimizedPath)
8759
0
        {
8760
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8761
0
        }
8762
0
        else
8763
0
        {
8764
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8765
0
                                 nYReduced, nXReduced, sNoDataValues,
8766
0
                                 pabyMaskData, dfMin, dfMax);
8767
0
        }
8768
8769
0
        CPLFree(pData);
8770
0
        CPLFree(pabyMaskData);
8771
0
    }
8772
8773
0
    else  // No arbitrary overviews
8774
0
    {
8775
0
        if (!InitBlockInfo())
8776
0
            return CE_Failure;
8777
8778
        /* --------------------------------------------------------------------
8779
         */
8780
        /*      Figure out the ratio of blocks we will read to get an */
8781
        /*      approximate value. */
8782
        /* --------------------------------------------------------------------
8783
         */
8784
0
        int nSampleRate = 1;
8785
8786
0
        if (bApproxOK)
8787
0
        {
8788
0
            nSampleRate = static_cast<int>(std::max(
8789
0
                1.0,
8790
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8791
            // We want to avoid probing only the first column of blocks for
8792
            // a square shaped raster, because it is not unlikely that it may
8793
            // be padding only (#6378).
8794
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8795
0
                nSampleRate += 1;
8796
0
        }
8797
8798
0
        if (bUseOptimizedPath)
8799
0
        {
8800
0
            for (GIntBig iSampleBlock = 0;
8801
0
                 iSampleBlock <
8802
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8803
0
                 iSampleBlock += nSampleRate)
8804
0
            {
8805
0
                const int iYBlock =
8806
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
8807
0
                const int iXBlock =
8808
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
8809
8810
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8811
0
                if (poBlock == nullptr)
8812
0
                    return CE_Failure;
8813
8814
0
                void *const pData = poBlock->GetDataRef();
8815
8816
0
                int nXCheck = 0, nYCheck = 0;
8817
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8818
8819
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8820
8821
0
                poBlock->DropLock();
8822
8823
0
                if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8824
0
                    nMax == 255)
8825
0
                    break;
8826
0
            }
8827
0
        }
8828
0
        else
8829
0
        {
8830
0
            const GIntBig nTotalBlocks =
8831
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8832
0
            if (!ComputeMinMaxGenericIterBlocks(
8833
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8834
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8835
0
            {
8836
0
                return CE_Failure;
8837
0
            }
8838
0
        }
8839
0
    }
8840
8841
0
    if (bUseOptimizedPath)
8842
0
    {
8843
0
        if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8844
0
        {
8845
0
            dfMin = nMin;
8846
0
            dfMax = nMax;
8847
0
        }
8848
0
        else if (eDataType == GDT_Int16)
8849
0
        {
8850
0
            dfMin = nMinInt16;
8851
0
            dfMax = nMaxInt16;
8852
0
        }
8853
0
    }
8854
8855
0
    if (dfMin > dfMax)
8856
0
    {
8857
0
        adfMinMax[0] = 0;
8858
0
        adfMinMax[1] = 0;
8859
0
        ReportError(
8860
0
            CE_Failure, CPLE_AppDefined,
8861
0
            "Failed to compute min/max, no valid pixels found in sampling.");
8862
0
        return CE_Failure;
8863
0
    }
8864
8865
0
    adfMinMax[0] = dfMin;
8866
0
    adfMinMax[1] = dfMax;
8867
8868
0
    return CE_None;
8869
0
}
8870
8871
/************************************************************************/
8872
/*                      GDALComputeRasterMinMax()                       */
8873
/************************************************************************/
8874
8875
/**
8876
 * \brief Compute the min/max values for a band.
8877
 *
8878
 * @see GDALRasterBand::ComputeRasterMinMax()
8879
 *
8880
 * @note Prior to GDAL 3.6, this function returned void
8881
 */
8882
8883
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8884
                                           double adfMinMax[2])
8885
8886
0
{
8887
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8888
8889
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8890
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8891
0
}
8892
8893
/************************************************************************/
8894
/*                    ComputeRasterMinMaxLocation()                     */
8895
/************************************************************************/
8896
8897
/**
8898
 * \brief Compute the min/max values for a band, and their location.
8899
 *
8900
 * Pixels whose value matches the nodata value or are masked by the mask
8901
 * band are ignored.
8902
 *
8903
 * If the minimum or maximum value is hit in several locations, it is not
8904
 * specified which one will be returned.
8905
 *
8906
 * @param[out] pdfMin Pointer to the minimum value.
8907
 * @param[out] pdfMax Pointer to the maximum value.
8908
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8909
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8910
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8911
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8912
 *
8913
 * @return CE_None in case of success, CE_Warning if there are no valid values,
8914
 *         CE_Failure in case of error.
8915
 *
8916
 * @since GDAL 3.11
8917
 */
8918
8919
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8920
                                                   double *pdfMax, int *pnMinX,
8921
                                                   int *pnMinY, int *pnMaxX,
8922
                                                   int *pnMaxY)
8923
0
{
8924
0
    int nMinX = -1;
8925
0
    int nMinY = -1;
8926
0
    int nMaxX = -1;
8927
0
    int nMaxY = -1;
8928
0
    double dfMin = std::numeric_limits<double>::infinity();
8929
0
    double dfMax = -std::numeric_limits<double>::infinity();
8930
0
    if (pdfMin)
8931
0
        *pdfMin = dfMin;
8932
0
    if (pdfMax)
8933
0
        *pdfMax = dfMax;
8934
0
    if (pnMinX)
8935
0
        *pnMinX = nMinX;
8936
0
    if (pnMinY)
8937
0
        *pnMinY = nMinY;
8938
0
    if (pnMaxX)
8939
0
        *pnMaxX = nMaxX;
8940
0
    if (pnMaxY)
8941
0
        *pnMaxY = nMaxY;
8942
8943
0
    if (GDALDataTypeIsComplex(eDataType))
8944
0
    {
8945
0
        CPLError(CE_Failure, CPLE_NotSupported,
8946
0
                 "Complex data type not supported");
8947
0
        return CE_Failure;
8948
0
    }
8949
8950
0
    if (!InitBlockInfo())
8951
0
        return CE_Failure;
8952
8953
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8954
0
    GDALRasterBand *poMaskBand = nullptr;
8955
0
    if (!sNoDataValues.bGotNoDataValue)
8956
0
    {
8957
0
        const int l_nMaskFlags = GetMaskFlags();
8958
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8959
0
            GetColorInterpretation() != GCI_AlphaBand)
8960
0
        {
8961
0
            poMaskBand = GetMaskBand();
8962
0
        }
8963
0
    }
8964
8965
0
    bool bSignedByte = false;
8966
0
    if (eDataType == GDT_UInt8)
8967
0
    {
8968
0
        EnablePixelTypeSignedByteWarning(false);
8969
0
        const char *pszPixelType =
8970
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8971
0
        EnablePixelTypeSignedByteWarning(true);
8972
0
        bSignedByte =
8973
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8974
0
    }
8975
8976
0
    GByte *pabyMaskData = nullptr;
8977
0
    if (poMaskBand)
8978
0
    {
8979
0
        pabyMaskData =
8980
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8981
0
        if (!pabyMaskData)
8982
0
        {
8983
0
            return CE_Failure;
8984
0
        }
8985
0
    }
8986
8987
0
    const GIntBig nTotalBlocks =
8988
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8989
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8990
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8991
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8992
0
    {
8993
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8994
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8995
8996
0
        int nXCheck = 0, nYCheck = 0;
8997
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8998
8999
0
        if (poMaskBand &&
9000
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
9001
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
9002
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
9003
0
                                 nBlockXSize, nullptr) != CE_None)
9004
0
        {
9005
0
            CPLFree(pabyMaskData);
9006
0
            return CE_Failure;
9007
0
        }
9008
9009
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
9010
0
        if (poBlock == nullptr)
9011
0
        {
9012
0
            CPLFree(pabyMaskData);
9013
0
            return CE_Failure;
9014
0
        }
9015
9016
0
        void *const pData = poBlock->GetDataRef();
9017
9018
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
9019
0
        {
9020
0
            for (int iY = 0; iY < nYCheck; ++iY)
9021
0
            {
9022
0
                for (int iX = 0; iX < nXCheck; ++iX)
9023
0
                {
9024
0
                    const GPtrDiff_t iOffset =
9025
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9026
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
9027
0
                        continue;
9028
0
                    bool bValid = true;
9029
0
                    double dfValue =
9030
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
9031
0
                                      sNoDataValues, bValid);
9032
0
                    if (!bValid)
9033
0
                        continue;
9034
0
                    if (dfValue < dfMin)
9035
0
                    {
9036
0
                        dfMin = dfValue;
9037
0
                        nMinX = iXBlock * nBlockXSize + iX;
9038
0
                        nMinY = iYBlock * nBlockYSize + iY;
9039
0
                    }
9040
0
                    if (dfValue > dfMax)
9041
0
                    {
9042
0
                        dfMax = dfValue;
9043
0
                        nMaxX = iXBlock * nBlockXSize + iX;
9044
0
                        nMaxY = iYBlock * nBlockYSize + iY;
9045
0
                    }
9046
0
                }
9047
0
            }
9048
0
        }
9049
0
        else
9050
0
        {
9051
0
            size_t pos_min = 0;
9052
0
            size_t pos_max = 0;
9053
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
9054
0
            if (bNeedsMin && bNeedsMax)
9055
0
            {
9056
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
9057
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9058
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
9059
0
                    sNoDataValues.dfNoDataValue);
9060
0
            }
9061
0
            else if (bNeedsMin)
9062
0
            {
9063
0
                pos_min = gdal::min_element(
9064
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9065
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
9066
0
                    sNoDataValues.dfNoDataValue);
9067
0
            }
9068
0
            else if (bNeedsMax)
9069
0
            {
9070
0
                pos_max = gdal::max_element(
9071
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9072
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
9073
0
                    sNoDataValues.dfNoDataValue);
9074
0
            }
9075
9076
0
            if (bNeedsMin)
9077
0
            {
9078
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
9079
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
9080
0
                bool bValid = true;
9081
0
                const double dfMinValueBlock =
9082
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9083
0
                                  sNoDataValues, bValid);
9084
0
                if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9085
0
                {
9086
0
                    dfMin = dfMinValueBlock;
9087
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
9088
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
9089
0
                }
9090
0
            }
9091
9092
0
            if (bNeedsMax)
9093
0
            {
9094
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9095
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9096
0
                bool bValid = true;
9097
0
                const double dfMaxValueBlock =
9098
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9099
0
                                  sNoDataValues, bValid);
9100
0
                if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9101
0
                {
9102
0
                    dfMax = dfMaxValueBlock;
9103
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9104
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9105
0
                }
9106
0
            }
9107
0
        }
9108
9109
0
        poBlock->DropLock();
9110
9111
0
        if (eDataType == GDT_UInt8)
9112
0
        {
9113
0
            if (bNeedsMin && dfMin == 0)
9114
0
            {
9115
0
                bNeedsMin = false;
9116
0
            }
9117
0
            if (bNeedsMax && dfMax == 255)
9118
0
            {
9119
0
                bNeedsMax = false;
9120
0
            }
9121
0
            if (!bNeedsMin && !bNeedsMax)
9122
0
            {
9123
0
                break;
9124
0
            }
9125
0
        }
9126
0
    }
9127
9128
0
    CPLFree(pabyMaskData);
9129
9130
0
    if (pdfMin)
9131
0
        *pdfMin = dfMin;
9132
0
    if (pdfMax)
9133
0
        *pdfMax = dfMax;
9134
0
    if (pnMinX)
9135
0
        *pnMinX = nMinX;
9136
0
    if (pnMinY)
9137
0
        *pnMinY = nMinY;
9138
0
    if (pnMaxX)
9139
0
        *pnMaxX = nMaxX;
9140
0
    if (pnMaxY)
9141
0
        *pnMaxY = nMaxY;
9142
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9143
0
                                                                  : CE_None;
9144
0
}
9145
9146
/************************************************************************/
9147
/*                  GDALComputeRasterMinMaxLocation()                   */
9148
/************************************************************************/
9149
9150
/**
9151
 * \brief Compute the min/max values for a band, and their location.
9152
 *
9153
 * @see GDALRasterBand::ComputeRasterMinMax()
9154
 * @since GDAL 3.11
9155
 */
9156
9157
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9158
                                       double *pdfMax, int *pnMinX, int *pnMinY,
9159
                                       int *pnMaxX, int *pnMaxY)
9160
9161
0
{
9162
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9163
9164
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9165
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9166
0
                                               pnMaxX, pnMaxY);
9167
0
}
9168
9169
/************************************************************************/
9170
/*                        SetDefaultHistogram()                         */
9171
/************************************************************************/
9172
9173
/* FIXME : add proper documentation */
9174
/**
9175
 * \brief Set default histogram.
9176
 *
9177
 * This method is the same as the C function GDALSetDefaultHistogram() and
9178
 * GDALSetDefaultHistogramEx()
9179
 */
9180
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9181
                                           double /* dfMax */,
9182
                                           int /* nBuckets */,
9183
                                           GUIntBig * /* panHistogram */)
9184
9185
0
{
9186
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9187
0
        ReportError(CE_Failure, CPLE_NotSupported,
9188
0
                    "SetDefaultHistogram() not implemented for this format.");
9189
9190
0
    return CE_Failure;
9191
0
}
9192
9193
/************************************************************************/
9194
/*                      GDALSetDefaultHistogram()                       */
9195
/************************************************************************/
9196
9197
/**
9198
 * \brief Set default histogram.
9199
 *
9200
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9201
 * 2 billion.
9202
 *
9203
 * @see GDALRasterBand::SetDefaultHistogram()
9204
 * @see GDALSetRasterHistogramEx()
9205
 */
9206
9207
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9208
                                           double dfMax, int nBuckets,
9209
                                           int *panHistogram)
9210
9211
0
{
9212
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9213
9214
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9215
9216
0
    GUIntBig *panHistogramTemp =
9217
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9218
0
    if (panHistogramTemp == nullptr)
9219
0
    {
9220
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9221
0
                            "Out of memory in GDALSetDefaultHistogram().");
9222
0
        return CE_Failure;
9223
0
    }
9224
9225
0
    for (int i = 0; i < nBuckets; ++i)
9226
0
    {
9227
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9228
0
    }
9229
9230
0
    const CPLErr eErr =
9231
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9232
9233
0
    CPLFree(panHistogramTemp);
9234
9235
0
    return eErr;
9236
0
}
9237
9238
/************************************************************************/
9239
/*                     GDALSetDefaultHistogramEx()                      */
9240
/************************************************************************/
9241
9242
/**
9243
 * \brief Set default histogram.
9244
 *
9245
 * @see GDALRasterBand::SetDefaultHistogram()
9246
 *
9247
 */
9248
9249
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9250
                                             double dfMin, double dfMax,
9251
                                             int nBuckets,
9252
                                             GUIntBig *panHistogram)
9253
9254
0
{
9255
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9256
9257
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9258
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9259
0
}
9260
9261
/************************************************************************/
9262
/*                           GetDefaultRAT()                            */
9263
/************************************************************************/
9264
9265
/**
9266
 * \brief Fetch default Raster Attribute Table.
9267
 *
9268
 * A RAT will be returned if there is a default one associated with the
9269
 * band, otherwise NULL is returned.  The returned RAT is owned by the
9270
 * band and should not be deleted by the application.
9271
 *
9272
 * This method is the same as the C function GDALGetDefaultRAT().
9273
 *
9274
 * @return NULL, or a pointer to an internal RAT owned by the band.
9275
 */
9276
9277
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9278
9279
0
{
9280
0
    return nullptr;
9281
0
}
9282
9283
/************************************************************************/
9284
/*                         GDALGetDefaultRAT()                          */
9285
/************************************************************************/
9286
9287
/**
9288
 * \brief Fetch default Raster Attribute Table.
9289
 *
9290
 * @see GDALRasterBand::GetDefaultRAT()
9291
 */
9292
9293
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9294
9295
0
{
9296
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9297
9298
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9299
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9300
0
}
9301
9302
/************************************************************************/
9303
/*                           SetDefaultRAT()                            */
9304
/************************************************************************/
9305
9306
/**
9307
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9308
 * \brief Set default Raster Attribute Table.
9309
 *
9310
 * Associates a default RAT with the band.  If not implemented for the
9311
 * format a CPLE_NotSupported error will be issued.  If successful a copy
9312
 * of the RAT is made, the original remains owned by the caller.
9313
 *
9314
 * This method is the same as the C function GDALSetDefaultRAT().
9315
 *
9316
 * @param poRAT the RAT to assign to the band.
9317
 *
9318
 * @return CE_None on success or CE_Failure if unsupported or otherwise
9319
 * failing.
9320
 */
9321
9322
/**/
9323
/**/
9324
9325
CPLErr
9326
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9327
0
{
9328
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9329
0
    {
9330
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
9331
0
        ReportError(CE_Failure, CPLE_NotSupported,
9332
0
                    "SetDefaultRAT() not implemented for this format.");
9333
0
        CPLPopErrorHandler();
9334
0
    }
9335
0
    return CE_Failure;
9336
0
}
9337
9338
/************************************************************************/
9339
/*                         GDALSetDefaultRAT()                          */
9340
/************************************************************************/
9341
9342
/**
9343
 * \brief Set default Raster Attribute Table.
9344
 *
9345
 * @see GDALRasterBand::GDALSetDefaultRAT()
9346
 */
9347
9348
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9349
                                     GDALRasterAttributeTableH hRAT)
9350
9351
0
{
9352
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9353
9354
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9355
9356
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9357
0
}
9358
9359
/************************************************************************/
9360
/*                             HasNoData()                              */
9361
/************************************************************************/
9362
9363
bool GDALRasterBand::HasNoData() const
9364
0
{
9365
0
    int bHaveNoDataRaw = FALSE;
9366
0
    bool bHaveNoData = false;
9367
0
    GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9368
0
    if (eDataType == GDT_Int64)
9369
0
    {
9370
0
        CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9371
0
        bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9372
0
    }
9373
0
    else if (eDataType == GDT_UInt64)
9374
0
    {
9375
0
        CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9376
0
        bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9377
0
    }
9378
0
    else
9379
0
    {
9380
0
        const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9381
0
        if (bHaveNoDataRaw &&
9382
0
            GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9383
0
        {
9384
0
            bHaveNoData = true;
9385
0
        }
9386
0
    }
9387
0
    return bHaveNoData;
9388
0
}
9389
9390
/************************************************************************/
9391
/*                            GetMaskBand()                             */
9392
/************************************************************************/
9393
9394
/**
9395
 * \brief Return the mask band associated with the band.
9396
 *
9397
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9398
 * that returns one of four default implementations :
9399
 * <ul>
9400
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9401
 * </li>
9402
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9403
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9404
 * GMF_NODATA | GMF_PER_DATASET.
9405
 * </li>
9406
 * <li>If the band has a nodata value set, an instance of the new
9407
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9408
 * GMF_NODATA.
9409
 * </li>
9410
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
9411
 * to apply to this band (specific rules yet to be determined) and that is of
9412
 * type GDT_UInt8 then that alpha band will be returned, and the flags
9413
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9414
 * </li>
9415
 * <li>If neither of the above apply, an instance of the new
9416
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9417
 * pixels. The null flags will return GMF_ALL_VALID.
9418
 * </li>
9419
 * </ul>
9420
 *
9421
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9422
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9423
 *
9424
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9425
 * dataset, with the same name as the main dataset and suffixed with .msk,
9426
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9427
 * main dataset.
9428
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9429
 * level, where xx matches the band number of a band of the main dataset. The
9430
 * value of those items is a combination of the flags GMF_ALL_VALID,
9431
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9432
 * a band, then the other rules explained above will be used to generate a
9433
 * on-the-fly mask band.
9434
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9435
 *
9436
 * This method is the same as the C function GDALGetMaskBand().
9437
 *
9438
 * @return a valid mask band.
9439
 *
9440
 *
9441
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9442
 *
9443
 */
9444
GDALRasterBand *GDALRasterBand::GetMaskBand()
9445
9446
0
{
9447
0
    if (poMask != nullptr)
9448
0
    {
9449
0
        if (poMask.IsOwned())
9450
0
        {
9451
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9452
0
            {
9453
0
                if (HasNoData())
9454
0
                {
9455
0
                    InvalidateMaskBand();
9456
0
                }
9457
0
            }
9458
0
            else if (auto poNoDataMaskBand =
9459
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9460
0
            {
9461
0
                int bHaveNoDataRaw = FALSE;
9462
0
                bool bIsSame = false;
9463
0
                if (eDataType == GDT_Int64)
9464
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9465
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9466
0
                              bHaveNoDataRaw;
9467
0
                else if (eDataType == GDT_UInt64)
9468
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9469
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9470
0
                              bHaveNoDataRaw;
9471
0
                else
9472
0
                {
9473
0
                    const double dfNoDataValue =
9474
0
                        GetNoDataValue(&bHaveNoDataRaw);
9475
0
                    if (bHaveNoDataRaw)
9476
0
                    {
9477
0
                        bIsSame =
9478
0
                            std::isnan(dfNoDataValue)
9479
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9480
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
9481
0
                                      dfNoDataValue;
9482
0
                    }
9483
0
                }
9484
0
                if (!bIsSame)
9485
0
                    InvalidateMaskBand();
9486
0
            }
9487
0
        }
9488
9489
0
        if (poMask)
9490
0
            return poMask.get();
9491
0
    }
9492
9493
    /* -------------------------------------------------------------------- */
9494
    /*      Check for a mask in a .msk file.                                */
9495
    /* -------------------------------------------------------------------- */
9496
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9497
0
    {
9498
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9499
0
        if (poMask != nullptr)
9500
0
        {
9501
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9502
0
            return poMask.get();
9503
0
        }
9504
0
    }
9505
9506
    /* -------------------------------------------------------------------- */
9507
    /*      Check for NODATA_VALUES metadata.                               */
9508
    /* -------------------------------------------------------------------- */
9509
0
    if (poDS != nullptr)
9510
0
    {
9511
0
        const char *pszGDALNoDataValues =
9512
0
            poDS->GetMetadataItem("NODATA_VALUES");
9513
0
        if (pszGDALNoDataValues != nullptr)
9514
0
        {
9515
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9516
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
9517
9518
            // Make sure we have as many values as bands.
9519
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9520
0
                poDS->GetRasterCount() != 0)
9521
0
            {
9522
                // Make sure that all bands have the same data type
9523
                // This is clearly not a fundamental condition, just a
9524
                // condition to make implementation easier.
9525
0
                GDALDataType eDT = GDT_Unknown;
9526
0
                int i = 0;  // Used after for.
9527
0
                for (; i < poDS->GetRasterCount(); ++i)
9528
0
                {
9529
0
                    if (i == 0)
9530
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9531
0
                    else if (eDT !=
9532
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
9533
0
                    {
9534
0
                        break;
9535
0
                    }
9536
0
                }
9537
0
                if (i == poDS->GetRasterCount())
9538
0
                {
9539
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9540
0
                    try
9541
0
                    {
9542
0
                        poMask.reset(
9543
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9544
0
                    }
9545
0
                    catch (const std::bad_alloc &)
9546
0
                    {
9547
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9548
0
                        poMask.reset();
9549
0
                    }
9550
0
                    CSLDestroy(papszGDALNoDataValues);
9551
0
                    return poMask.get();
9552
0
                }
9553
0
                else
9554
0
                {
9555
0
                    ReportError(CE_Warning, CPLE_AppDefined,
9556
0
                                "All bands should have the same type in "
9557
0
                                "order the NODATA_VALUES metadata item "
9558
0
                                "to be used as a mask.");
9559
0
                }
9560
0
            }
9561
0
            else
9562
0
            {
9563
0
                ReportError(
9564
0
                    CE_Warning, CPLE_AppDefined,
9565
0
                    "NODATA_VALUES metadata item doesn't have the same number "
9566
0
                    "of values as the number of bands.  "
9567
0
                    "Ignoring it for mask.");
9568
0
            }
9569
9570
0
            CSLDestroy(papszGDALNoDataValues);
9571
0
        }
9572
0
    }
9573
9574
    /* -------------------------------------------------------------------- */
9575
    /*      Check for nodata case.                                          */
9576
    /* -------------------------------------------------------------------- */
9577
0
    if (HasNoData())
9578
0
    {
9579
0
        nMaskFlags = GMF_NODATA;
9580
0
        try
9581
0
        {
9582
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9583
0
        }
9584
0
        catch (const std::bad_alloc &)
9585
0
        {
9586
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9587
0
            poMask.reset();
9588
0
        }
9589
0
        return poMask.get();
9590
0
    }
9591
9592
    /* -------------------------------------------------------------------- */
9593
    /*      Check for alpha case.                                           */
9594
    /* -------------------------------------------------------------------- */
9595
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9596
0
        this == poDS->GetRasterBand(1) &&
9597
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9598
0
    {
9599
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9600
0
        {
9601
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9602
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
9603
0
            return poMask.get();
9604
0
        }
9605
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9606
0
        {
9607
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9608
0
            try
9609
0
            {
9610
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9611
0
                    poDS->GetRasterBand(2)));
9612
0
            }
9613
0
            catch (const std::bad_alloc &)
9614
0
            {
9615
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9616
0
                poMask.reset();
9617
0
            }
9618
0
            return poMask.get();
9619
0
        }
9620
0
    }
9621
9622
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9623
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9624
0
         this == poDS->GetRasterBand(3)) &&
9625
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9626
0
    {
9627
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9628
0
        {
9629
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9630
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
9631
0
            return poMask.get();
9632
0
        }
9633
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9634
0
        {
9635
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9636
0
            try
9637
0
            {
9638
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9639
0
                    poDS->GetRasterBand(4)));
9640
0
            }
9641
0
            catch (const std::bad_alloc &)
9642
0
            {
9643
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9644
0
                poMask.reset();
9645
0
            }
9646
0
            return poMask.get();
9647
0
        }
9648
0
    }
9649
9650
    /* -------------------------------------------------------------------- */
9651
    /*      Fallback to all valid case.                                     */
9652
    /* -------------------------------------------------------------------- */
9653
0
    nMaskFlags = GMF_ALL_VALID;
9654
0
    try
9655
0
    {
9656
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9657
0
    }
9658
0
    catch (const std::bad_alloc &)
9659
0
    {
9660
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9661
0
        poMask.reset();
9662
0
    }
9663
9664
0
    return poMask.get();
9665
0
}
9666
9667
/************************************************************************/
9668
/*                          GDALGetMaskBand()                           */
9669
/************************************************************************/
9670
9671
/**
9672
 * \brief Return the mask band associated with the band.
9673
 *
9674
 * @see GDALRasterBand::GetMaskBand()
9675
 */
9676
9677
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9678
9679
0
{
9680
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9681
9682
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9683
0
    return poBand->GetMaskBand();
9684
0
}
9685
9686
/************************************************************************/
9687
/*                            GetMaskFlags()                            */
9688
/************************************************************************/
9689
9690
/**
9691
 * \brief Return the status flags of the mask band associated with the band.
9692
 *
9693
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9694
 * the following available definitions that may be extended in the future:
9695
 * <ul>
9696
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9697
 * 255. When used this will normally be the only flag set.
9698
 * </li>
9699
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9700
 * dataset.
9701
 * </li>
9702
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9703
 * and may have values other than 0 and 255.
9704
 * </li>
9705
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9706
 * nodata values. (mutually exclusive of GMF_ALPHA)
9707
 * </li>
9708
 * </ul>
9709
 *
9710
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9711
 * that returns one of four default implementations:
9712
 * <ul>
9713
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9714
 * </li>
9715
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9716
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9717
 * GMF_NODATA | GMF_PER_DATASET.
9718
 * </li>
9719
 * <li>If the band has a nodata value set, an instance of the new
9720
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9721
 * GMF_NODATA.
9722
 * </li>
9723
 * <li>If there is no nodata value, but the dataset has an alpha band that
9724
 * seems to apply to this band (specific rules yet to be determined) and that is
9725
 * of type GDT_UInt8 then that alpha band will be returned, and the flags
9726
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9727
 * </li>
9728
 * <li>If neither of the above apply, an instance of the new
9729
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9730
 * pixels. The null flags will return GMF_ALL_VALID.
9731
 * </li>
9732
 * </ul>
9733
 *
9734
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9735
 * dataset, with the same name as the main dataset and suffixed with .msk,
9736
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9737
 * main dataset.
9738
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9739
 * level, where xx matches the band number of a band of the main dataset. The
9740
 * value of those items is a combination of the flags GMF_ALL_VALID,
9741
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9742
 * a band, then the other rules explained above will be used to generate a
9743
 * on-the-fly mask band.
9744
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9745
 *
9746
 * This method is the same as the C function GDALGetMaskFlags().
9747
 *
9748
 *
9749
 * @return a valid mask band.
9750
 *
9751
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9752
 *
9753
 */
9754
int GDALRasterBand::GetMaskFlags()
9755
9756
0
{
9757
    // If we don't have a band yet, force this now so that the masks value
9758
    // will be initialized.
9759
9760
0
    if (poMask == nullptr)
9761
0
        GetMaskBand();
9762
9763
0
    return nMaskFlags;
9764
0
}
9765
9766
/************************************************************************/
9767
/*                          GDALGetMaskFlags()                          */
9768
/************************************************************************/
9769
9770
/**
9771
 * \brief Return the status flags of the mask band associated with the band.
9772
 *
9773
 * @see GDALRasterBand::GetMaskFlags()
9774
 */
9775
9776
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9777
9778
0
{
9779
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9780
9781
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9782
0
    return poBand->GetMaskFlags();
9783
0
}
9784
9785
/************************************************************************/
9786
/*                         InvalidateMaskBand()                         */
9787
/************************************************************************/
9788
9789
//! @cond Doxygen_Suppress
9790
void GDALRasterBand::InvalidateMaskBand()
9791
0
{
9792
0
    poMask.reset();
9793
0
    nMaskFlags = 0;
9794
0
}
9795
9796
//! @endcond
9797
9798
/************************************************************************/
9799
/*                           CreateMaskBand()                           */
9800
/************************************************************************/
9801
9802
/**
9803
 * \brief Adds a mask band to the current band
9804
 *
9805
 * The default implementation of the CreateMaskBand() method is implemented
9806
 * based on similar rules to the .ovr handling implemented using the
9807
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9808
 * be created with the same basename as the original file, and it will have
9809
 * as many bands as the original image (or just one for GMF_PER_DATASET).
9810
 * The mask images will be deflate compressed tiled images with the same
9811
 * block size as the original image if possible.
9812
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9813
 * level, where xx matches the band number of a band of the main dataset. The
9814
 * value of those items will be the one of the nFlagsIn parameter.
9815
 *
9816
 * Note that if you got a mask band with a previous call to GetMaskBand(),
9817
 * it might be invalidated by CreateMaskBand(). So you have to call
9818
 * GetMaskBand() again.
9819
 *
9820
 * This method is the same as the C function GDALCreateMaskBand().
9821
 *
9822
 *
9823
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9824
 *
9825
 * @return CE_None on success or CE_Failure on an error.
9826
 *
9827
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9828
 * @see GDALDataset::CreateMaskBand()
9829
 *
9830
 */
9831
9832
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9833
9834
0
{
9835
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9836
0
    {
9837
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9838
0
        if (eErr != CE_None)
9839
0
            return eErr;
9840
9841
0
        InvalidateMaskBand();
9842
9843
0
        return CE_None;
9844
0
    }
9845
9846
0
    ReportError(CE_Failure, CPLE_NotSupported,
9847
0
                "CreateMaskBand() not supported for this band.");
9848
9849
0
    return CE_Failure;
9850
0
}
9851
9852
/************************************************************************/
9853
/*                         GDALCreateMaskBand()                         */
9854
/************************************************************************/
9855
9856
/**
9857
 * \brief Adds a mask band to the current band
9858
 *
9859
 * @see GDALRasterBand::CreateMaskBand()
9860
 */
9861
9862
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9863
9864
0
{
9865
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9866
9867
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9868
0
    return poBand->CreateMaskBand(nFlags);
9869
0
}
9870
9871
/************************************************************************/
9872
/*                             IsMaskBand()                             */
9873
/************************************************************************/
9874
9875
/**
9876
 * \brief Returns whether a band is a mask band.
9877
 *
9878
 * Mask band must be understood in the broad term: it can be a per-dataset
9879
 * mask band, an alpha band, or an implicit mask band.
9880
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9881
 *
9882
 * This method is the same as the C function GDALIsMaskBand().
9883
 *
9884
 * @return true if the band is a mask band.
9885
 *
9886
 * @see GDALDataset::CreateMaskBand()
9887
 *
9888
 * @since GDAL 3.5.0
9889
 *
9890
 */
9891
9892
bool GDALRasterBand::IsMaskBand() const
9893
0
{
9894
    // The GeoTIFF driver, among others, override this method to
9895
    // also handle external .msk bands.
9896
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9897
0
           GCI_AlphaBand;
9898
0
}
9899
9900
/************************************************************************/
9901
/*                           GDALIsMaskBand()                           */
9902
/************************************************************************/
9903
9904
/**
9905
 * \brief Returns whether a band is a mask band.
9906
 *
9907
 * Mask band must be understood in the broad term: it can be a per-dataset
9908
 * mask band, an alpha band, or an implicit mask band.
9909
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9910
 *
9911
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9912
 *
9913
 * @return true if the band is a mask band.
9914
 *
9915
 * @see GDALRasterBand::IsMaskBand()
9916
 *
9917
 * @since GDAL 3.5.0
9918
 *
9919
 */
9920
9921
bool GDALIsMaskBand(GDALRasterBandH hBand)
9922
9923
0
{
9924
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9925
9926
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9927
0
    return poBand->IsMaskBand();
9928
0
}
9929
9930
/************************************************************************/
9931
/*                         GetMaskValueRange()                          */
9932
/************************************************************************/
9933
9934
/**
9935
 * \brief Returns the range of values that a mask band can take.
9936
 *
9937
 * @return the range of values that a mask band can take.
9938
 *
9939
 * @since GDAL 3.5.0
9940
 *
9941
 */
9942
9943
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9944
0
{
9945
0
    return GMVR_UNKNOWN;
9946
0
}
9947
9948
/************************************************************************/
9949
/*                     HasConflictingMaskSources()                      */
9950
/************************************************************************/
9951
9952
/**
9953
 * \brief Returns whether a raster band has conflicting mask sources.
9954
 *
9955
 * That is, if more than one of the following conditions is met:
9956
 * - it has a binary mask band (that is not an alpha band)
9957
 * - it has an external mask flags (.msk file)
9958
 * - it has a nodata value
9959
 * - it belongs to a dataset with the NODATA_VALUES metadata item set
9960
 * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
9961
 *
9962
 * @param[out] posDetailMessage Pointer to a string that will contain the
9963
 *                              details of the conflict.
9964
 * @param bMentionPrioritarySource Whether the mask source used should be
9965
 *                                 mentioned in *posDetailMessage.
9966
 * @since GDAL 3.13.0
9967
 */
9968
9969
bool GDALRasterBand::HasConflictingMaskSources(
9970
    std::string *posDetailMessage, bool bMentionPrioritarySource) const
9971
0
{
9972
0
    const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
9973
0
    const bool bHasBinaryMaskBand =
9974
0
        ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
9975
0
          (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
9976
0
        (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
9977
0
    const bool bHasNoData = HasNoData();
9978
0
    const bool bHasNODATA_VALUES =
9979
0
        poDS && poDS->GetMetadataItem("NODATA_VALUES");
9980
0
    const bool bHasAlphaBand =
9981
0
        poDS &&
9982
0
        poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
9983
0
            GCI_AlphaBand;
9984
0
    const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
9985
0
                                  bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
9986
0
    const size_t nCount =
9987
0
        std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
9988
0
    if (nCount >= 2)
9989
0
    {
9990
0
        if (posDetailMessage)
9991
0
        {
9992
0
            *posDetailMessage = "Raster band ";
9993
0
            *posDetailMessage += std::to_string(nBand);
9994
0
            if (poDS && poDS->GetDescription()[0])
9995
0
            {
9996
0
                *posDetailMessage += " of dataset ";
9997
0
                *posDetailMessage += poDS->GetDescription();
9998
0
            }
9999
0
            *posDetailMessage += " has several conflicting mask sources:\n";
10000
0
            if (bHasExternalMask)
10001
0
                *posDetailMessage += "- internal binary mask band\n";
10002
0
            if (bHasExternalMask)
10003
0
                *posDetailMessage += "- external mask band (.msk)\n";
10004
0
            if (bHasNoData)
10005
0
                *posDetailMessage += "- nodata value\n";
10006
0
            if (bHasNODATA_VALUES)
10007
0
                *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
10008
0
            if (bHasAlphaBand)
10009
0
                *posDetailMessage +=
10010
0
                    "- related to a raster band that is an alpha band\n";
10011
0
            if (bMentionPrioritarySource)
10012
0
                *posDetailMessage +=
10013
0
                    "Only the first listed one will be taken into account.";
10014
0
        }
10015
0
        return true;
10016
0
    }
10017
0
    return false;
10018
0
}
10019
10020
/************************************************************************/
10021
/*                     GetIndexColorTranslationTo()                     */
10022
/************************************************************************/
10023
10024
/**
10025
 * \brief Compute translation table for color tables.
10026
 *
10027
 * When the raster band has a palette index, it may be useful to compute
10028
 * the "translation" of this palette to the palette of another band.
10029
 * The translation tries to do exact matching first, and then approximate
10030
 * matching if no exact matching is possible.
10031
 * This method returns a table such that table[i] = j where i is an index
10032
 * of the 'this' rasterband and j the corresponding index for the reference
10033
 * rasterband.
10034
 *
10035
 * This method is thought as internal to GDAL and is used for drivers
10036
 * like RPFTOC.
10037
 *
10038
 * The implementation only supports 1-byte palette rasterbands.
10039
 *
10040
 * @param poReferenceBand the raster band
10041
 * @param pTranslationTable an already allocated translation table (at least 256
10042
 * bytes), or NULL to let the method allocate it
10043
 * @param pApproximateMatching a pointer to a flag that is set if the matching
10044
 *                              is approximate. May be NULL.
10045
 *
10046
 * @return a translation table if the two bands are palette index and that they
10047
 * do not match or NULL in other cases. The table must be freed with CPLFree if
10048
 * NULL was passed for pTranslationTable.
10049
 */
10050
10051
unsigned char *
10052
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
10053
                                           unsigned char *pTranslationTable,
10054
                                           int *pApproximateMatching)
10055
0
{
10056
0
    if (poReferenceBand == nullptr)
10057
0
        return nullptr;
10058
10059
    // cppcheck-suppress knownConditionTrueFalse
10060
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
10061
        // cppcheck-suppress knownConditionTrueFalse
10062
0
        GetColorInterpretation() == GCI_PaletteIndex &&
10063
0
        poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
10064
0
        GetRasterDataType() == GDT_UInt8)
10065
0
    {
10066
0
        const GDALColorTable *srcColorTable = GetColorTable();
10067
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
10068
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
10069
0
        {
10070
0
            const int nEntries = srcColorTable->GetColorEntryCount();
10071
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
10072
10073
0
            int bHasNoDataValueSrc = FALSE;
10074
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
10075
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
10076
0
                  dfNoDataValueSrc <= 255 &&
10077
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
10078
0
                bHasNoDataValueSrc = FALSE;
10079
0
            const int noDataValueSrc =
10080
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10081
10082
0
            int bHasNoDataValueRef = FALSE;
10083
0
            const double dfNoDataValueRef =
10084
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10085
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10086
0
                  dfNoDataValueRef <= 255 &&
10087
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10088
0
                bHasNoDataValueRef = FALSE;
10089
0
            const int noDataValueRef =
10090
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10091
10092
0
            bool samePalette = false;
10093
10094
0
            if (pApproximateMatching)
10095
0
                *pApproximateMatching = FALSE;
10096
10097
0
            if (nEntries == nRefEntries &&
10098
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
10099
0
                (bHasNoDataValueSrc == FALSE ||
10100
0
                 noDataValueSrc == noDataValueRef))
10101
0
            {
10102
0
                samePalette = true;
10103
0
                for (int i = 0; i < nEntries; ++i)
10104
0
                {
10105
0
                    if (noDataValueSrc == i)
10106
0
                        continue;
10107
0
                    const GDALColorEntry *entry =
10108
0
                        srcColorTable->GetColorEntry(i);
10109
0
                    const GDALColorEntry *entryRef =
10110
0
                        destColorTable->GetColorEntry(i);
10111
0
                    if (entry->c1 != entryRef->c1 ||
10112
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10113
0
                    {
10114
0
                        samePalette = false;
10115
0
                    }
10116
0
                }
10117
0
            }
10118
10119
0
            if (!samePalette)
10120
0
            {
10121
0
                if (pTranslationTable == nullptr)
10122
0
                {
10123
0
                    pTranslationTable = static_cast<unsigned char *>(
10124
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10125
0
                    if (pTranslationTable == nullptr)
10126
0
                        return nullptr;
10127
0
                }
10128
10129
                // Trying to remap the product palette on the subdataset
10130
                // palette.
10131
0
                for (int i = 0; i < nEntries; ++i)
10132
0
                {
10133
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10134
0
                        noDataValueSrc == i)
10135
0
                        continue;
10136
0
                    const GDALColorEntry *entry =
10137
0
                        srcColorTable->GetColorEntry(i);
10138
0
                    bool bMatchFound = false;
10139
0
                    for (int j = 0; j < nRefEntries; ++j)
10140
0
                    {
10141
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
10142
0
                            continue;
10143
0
                        const GDALColorEntry *entryRef =
10144
0
                            destColorTable->GetColorEntry(j);
10145
0
                        if (entry->c1 == entryRef->c1 &&
10146
0
                            entry->c2 == entryRef->c2 &&
10147
0
                            entry->c3 == entryRef->c3)
10148
0
                        {
10149
0
                            pTranslationTable[i] =
10150
0
                                static_cast<unsigned char>(j);
10151
0
                            bMatchFound = true;
10152
0
                            break;
10153
0
                        }
10154
0
                    }
10155
0
                    if (!bMatchFound)
10156
0
                    {
10157
                        // No exact match. Looking for closest color now.
10158
0
                        int best_j = 0;
10159
0
                        int best_distance = 0;
10160
0
                        if (pApproximateMatching)
10161
0
                            *pApproximateMatching = TRUE;
10162
0
                        for (int j = 0; j < nRefEntries; ++j)
10163
0
                        {
10164
0
                            const GDALColorEntry *entryRef =
10165
0
                                destColorTable->GetColorEntry(j);
10166
0
                            int distance = (entry->c1 - entryRef->c1) *
10167
0
                                               (entry->c1 - entryRef->c1) +
10168
0
                                           (entry->c2 - entryRef->c2) *
10169
0
                                               (entry->c2 - entryRef->c2) +
10170
0
                                           (entry->c3 - entryRef->c3) *
10171
0
                                               (entry->c3 - entryRef->c3);
10172
0
                            if (j == 0 || distance < best_distance)
10173
0
                            {
10174
0
                                best_j = j;
10175
0
                                best_distance = distance;
10176
0
                            }
10177
0
                        }
10178
0
                        pTranslationTable[i] =
10179
0
                            static_cast<unsigned char>(best_j);
10180
0
                    }
10181
0
                }
10182
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
10183
0
                    pTranslationTable[noDataValueSrc] =
10184
0
                        static_cast<unsigned char>(noDataValueRef);
10185
10186
0
                return pTranslationTable;
10187
0
            }
10188
0
        }
10189
0
    }
10190
0
    return nullptr;
10191
0
}
10192
10193
/************************************************************************/
10194
/*                          SetFlushBlockErr()                          */
10195
/************************************************************************/
10196
10197
/**
10198
 * \brief Store that an error occurred while writing a dirty block.
10199
 *
10200
 * This function stores the fact that an error occurred while writing a dirty
10201
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10202
 * flushed when the block cache get full, it is not convenient/possible to
10203
 * report that a dirty block could not be written correctly. This function
10204
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10205
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10206
 * places where the user can easily match the error with the relevant dataset.
10207
 */
10208
10209
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10210
0
{
10211
0
    eFlushBlockErr = eErr;
10212
0
}
10213
10214
/************************************************************************/
10215
/*                           IncDirtyBlocks()                           */
10216
/************************************************************************/
10217
10218
/**
10219
 * \brief Increment/decrement the number of dirty blocks
10220
 */
10221
10222
void GDALRasterBand::IncDirtyBlocks(int nInc)
10223
0
{
10224
0
    if (poBandBlockCache)
10225
0
        poBandBlockCache->IncDirtyBlocks(nInc);
10226
0
}
10227
10228
/************************************************************************/
10229
/*                            ReportError()                             */
10230
/************************************************************************/
10231
10232
#ifndef DOXYGEN_XML
10233
/**
10234
 * \brief Emits an error related to a raster band.
10235
 *
10236
 * This function is a wrapper for regular CPLError(). The only difference
10237
 * with CPLError() is that it prepends the error message with the dataset
10238
 * name and the band number.
10239
 *
10240
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10241
 * @param err_no the error number (CPLE_*) from cpl_error.h.
10242
 * @param fmt a printf() style format string.  Any additional arguments
10243
 * will be treated as arguments to fill in this format in a manner
10244
 * similar to printf().
10245
 *
10246
 */
10247
10248
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10249
                                 const char *fmt, ...) const
10250
0
{
10251
0
    va_list args;
10252
10253
0
    va_start(args, fmt);
10254
10255
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
10256
0
    pszDSName = CPLGetFilename(pszDSName);
10257
0
    if (pszDSName[0] != '\0')
10258
0
    {
10259
0
        CPLError(eErrClass, err_no, "%s",
10260
0
                 CPLString()
10261
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
10262
0
                     .append(CPLString().vPrintf(fmt, args))
10263
0
                     .c_str());
10264
0
    }
10265
0
    else
10266
0
    {
10267
0
        CPLErrorV(eErrClass, err_no, fmt, args);
10268
0
    }
10269
10270
0
    va_end(args);
10271
0
}
10272
#endif
10273
10274
/************************************************************************/
10275
/*                         GetVirtualMemAuto()                          */
10276
/************************************************************************/
10277
10278
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10279
 *
10280
 * Only supported on Linux and Unix systems with mmap() for now.
10281
 *
10282
 * This method allows creating a virtual memory object for a GDALRasterBand,
10283
 * that exposes the whole image data as a virtual array.
10284
 *
10285
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10286
 * specialized implementation, such as for raw files, may also directly use
10287
 * mechanisms of the operating system to create a view of the underlying file
10288
 * into virtual memory ( CPLVirtualMemFileMapNew() )
10289
 *
10290
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10291
 * offer a specialized implementation with direct file mapping, provided that
10292
 * some requirements are met :
10293
 *   - for all drivers, the dataset must be backed by a "real" file in the file
10294
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10295
 *     must match the native ordering of the CPU.
10296
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10297
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10298
 * the file in sequential order, and be equally spaced (which is generally the
10299
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10300
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10301
 *
10302
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
10303
 * CPLVirtualMemFree() must be called before the raster band object is
10304
 * destroyed.
10305
 *
10306
 * If p is such a pointer and base_type the type matching
10307
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10308
 * accessed with
10309
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10310
 *
10311
 * This method is the same as the C GDALGetVirtualMemAuto() function.
10312
 *
10313
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10314
 * read/write the band.
10315
 *
10316
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
10317
 * one pixel value in the buffer to the start of the next pixel value within a
10318
 * scanline.
10319
 *
10320
 * @param pnLineSpace Output parameter giving the byte offset from the start of
10321
 * one scanline in the buffer to the start of the next.
10322
 *
10323
 * @param papszOptions NULL terminated list of options.
10324
 *                     If a specialized implementation exists, defining
10325
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10326
 * used. On the contrary, defining
10327
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10328
 * being used (thus only allowing efficient implementations to be used). When
10329
 * requiring or falling back to the default implementation, the following
10330
 *                     options are available : CACHE_SIZE (in bytes, defaults to
10331
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10332
 * to FALSE)
10333
 *
10334
 * @return a virtual memory object that must be unreferenced by
10335
 * CPLVirtualMemFree(), or NULL in case of failure.
10336
 *
10337
 */
10338
10339
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10340
                                                 int *pnPixelSpace,
10341
                                                 GIntBig *pnLineSpace,
10342
                                                 CSLConstList papszOptions)
10343
0
{
10344
0
    const char *pszImpl = CSLFetchNameValueDef(
10345
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10346
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10347
0
        EQUAL(pszImpl, "FALSE"))
10348
0
    {
10349
0
        return nullptr;
10350
0
    }
10351
10352
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10353
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10354
0
    if (pnPixelSpace)
10355
0
        *pnPixelSpace = nPixelSpace;
10356
0
    if (pnLineSpace)
10357
0
        *pnLineSpace = nLineSpace;
10358
0
    const size_t nCacheSize =
10359
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10360
0
    const size_t nPageSizeHint =
10361
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10362
0
    const bool bSingleThreadUsage = CPLTestBool(
10363
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10364
0
    return GDALRasterBandGetVirtualMem(
10365
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10366
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10367
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10368
0
        papszOptions);
10369
0
}
10370
10371
/************************************************************************/
10372
/*                       GDALGetVirtualMemAuto()                        */
10373
/************************************************************************/
10374
10375
/**
10376
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10377
 *
10378
 * @see GDALRasterBand::GetVirtualMemAuto()
10379
 */
10380
10381
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10382
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
10383
                                     CSLConstList papszOptions)
10384
0
{
10385
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10386
10387
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10388
10389
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10390
0
                                     const_cast<char **>(papszOptions));
10391
0
}
10392
10393
/************************************************************************/
10394
/*                     GDALGetDataCoverageStatus()                      */
10395
/************************************************************************/
10396
10397
/**
10398
 * \brief Get the coverage status of a sub-window of the raster.
10399
 *
10400
 * Returns whether a sub-window of the raster contains only data, only empty
10401
 * blocks or a mix of both. This function can be used to determine quickly
10402
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10403
 * be sparse.
10404
 *
10405
 * Empty blocks are blocks that are generally not physically present in the
10406
 * file, and when read through GDAL, contain only pixels whose value is the
10407
 * nodata value when it is set, or whose value is 0 when the nodata value is
10408
 * not set.
10409
 *
10410
 * The query is done in an efficient way without reading the actual pixel
10411
 * values. If not possible, or not implemented at all by the driver,
10412
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10413
 * be returned.
10414
 *
10415
 * The values that can be returned by the function are the following,
10416
 * potentially combined with the binary or operator :
10417
 * <ul>
10418
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10419
 * GetDataCoverageStatus(). This flag should be returned together with
10420
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10421
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10422
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10423
 * the queried window. This is typically identified by the concept of missing
10424
 * block in formats that supports it.
10425
 * </li>
10426
 * </ul>
10427
 *
10428
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10429
 * should be interpreted more as hint of potential presence of data. For example
10430
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10431
 * nodata value), instead of using the missing block mechanism,
10432
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10433
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10434
 *
10435
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10436
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10437
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10438
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10439
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10440
 * the function will exit, so that you can potentially refine the requested area
10441
 * to find which particular region(s) have missing blocks.
10442
 *
10443
 * @see GDALRasterBand::GetDataCoverageStatus()
10444
 *
10445
 * @param hBand raster band
10446
 *
10447
 * @param nXOff The pixel offset to the top left corner of the region
10448
 * of the band to be queried. This would be zero to start from the left side.
10449
 *
10450
 * @param nYOff The line offset to the top left corner of the region
10451
 * of the band to be queried. This would be zero to start from the top.
10452
 *
10453
 * @param nXSize The width of the region of the band to be queried in pixels.
10454
 *
10455
 * @param nYSize The height of the region of the band to be queried in lines.
10456
 *
10457
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10458
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10459
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10460
 * as the computation of the coverage matches the mask, the computation will be
10461
 * stopped. *pdfDataPct will not be valid in that case.
10462
 *
10463
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10464
 * to the (approximate) percentage in [0,100] of pixels in the queried
10465
 * sub-window that have valid values. The implementation might not always be
10466
 * able to compute it, in which case it will be set to a negative value.
10467
 *
10468
 * @return a binary-or'ed combination of possible values
10469
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10470
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10471
 */
10472
10473
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10474
                                          int nYOff, int nXSize, int nYSize,
10475
                                          int nMaskFlagStop, double *pdfDataPct)
10476
0
{
10477
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10478
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10479
10480
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10481
10482
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10483
0
                                         nMaskFlagStop, pdfDataPct);
10484
0
}
10485
10486
/************************************************************************/
10487
/*                       GetDataCoverageStatus()                        */
10488
/************************************************************************/
10489
10490
/**
10491
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10492
 *                                           int nYOff,
10493
 *                                           int nXSize,
10494
 *                                           int nYSize,
10495
 *                                           int nMaskFlagStop,
10496
 *                                           double* pdfDataPct)
10497
 * \brief Get the coverage status of a sub-window of the raster.
10498
 *
10499
 * Returns whether a sub-window of the raster contains only data, only empty
10500
 * blocks or a mix of both. This function can be used to determine quickly
10501
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10502
 * be sparse.
10503
 *
10504
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10505
 * value when it is set, or whose value is 0 when the nodata value is not set.
10506
 *
10507
 * The query is done in an efficient way without reading the actual pixel
10508
 * values. If not possible, or not implemented at all by the driver,
10509
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10510
 * be returned.
10511
 *
10512
 * The values that can be returned by the function are the following,
10513
 * potentially combined with the binary or operator :
10514
 * <ul>
10515
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10516
 * GetDataCoverageStatus(). This flag should be returned together with
10517
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10518
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10519
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10520
 * the queried window. This is typically identified by the concept of missing
10521
 * block in formats that supports it.
10522
 * </li>
10523
 * </ul>
10524
 *
10525
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10526
 * should be interpreted more as hint of potential presence of data. For example
10527
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10528
 * nodata value), instead of using the missing block mechanism,
10529
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10530
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10531
 *
10532
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10533
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10534
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10535
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10536
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10537
 * the function will exit, so that you can potentially refine the requested area
10538
 * to find which particular region(s) have missing blocks.
10539
 *
10540
 * @see GDALGetDataCoverageStatus()
10541
 *
10542
 * @param nXOff The pixel offset to the top left corner of the region
10543
 * of the band to be queried. This would be zero to start from the left side.
10544
 *
10545
 * @param nYOff The line offset to the top left corner of the region
10546
 * of the band to be queried. This would be zero to start from the top.
10547
 *
10548
 * @param nXSize The width of the region of the band to be queried in pixels.
10549
 *
10550
 * @param nYSize The height of the region of the band to be queried in lines.
10551
 *
10552
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10553
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10554
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10555
 * as the computation of the coverage matches the mask, the computation will be
10556
 * stopped. *pdfDataPct will not be valid in that case.
10557
 *
10558
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10559
 * to the (approximate) percentage in [0,100] of pixels in the queried
10560
 * sub-window that have valid values. The implementation might not always be
10561
 * able to compute it, in which case it will be set to a negative value.
10562
 *
10563
 * @return a binary-or'ed combination of possible values
10564
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10565
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10566
 */
10567
10568
/**
10569
 * \brief Get the coverage status of a sub-window of the raster.
10570
 *
10571
 * Returns whether a sub-window of the raster contains only data, only empty
10572
 * blocks or a mix of both. This function can be used to determine quickly
10573
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10574
 * be sparse.
10575
 *
10576
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10577
 * value when it is set, or whose value is 0 when the nodata value is not set.
10578
 *
10579
 * The query is done in an efficient way without reading the actual pixel
10580
 * values. If not possible, or not implemented at all by the driver,
10581
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10582
 * be returned.
10583
 *
10584
 * The values that can be returned by the function are the following,
10585
 * potentially combined with the binary or operator :
10586
 * <ul>
10587
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10588
 * GetDataCoverageStatus(). This flag should be returned together with
10589
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10590
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10591
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10592
 * the queried window. This is typically identified by the concept of missing
10593
 * block in formats that supports it.
10594
 * </li>
10595
 * </ul>
10596
 *
10597
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10598
 * should be interpreted more as hint of potential presence of data. For example
10599
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10600
 * nodata value), instead of using the missing block mechanism,
10601
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10602
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10603
 *
10604
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10605
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10606
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10607
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10608
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10609
 * the function will exit, so that you can potentially refine the requested area
10610
 * to find which particular region(s) have missing blocks.
10611
 *
10612
 * @see GDALGetDataCoverageStatus()
10613
 *
10614
 * @param nXOff The pixel offset to the top left corner of the region
10615
 * of the band to be queried. This would be zero to start from the left side.
10616
 *
10617
 * @param nYOff The line offset to the top left corner of the region
10618
 * of the band to be queried. This would be zero to start from the top.
10619
 *
10620
 * @param nXSize The width of the region of the band to be queried in pixels.
10621
 *
10622
 * @param nYSize The height of the region of the band to be queried in lines.
10623
 *
10624
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10625
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10626
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10627
 * as the computation of the coverage matches the mask, the computation will be
10628
 * stopped. *pdfDataPct will not be valid in that case.
10629
 *
10630
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10631
 * to the (approximate) percentage in [0,100] of pixels in the queried
10632
 * sub-window that have valid values. The implementation might not always be
10633
 * able to compute it, in which case it will be set to a negative value.
10634
 *
10635
 * @return a binary-or'ed combination of possible values
10636
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10637
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10638
 */
10639
10640
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10641
                                          int nYSize, int nMaskFlagStop,
10642
                                          double *pdfDataPct)
10643
0
{
10644
0
    if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10645
0
        nYSize > nRasterYSize - nYOff)
10646
0
    {
10647
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10648
0
        if (pdfDataPct)
10649
0
            *pdfDataPct = 0.0;
10650
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10651
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
10652
0
    }
10653
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10654
0
                                  pdfDataPct);
10655
0
}
10656
10657
/************************************************************************/
10658
/*                       IGetDataCoverageStatus()                       */
10659
/************************************************************************/
10660
10661
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10662
                                           int /*nXSize*/, int /*nYSize*/,
10663
                                           int /*nMaskFlagStop*/,
10664
                                           double *pdfDataPct)
10665
0
{
10666
0
    if (pdfDataPct != nullptr)
10667
0
        *pdfDataPct = 100.0;
10668
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10669
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
10670
0
}
10671
10672
//! @cond Doxygen_Suppress
10673
/************************************************************************/
10674
/*                           EnterReadWrite()                           */
10675
/************************************************************************/
10676
10677
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10678
0
{
10679
0
    if (poDS != nullptr)
10680
0
        return poDS->EnterReadWrite(eRWFlag);
10681
0
    return FALSE;
10682
0
}
10683
10684
/************************************************************************/
10685
/*                           LeaveReadWrite()                           */
10686
/************************************************************************/
10687
10688
void GDALRasterBand::LeaveReadWrite()
10689
0
{
10690
0
    if (poDS != nullptr)
10691
0
        poDS->LeaveReadWrite();
10692
0
}
10693
10694
/************************************************************************/
10695
/*                             InitRWLock()                             */
10696
/************************************************************************/
10697
10698
void GDALRasterBand::InitRWLock()
10699
0
{
10700
0
    if (poDS != nullptr)
10701
0
        poDS->InitRWLock();
10702
0
}
10703
10704
//! @endcond
10705
10706
// clang-format off
10707
10708
/**
10709
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10710
 * \brief Set metadata.
10711
 *
10712
 * CAUTION: depending on the format, older values of the updated information
10713
 * might still be found in the file in a "ghost" state, even if no longer
10714
 * accessible through the GDAL API. This is for example the case of the GTiff
10715
 * format (this is not a exhaustive list)
10716
 *
10717
 * The C function GDALSetMetadata() does the same thing as this method.
10718
 *
10719
 * @param papszMetadata the metadata in name=value string list format to
10720
 * apply.
10721
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
10722
 * domain.
10723
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10724
 * metadata has been accepted, but is likely not maintained persistently
10725
 * by the underlying object between sessions.
10726
 */
10727
10728
/**
10729
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10730
 * \brief Set single metadata item.
10731
 *
10732
 * CAUTION: depending on the format, older values of the updated information
10733
 * might still be found in the file in a "ghost" state, even if no longer
10734
 * accessible through the GDAL API. This is for example the case of the GTiff
10735
 * format (this is not a exhaustive list)
10736
 *
10737
 * The C function GDALSetMetadataItem() does the same thing as this method.
10738
 *
10739
 * @param pszName the key for the metadata item to fetch.
10740
 * @param pszValue the value to assign to the key.
10741
 * @param pszDomain the domain to set within, use NULL for the default domain.
10742
 *
10743
 * @return CE_None on success, or an error code on failure.
10744
 */
10745
10746
// clang-format on
10747
10748
//! @cond Doxygen_Suppress
10749
/************************************************************************/
10750
/*                  EnablePixelTypeSignedByteWarning()                  */
10751
/************************************************************************/
10752
10753
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10754
0
{
10755
0
    m_bEnablePixelTypeSignedByteWarning = b;
10756
0
}
10757
10758
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10759
0
{
10760
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10761
0
}
10762
10763
//! @endcond
10764
10765
/************************************************************************/
10766
/*                          GetMetadataItem()                           */
10767
/************************************************************************/
10768
10769
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10770
                                            const char *pszDomain)
10771
0
{
10772
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10773
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10774
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10775
0
        EQUAL(pszName, "PIXELTYPE"))
10776
0
    {
10777
0
        CPLError(CE_Warning, CPLE_AppDefined,
10778
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10779
0
                 "used to signal signed 8-bit raster. Change your code to "
10780
0
                 "test for the new GDT_Int8 data type instead.");
10781
0
    }
10782
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10783
0
}
10784
10785
/************************************************************************/
10786
/*                            WindowIterator                            */
10787
/************************************************************************/
10788
10789
//! @cond Doxygen_Suppress
10790
10791
GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10792
                                               int nRasterYSize,
10793
                                               int nBlockXSize, int nBlockYSize,
10794
                                               int nRow, int nCol)
10795
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10796
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10797
0
      m_col(nCol)
10798
0
{
10799
0
}
10800
10801
bool GDALRasterBand::WindowIterator::operator==(
10802
    const WindowIterator &other) const
10803
0
{
10804
0
    return m_row == other.m_row && m_col == other.m_col &&
10805
0
           m_nRasterXSize == other.m_nRasterXSize &&
10806
0
           m_nRasterYSize == other.m_nRasterYSize &&
10807
0
           m_nBlockXSize == other.m_nBlockXSize &&
10808
0
           m_nBlockYSize == other.m_nBlockYSize;
10809
0
}
10810
10811
bool GDALRasterBand::WindowIterator::operator!=(
10812
    const WindowIterator &other) const
10813
0
{
10814
0
    return !(*this == other);
10815
0
}
10816
10817
GDALRasterBand::WindowIterator::value_type
10818
GDALRasterBand::WindowIterator::operator*() const
10819
0
{
10820
0
    GDALRasterWindow ret;
10821
0
    ret.nXOff = m_col * m_nBlockXSize;
10822
0
    ret.nYOff = m_row * m_nBlockYSize;
10823
0
    ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10824
0
    ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10825
10826
0
    return ret;
10827
0
}
10828
10829
GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10830
0
{
10831
0
    m_col++;
10832
0
    if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10833
0
    {
10834
0
        m_col = 0;
10835
0
        m_row++;
10836
0
    }
10837
0
    return *this;
10838
0
}
10839
10840
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10841
    const GDALRasterBand &band, size_t maxSize)
10842
0
    : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10843
0
                            band.nBlockYSize, maxSize)
10844
0
{
10845
0
}
10846
10847
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10848
    const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10849
0
    : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10850
0
                            std::min(band1.GetYSize(), band2.GetYSize()),
10851
0
                            std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10852
0
                            std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10853
0
                            maxSize)
10854
0
{
10855
0
    if (band1.GetXSize() != band2.GetXSize() ||
10856
0
        band1.GetYSize() != band2.GetYSize())
10857
0
    {
10858
0
        CPLError(CE_Warning, CPLE_AppDefined,
10859
0
                 "WindowIteratorWrapper called on bands of different "
10860
0
                 "dimensions. Selecting smallest one");
10861
0
    }
10862
0
}
10863
10864
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10865
                                                             int nRasterYSize,
10866
                                                             int nBlockXSize,
10867
                                                             int nBlockYSize,
10868
                                                             size_t maxSize)
10869
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10870
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10871
0
{
10872
#ifdef CSA_BUILD
10873
    assert(this);
10874
#endif
10875
0
    int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10876
0
    int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10877
10878
0
    if (nXSize < 1 || nYSize < 1)
10879
0
    {
10880
        // If invalid block size is reported, assume scanlines
10881
0
        nXSize = m_nRasterXSize;
10882
0
        nYSize = 1;
10883
0
    }
10884
10885
0
    if (maxSize == 0)
10886
0
    {
10887
0
        m_nBlockXSize = nXSize;
10888
0
        m_nBlockYSize = nYSize;
10889
0
        return;
10890
0
    }
10891
10892
0
    const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10893
0
    const double dfBlocksPerChunk =
10894
0
        static_cast<double>(maxSize) /
10895
0
        (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10896
10897
0
    if (dfBlocksPerChunk < dfBlocksPerRow)
10898
0
    {
10899
0
        m_nBlockXSize = static_cast<int>(std::min<double>(
10900
0
            m_nRasterXSize,
10901
0
            nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10902
0
        m_nBlockYSize = nYSize;
10903
0
    }
10904
0
    else
10905
0
    {
10906
0
        m_nBlockXSize = m_nRasterXSize;
10907
0
        m_nBlockYSize = static_cast<int>(std::min<double>(
10908
0
            m_nRasterYSize,
10909
0
            nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10910
0
    }
10911
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
10912
    {
10913
        if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10914
        {
10915
            m_nBlockXSize = m_nRasterXSize;
10916
            m_nBlockYSize = 1;
10917
        }
10918
    }
10919
0
}
10920
10921
GDALRasterBand::WindowIterator
10922
GDALRasterBand::WindowIteratorWrapper::begin() const
10923
0
{
10924
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10925
0
                          m_nBlockYSize, 0, 0);
10926
0
}
10927
10928
GDALRasterBand::WindowIterator
10929
GDALRasterBand::WindowIteratorWrapper::end() const
10930
0
{
10931
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10932
0
                          m_nBlockYSize,
10933
0
                          DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10934
0
}
10935
10936
uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10937
0
{
10938
0
    return static_cast<uint64_t>(
10939
0
               cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10940
0
           static_cast<uint64_t>(
10941
0
               cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10942
0
}
10943
10944
//! @endcond
10945
10946
/** Return an object whose begin() and end() methods can be used to iterate
10947
 *  over GDALRasterWindow objects that are aligned with blocks in this raster
10948
 *  band. The iteration order is from left to right, then from top to bottom.
10949
 *
10950
\code{.cpp}
10951
    std::vector<double> pixelValues;
10952
    for (const auto& window : poBand->IterateWindows()) {
10953
        CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10954
                                         window.nXSize, window.nYSize);
10955
        // check eErr
10956
    }
10957
\endcode
10958
 *
10959
 *
10960
 *  @param maxSize The maximum number of pixels in each window. If set to
10961
 *         zero (the default), or a number smaller than the block size,
10962
 *         the window size will be the same as the block size.
10963
 *  @since GDAL 3.12
10964
 */
10965
GDALRasterBand::WindowIteratorWrapper
10966
GDALRasterBand::IterateWindows(size_t maxSize) const
10967
0
{
10968
0
    return WindowIteratorWrapper(*this, maxSize);
10969
0
}
10970
10971
/************************************************************************/
10972
/*                MayMultiBlockReadingBeMultiThreaded()                 */
10973
/************************************************************************/
10974
10975
/** Return whether a RasterIO(GF_Read) request spanning over multiple
10976
 * blocks may be accelerated internally using multi-threading.
10977
 *
10978
 * This can be used to determine the best chunk size to read a raster band.
10979
 *
10980
 * Note that such optimizations may require that the window is perfectly aligned
10981
 * on block boundaries and does not involve resampling or data type translation
10982
 * occurs, etc.
10983
 *
10984
 * @since GDAL 3.13
10985
 */
10986
bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
10987
0
{
10988
0
    return false;
10989
0
}
10990
10991
/************************************************************************/
10992
/*                      GDALMDArrayFromRasterBand                       */
10993
/************************************************************************/
10994
10995
class GDALMDArrayFromRasterBand final : public GDALMDArray
10996
{
10997
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10998
10999
    GDALDataset *m_poDS;
11000
    GDALRasterBand *m_poBand;
11001
    GDALExtendedDataType m_dt;
11002
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11003
    std::string m_osUnit;
11004
    std::vector<GByte> m_pabyNoData{};
11005
    std::shared_ptr<GDALMDArray> m_varX{};
11006
    std::shared_ptr<GDALMDArray> m_varY{};
11007
    std::string m_osFilename{};
11008
    mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11009
11010
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11011
                   const size_t *count, const GInt64 *arrayStep,
11012
                   const GPtrDiff_t *bufferStride,
11013
                   const GDALExtendedDataType &bufferDataType,
11014
                   void *pBuffer) const;
11015
11016
  protected:
11017
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
11018
0
        : GDALAbstractMDArray(std::string(),
11019
0
                              std::string(poDS->GetDescription()) +
11020
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
11021
0
          GDALMDArray(std::string(),
11022
0
                      std::string(poDS->GetDescription()) +
11023
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
11024
0
          m_poDS(poDS), m_poBand(poBand),
11025
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
11026
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
11027
0
    {
11028
0
        m_poDS->Reference();
11029
11030
0
        int bHasNoData = false;
11031
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
11032
0
        {
11033
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
11034
0
            if (bHasNoData)
11035
0
            {
11036
0
                m_pabyNoData.resize(m_dt.GetSize());
11037
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
11038
0
                                m_dt.GetNumericDataType(), 0, 1);
11039
0
            }
11040
0
        }
11041
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
11042
0
        {
11043
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
11044
0
            if (bHasNoData)
11045
0
            {
11046
0
                m_pabyNoData.resize(m_dt.GetSize());
11047
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
11048
0
                                m_dt.GetNumericDataType(), 0, 1);
11049
0
            }
11050
0
        }
11051
0
        else
11052
0
        {
11053
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
11054
0
            if (bHasNoData)
11055
0
            {
11056
0
                m_pabyNoData.resize(m_dt.GetSize());
11057
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
11058
0
                                m_dt.GetNumericDataType(), 0, 1);
11059
0
            }
11060
0
        }
11061
11062
0
        const int nXSize = poBand->GetXSize();
11063
0
        const int nYSize = poBand->GetYSize();
11064
11065
0
        auto poSRS = m_poDS->GetSpatialRef();
11066
0
        std::string osTypeY;
11067
0
        std::string osTypeX;
11068
0
        std::string osDirectionY;
11069
0
        std::string osDirectionX;
11070
0
        if (poSRS && poSRS->GetAxesCount() == 2)
11071
0
        {
11072
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11073
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
11074
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
11075
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
11076
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
11077
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11078
0
            {
11079
0
                if (mapping == std::vector<int>{1, 2})
11080
0
                {
11081
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11082
0
                    osDirectionY = "NORTH";
11083
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11084
0
                    osDirectionX = "EAST";
11085
0
                }
11086
0
            }
11087
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11088
0
            {
11089
0
                if (mapping == std::vector<int>{2, 1})
11090
0
                {
11091
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11092
0
                    osDirectionY = "NORTH";
11093
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11094
0
                    osDirectionX = "EAST";
11095
0
                }
11096
0
            }
11097
0
        }
11098
11099
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11100
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
11101
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
11102
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
11103
11104
0
        GDALGeoTransform gt;
11105
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
11106
0
        {
11107
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
11108
0
                "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
11109
0
            m_dims[1]->SetIndexingVariable(m_varX);
11110
11111
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
11112
0
                "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
11113
0
            m_dims[0]->SetIndexingVariable(m_varY);
11114
0
        }
11115
0
    }
11116
11117
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11118
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11119
               const GDALExtendedDataType &bufferDataType,
11120
               void *pDstBuffer) const override;
11121
11122
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11123
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11124
                const GDALExtendedDataType &bufferDataType,
11125
                const void *pSrcBuffer) override
11126
0
    {
11127
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11128
0
                         bufferStride, bufferDataType,
11129
0
                         const_cast<void *>(pSrcBuffer));
11130
0
    }
11131
11132
  public:
11133
    ~GDALMDArrayFromRasterBand() override
11134
0
    {
11135
0
        m_poDS->ReleaseRef();
11136
0
    }
11137
11138
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11139
                                               GDALRasterBand *poBand)
11140
0
    {
11141
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11142
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
11143
0
        array->SetSelf(array);
11144
0
        return array;
11145
0
    }
11146
11147
    bool IsWritable() const override
11148
0
    {
11149
0
        return m_poDS->GetAccess() == GA_Update;
11150
0
    }
11151
11152
    const std::string &GetFilename() const override
11153
0
    {
11154
0
        return m_osFilename;
11155
0
    }
11156
11157
    const std::vector<std::shared_ptr<GDALDimension>> &
11158
    GetDimensions() const override
11159
0
    {
11160
0
        return m_dims;
11161
0
    }
11162
11163
    const GDALExtendedDataType &GetDataType() const override
11164
0
    {
11165
0
        return m_dt;
11166
0
    }
11167
11168
    const std::string &GetUnit() const override
11169
0
    {
11170
0
        return m_osUnit;
11171
0
    }
11172
11173
    const void *GetRawNoDataValue() const override
11174
0
    {
11175
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11176
0
    }
11177
11178
    double GetOffset(bool *pbHasOffset,
11179
                     GDALDataType *peStorageType) const override
11180
0
    {
11181
0
        int bHasOffset = false;
11182
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
11183
0
        if (pbHasOffset)
11184
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11185
0
        if (peStorageType)
11186
0
            *peStorageType = GDT_Unknown;
11187
0
        return dfRes;
11188
0
    }
11189
11190
    double GetScale(bool *pbHasScale,
11191
                    GDALDataType *peStorageType) const override
11192
0
    {
11193
0
        int bHasScale = false;
11194
0
        double dfRes = m_poBand->GetScale(&bHasScale);
11195
0
        if (pbHasScale)
11196
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
11197
0
        if (peStorageType)
11198
0
            *peStorageType = GDT_Unknown;
11199
0
        return dfRes;
11200
0
    }
11201
11202
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11203
0
    {
11204
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
11205
0
        if (!poSrcSRS)
11206
0
            return nullptr;
11207
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11208
11209
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11210
0
        constexpr int iYDim = 0;
11211
0
        constexpr int iXDim = 1;
11212
0
        for (auto &m : axisMapping)
11213
0
        {
11214
0
            if (m == 1)
11215
0
                m = iXDim + 1;
11216
0
            else if (m == 2)
11217
0
                m = iYDim + 1;
11218
0
            else
11219
0
                m = 0;
11220
0
        }
11221
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11222
0
        return poSRS;
11223
0
    }
11224
11225
    std::vector<GUInt64> GetBlockSize() const override
11226
0
    {
11227
0
        int nBlockXSize = 0;
11228
0
        int nBlockYSize = 0;
11229
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11230
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11231
0
                                    static_cast<GUInt64>(nBlockXSize)};
11232
0
    }
11233
11234
    std::vector<std::shared_ptr<GDALAttribute>>
11235
    GetAttributes(CSLConstList) const override
11236
0
    {
11237
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
11238
0
        auto papszMD = m_poBand->GetMetadata();
11239
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
11240
0
        {
11241
0
            char *pszKey = nullptr;
11242
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11243
0
            if (pszKey && pszValue)
11244
0
            {
11245
0
                res.emplace_back(
11246
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11247
0
            }
11248
0
            CPLFree(pszKey);
11249
0
        }
11250
0
        return res;
11251
0
    }
11252
11253
    int GetOverviewCount() const override
11254
0
    {
11255
0
        return m_poBand->GetOverviewCount();
11256
0
    }
11257
11258
    std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11259
0
    {
11260
0
        const int nOverviews = GetOverviewCount();
11261
0
        if (idx < 0 || idx >= nOverviews)
11262
0
            return nullptr;
11263
0
        m_apoOverviews.resize(nOverviews);
11264
0
        if (!m_apoOverviews[idx])
11265
0
        {
11266
0
            if (auto poOvrBand = m_poBand->GetOverview(idx))
11267
0
            {
11268
0
                if (auto poOvrDS = poOvrBand->GetDataset())
11269
0
                {
11270
0
                    m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11271
0
                }
11272
0
            }
11273
0
        }
11274
0
        return m_apoOverviews[idx];
11275
0
    }
11276
};
11277
11278
bool GDALMDArrayFromRasterBand::IRead(
11279
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11280
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11281
    void *pDstBuffer) const
11282
0
{
11283
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11284
0
                     bufferDataType, pDstBuffer);
11285
0
}
11286
11287
/************************************************************************/
11288
/*                             ReadWrite()                              */
11289
/************************************************************************/
11290
11291
bool GDALMDArrayFromRasterBand::ReadWrite(
11292
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11293
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11294
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11295
0
{
11296
0
    constexpr size_t iDimX = 1;
11297
0
    constexpr size_t iDimY = 0;
11298
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11299
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
11300
0
                                  bufferDataType, pBuffer);
11301
0
}
11302
11303
/************************************************************************/
11304
/*                       GDALMDRasterIOFromBand()                       */
11305
/************************************************************************/
11306
11307
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11308
                            size_t iDimX, size_t iDimY,
11309
                            const GUInt64 *arrayStartIdx, const size_t *count,
11310
                            const GInt64 *arrayStep,
11311
                            const GPtrDiff_t *bufferStride,
11312
                            const GDALExtendedDataType &bufferDataType,
11313
                            void *pBuffer)
11314
0
{
11315
0
    const auto eDT(bufferDataType.GetNumericDataType());
11316
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11317
0
    const int nX =
11318
0
        arrayStep[iDimX] > 0
11319
0
            ? static_cast<int>(arrayStartIdx[iDimX])
11320
0
            : static_cast<int>(arrayStartIdx[iDimX] -
11321
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
11322
0
    const int nY =
11323
0
        arrayStep[iDimY] > 0
11324
0
            ? static_cast<int>(arrayStartIdx[iDimY])
11325
0
            : static_cast<int>(arrayStartIdx[iDimY] -
11326
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
11327
0
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
11328
0
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
11329
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11330
0
    int nStrideXSign = 1;
11331
0
    if (arrayStep[iDimX] < 0)
11332
0
    {
11333
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11334
0
        nStrideXSign = -1;
11335
0
    }
11336
0
    int nStrideYSign = 1;
11337
0
    if (arrayStep[iDimY] < 0)
11338
0
    {
11339
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11340
0
        nStrideYSign = -1;
11341
0
    }
11342
11343
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11344
0
                            static_cast<int>(count[iDimX]),
11345
0
                            static_cast<int>(count[iDimY]), eDT,
11346
0
                            static_cast<GSpacing>(
11347
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
11348
0
                            static_cast<GSpacing>(
11349
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
11350
0
                            nullptr) == CE_None;
11351
0
}
11352
11353
/************************************************************************/
11354
/*                             AsMDArray()                              */
11355
/************************************************************************/
11356
11357
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11358
 *
11359
 * The band must be linked to a GDALDataset. If this dataset is not already
11360
 * marked as shared, it will be, so that the returned array holds a reference
11361
 * to it.
11362
 *
11363
 * If the dataset has a geotransform attached, the X and Y dimensions of the
11364
 * returned array will have an associated indexing variable.
11365
 *
11366
 * This is the same as the C function GDALRasterBandAsMDArray().
11367
 *
11368
 * The "reverse" method is GDALMDArray::AsClassicDataset().
11369
 *
11370
 * @return a new array, or nullptr.
11371
 *
11372
 * @since GDAL 3.1
11373
 */
11374
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11375
0
{
11376
0
    if (!poDS)
11377
0
    {
11378
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11379
0
        return nullptr;
11380
0
    }
11381
0
    if (!poDS->GetShared())
11382
0
    {
11383
0
        poDS->MarkAsShared();
11384
0
    }
11385
0
    return GDALMDArrayFromRasterBand::Create(
11386
0
        poDS, const_cast<GDALRasterBand *>(this));
11387
0
}
11388
11389
/************************************************************************/
11390
/*                         InterpolateAtPoint()                         */
11391
/************************************************************************/
11392
11393
/**
11394
 * \brief Interpolates the value between pixels using a resampling algorithm,
11395
 * taking pixel/line coordinates as input.
11396
 *
11397
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11398
 * @param dfLine line coordinate as a double, where interpolation should be done.
11399
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11400
 * @param pdfRealValue pointer to real part of interpolated value
11401
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11402
 *
11403
 * @return CE_None on success, or an error code on failure.
11404
 * @since GDAL 3.10
11405
 */
11406
11407
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11408
                                          GDALRIOResampleAlg eInterpolation,
11409
                                          double *pdfRealValue,
11410
                                          double *pdfImagValue) const
11411
0
{
11412
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
11413
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11414
0
        eInterpolation != GRIORA_CubicSpline)
11415
0
    {
11416
0
        CPLError(CE_Failure, CPLE_AppDefined,
11417
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
11418
0
                 "methods "
11419
0
                 "allowed");
11420
11421
0
        return CE_Failure;
11422
0
    }
11423
11424
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11425
0
    if (!m_poPointsCache)
11426
0
        m_poPointsCache = new GDALDoublePointsCache();
11427
11428
0
    const bool res =
11429
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11430
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
11431
11432
0
    return res ? CE_None : CE_Failure;
11433
0
}
11434
11435
/************************************************************************/
11436
/*                    GDALRasterInterpolateAtPoint()                    */
11437
/************************************************************************/
11438
11439
/**
11440
 * \brief Interpolates the value between pixels using
11441
 * a resampling algorithm
11442
 *
11443
 * @see GDALRasterBand::InterpolateAtPoint()
11444
 * @since GDAL 3.10
11445
 */
11446
11447
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11448
                                    double dfLine,
11449
                                    GDALRIOResampleAlg eInterpolation,
11450
                                    double *pdfRealValue, double *pdfImagValue)
11451
0
{
11452
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11453
11454
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11455
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11456
0
                                      pdfRealValue, pdfImagValue);
11457
0
}
11458
11459
/************************************************************************/
11460
/*                      InterpolateAtGeolocation()                      */
11461
/************************************************************************/
11462
11463
/**
11464
 * \brief Interpolates the value between pixels using a resampling algorithm,
11465
 * taking georeferenced coordinates as input.
11466
 *
11467
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11468
 * must be in the "natural" SRS of the dataset, that is the one returned by
11469
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11470
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11471
 * array (generally WGS 84) if there is a geolocation array.
11472
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11473
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11474
 * be a easting, and dfGeolocY a northing.
11475
 *
11476
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11477
 * expressed in that CRS, and that tuple must be conformant with the
11478
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11479
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11480
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11481
 * before calling this method, and in that case, dfGeolocX must be a longitude
11482
 * or an easting value, and dfGeolocX a latitude or a northing value.
11483
 *
11484
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11485
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11486
 * it for details on how that transformation is done.
11487
 *
11488
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11489
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11490
 * where interpolation should be done.
11491
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11492
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11493
 * where interpolation should be done.
11494
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11495
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11496
 * @param pdfRealValue pointer to real part of interpolated value
11497
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11498
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11499
 *
11500
 * @return CE_None on success, or an error code on failure.
11501
 * @since GDAL 3.11
11502
 */
11503
11504
CPLErr GDALRasterBand::InterpolateAtGeolocation(
11505
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11506
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11507
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
11508
0
{
11509
0
    double dfPixel;
11510
0
    double dfLine;
11511
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11512
0
                                     &dfLine,
11513
0
                                     papszTransformerOptions) != CE_None)
11514
0
    {
11515
0
        return CE_Failure;
11516
0
    }
11517
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11518
0
                              pdfImagValue);
11519
0
}
11520
11521
/************************************************************************/
11522
/*                 GDALRasterInterpolateAtGeolocation()                 */
11523
/************************************************************************/
11524
11525
/**
11526
 * \brief Interpolates the value between pixels using a resampling algorithm,
11527
 * taking georeferenced coordinates as input.
11528
 *
11529
 * @see GDALRasterBand::InterpolateAtGeolocation()
11530
 * @since GDAL 3.11
11531
 */
11532
11533
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11534
                                          double dfGeolocX, double dfGeolocY,
11535
                                          OGRSpatialReferenceH hSRS,
11536
                                          GDALRIOResampleAlg eInterpolation,
11537
                                          double *pdfRealValue,
11538
                                          double *pdfImagValue,
11539
                                          CSLConstList papszTransformerOptions)
11540
0
{
11541
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11542
11543
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11544
0
    return poBand->InterpolateAtGeolocation(
11545
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11546
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11547
0
}
11548
11549
/************************************************************************/
11550
/*                   GDALRasterBand::SplitRasterIO()                    */
11551
/************************************************************************/
11552
11553
//! @cond Doxygen_Suppress
11554
11555
/** Implements IRasterIO() by dividing the request in 2.
11556
 *
11557
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11558
 *
11559
 * Return CE_Warning if the split could not be done, CE_None in case of
11560
 * success and CE_Failure in case of error.
11561
 *
11562
 * @since 3.12
11563
 */
11564
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11565
                                     [[maybe_unused]] int nXSize,
11566
                                     [[maybe_unused]] int nYSize, void *pData,
11567
                                     int nBufXSize, int nBufYSize,
11568
                                     GDALDataType eBufType,
11569
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
11570
                                     GDALRasterIOExtraArg *psExtraArg)
11571
0
{
11572
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11573
11574
0
    GByte *pabyData = static_cast<GByte *>(pData);
11575
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11576
0
    {
11577
0
        GDALRasterIOExtraArg sArg;
11578
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11579
0
        const int nHalfHeight = nBufYSize / 2;
11580
11581
0
        sArg.pfnProgress = GDALScaledProgress;
11582
0
        sArg.pProgressData = GDALCreateScaledProgress(
11583
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11584
0
        if (sArg.pProgressData == nullptr)
11585
0
            sArg.pfnProgress = nullptr;
11586
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11587
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
11588
0
                                nPixelSpace, nLineSpace, &sArg);
11589
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11590
11591
0
        if (eErr == CE_None)
11592
0
        {
11593
0
            sArg.pfnProgress = GDALScaledProgress;
11594
0
            sArg.pProgressData = GDALCreateScaledProgress(
11595
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11596
0
            if (sArg.pProgressData == nullptr)
11597
0
                sArg.pfnProgress = nullptr;
11598
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11599
0
                             nBufYSize - nHalfHeight,
11600
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
11601
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11602
0
                             nLineSpace, &sArg);
11603
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11604
0
        }
11605
0
        return eErr;
11606
0
    }
11607
0
    else if (nBufXSize >= 2)
11608
0
    {
11609
0
        GDALRasterIOExtraArg sArg;
11610
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11611
0
        const int nHalfWidth = nBufXSize / 2;
11612
11613
0
        sArg.pfnProgress = GDALScaledProgress;
11614
0
        sArg.pProgressData = GDALCreateScaledProgress(
11615
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11616
0
        if (sArg.pProgressData == nullptr)
11617
0
            sArg.pfnProgress = nullptr;
11618
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11619
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
11620
0
                                nPixelSpace, nLineSpace, &sArg);
11621
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11622
11623
0
        if (eErr == CE_None)
11624
0
        {
11625
0
            sArg.pfnProgress = GDALScaledProgress;
11626
0
            sArg.pProgressData = GDALCreateScaledProgress(
11627
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11628
0
            if (sArg.pProgressData == nullptr)
11629
0
                sArg.pfnProgress = nullptr;
11630
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11631
0
                             nBufXSize - nHalfWidth, nBufYSize,
11632
0
                             pabyData + nHalfWidth * nPixelSpace,
11633
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
11634
0
                             nPixelSpace, nLineSpace, &sArg);
11635
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11636
0
        }
11637
0
        return eErr;
11638
0
    }
11639
11640
0
    return CE_Warning;
11641
0
}
11642
11643
//! @endcond
11644
11645
/************************************************************************/
11646
/*                      ThrowIfNotSameDimensions()                      */
11647
/************************************************************************/
11648
11649
//! @cond Doxygen_Suppress
11650
/* static */
11651
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11652
                                              const GDALRasterBand &second)
11653
0
{
11654
0
    if (first.GetXSize() != second.GetXSize() ||
11655
0
        first.GetYSize() != second.GetYSize())
11656
0
    {
11657
0
        throw std::runtime_error("Bands do not have the same dimensions");
11658
0
    }
11659
0
}
11660
11661
//! @endcond
11662
11663
/************************************************************************/
11664
/*                       GDALRasterBandUnaryOp()                        */
11665
/************************************************************************/
11666
11667
/** Apply a unary operation on this band.
11668
 *
11669
 * The resulting band is lazy evaluated. A reference is taken on the input
11670
 * dataset.
11671
 *
11672
 * @since 3.12
11673
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11674
 */
11675
GDALComputedRasterBandH
11676
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11677
                      GDALRasterAlgebraUnaryOperation eOp)
11678
0
{
11679
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11680
0
    GDALComputedRasterBand::Operation cppOp{};
11681
0
    switch (eOp)
11682
0
    {
11683
0
        case GRAUO_LOGICAL_NOT:
11684
0
            return new GDALComputedRasterBand(
11685
0
                GDALComputedRasterBand::Operation::OP_NE,
11686
0
                *(GDALRasterBand::FromHandle(hBand)), true);
11687
0
        case GRAUO_ABS:
11688
0
            cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11689
0
            break;
11690
0
        case GRAUO_SQRT:
11691
0
            cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11692
0
            break;
11693
0
        case GRAUO_LOG:
11694
0
#ifndef HAVE_MUPARSER
11695
0
            CPLError(
11696
0
                CE_Failure, CPLE_NotSupported,
11697
0
                "log(band) not available on a GDAL build without muparser");
11698
0
            return nullptr;
11699
#else
11700
            cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11701
            break;
11702
#endif
11703
0
        case GRAUO_LOG10:
11704
0
            cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11705
0
            break;
11706
0
    }
11707
0
    return new GDALComputedRasterBand(cppOp,
11708
0
                                      *(GDALRasterBand::FromHandle(hBand)));
11709
0
}
11710
11711
/************************************************************************/
11712
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
11713
/************************************************************************/
11714
11715
static GDALComputedRasterBand::Operation
11716
ConvertGDALRasterAlgebraBinaryOperationToCpp(
11717
    GDALRasterAlgebraBinaryOperation eOp)
11718
0
{
11719
0
    switch (eOp)
11720
0
    {
11721
0
        case GRABO_ADD:
11722
0
            return GDALComputedRasterBand::Operation::OP_ADD;
11723
0
        case GRABO_SUB:
11724
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11725
0
        case GRABO_MUL:
11726
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11727
0
        case GRABO_DIV:
11728
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
11729
0
        case GRABO_GT:
11730
0
            return GDALComputedRasterBand::Operation::OP_GT;
11731
0
        case GRABO_GE:
11732
0
            return GDALComputedRasterBand::Operation::OP_GE;
11733
0
        case GRABO_LT:
11734
0
            return GDALComputedRasterBand::Operation::OP_LT;
11735
0
        case GRABO_LE:
11736
0
            return GDALComputedRasterBand::Operation::OP_LE;
11737
0
        case GRABO_EQ:
11738
0
            return GDALComputedRasterBand::Operation::OP_EQ;
11739
0
        case GRABO_NE:
11740
0
            break;
11741
0
        case GRABO_LOGICAL_AND:
11742
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11743
0
        case GRABO_LOGICAL_OR:
11744
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11745
0
        case GRABO_POW:
11746
0
            return GDALComputedRasterBand::Operation::OP_POW;
11747
0
    }
11748
0
    return GDALComputedRasterBand::Operation::OP_NE;
11749
0
}
11750
11751
/************************************************************************/
11752
/*                     GDALRasterBandBinaryOpBand()                     */
11753
/************************************************************************/
11754
11755
/** Apply a binary operation on this band with another one.
11756
 *
11757
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11758
 * "hBand1 - hBand2".
11759
 *
11760
 * The resulting band is lazy evaluated. A reference is taken on both input
11761
 * datasets.
11762
 *
11763
 * @since 3.12
11764
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11765
 */
11766
GDALComputedRasterBandH
11767
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11768
                           GDALRasterAlgebraBinaryOperation eOp,
11769
                           GDALRasterBandH hOtherBand)
11770
0
{
11771
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11772
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11773
0
#ifndef HAVE_MUPARSER
11774
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11775
0
    {
11776
0
        CPLError(
11777
0
            CE_Failure, CPLE_NotSupported,
11778
0
            "Band comparison operators not available on a GDAL build without "
11779
0
            "muparser");
11780
0
        return nullptr;
11781
0
    }
11782
0
    else if (eOp == GRABO_POW)
11783
0
    {
11784
0
        CPLError(
11785
0
            CE_Failure, CPLE_NotSupported,
11786
0
            "pow(band, band) not available on a GDAL build without muparser");
11787
0
        return nullptr;
11788
0
    }
11789
0
#endif
11790
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11791
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11792
0
    try
11793
0
    {
11794
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11795
0
    }
11796
0
    catch (const std::exception &e)
11797
0
    {
11798
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11799
0
        return nullptr;
11800
0
    }
11801
0
    return new GDALComputedRasterBand(
11802
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11803
0
        secondBand);
11804
0
}
11805
11806
/************************************************************************/
11807
/*                    GDALRasterBandBinaryOpDouble()                    */
11808
/************************************************************************/
11809
11810
/** Apply a binary operation on this band with a constant
11811
 *
11812
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11813
 * "hBand - constant".
11814
 *
11815
 * The resulting band is lazy evaluated. A reference is taken on the input
11816
 * dataset.
11817
 *
11818
 * @since 3.12
11819
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11820
 */
11821
GDALComputedRasterBandH
11822
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11823
                             GDALRasterAlgebraBinaryOperation eOp,
11824
                             double constant)
11825
0
{
11826
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11827
0
#ifndef HAVE_MUPARSER
11828
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11829
0
    {
11830
0
        CPLError(
11831
0
            CE_Failure, CPLE_NotSupported,
11832
0
            "Band comparison operators not available on a GDAL build without "
11833
0
            "muparser");
11834
0
        return nullptr;
11835
0
    }
11836
0
#endif
11837
0
    return new GDALComputedRasterBand(
11838
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11839
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
11840
0
}
11841
11842
/************************************************************************/
11843
/*                 GDALRasterBandBinaryOpDoubleToBand()                 */
11844
/************************************************************************/
11845
11846
/** Apply a binary operation on the constant with this band
11847
 *
11848
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11849
 * "constant - hBand".
11850
 *
11851
 * The resulting band is lazy evaluated. A reference is taken on the input
11852
 * dataset.
11853
 *
11854
 * @since 3.12
11855
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11856
 */
11857
GDALComputedRasterBandH
11858
GDALRasterBandBinaryOpDoubleToBand(double constant,
11859
                                   GDALRasterAlgebraBinaryOperation eOp,
11860
                                   GDALRasterBandH hBand)
11861
0
{
11862
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11863
0
#ifndef HAVE_MUPARSER
11864
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11865
0
    {
11866
0
        CPLError(
11867
0
            CE_Failure, CPLE_NotSupported,
11868
0
            "Band comparison operators not available on a GDAL build without "
11869
0
            "muparser");
11870
0
        return nullptr;
11871
0
    }
11872
0
#endif
11873
0
    switch (eOp)
11874
0
    {
11875
0
        case GRABO_ADD:
11876
0
        case GRABO_MUL:
11877
0
        {
11878
0
            return new GDALComputedRasterBand(
11879
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11880
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
11881
0
        }
11882
11883
0
        case GRABO_DIV:
11884
0
        case GRABO_GT:
11885
0
        case GRABO_GE:
11886
0
        case GRABO_LT:
11887
0
        case GRABO_LE:
11888
0
        case GRABO_EQ:
11889
0
        case GRABO_NE:
11890
0
        case GRABO_LOGICAL_AND:
11891
0
        case GRABO_LOGICAL_OR:
11892
0
        case GRABO_POW:
11893
0
        {
11894
0
            return new GDALComputedRasterBand(
11895
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11896
0
                *(GDALRasterBand::FromHandle(hBand)));
11897
0
        }
11898
11899
0
        case GRABO_SUB:
11900
0
        {
11901
0
            break;
11902
0
        }
11903
0
    }
11904
11905
0
    return new GDALComputedRasterBand(
11906
0
        GDALComputedRasterBand::Operation::OP_ADD,
11907
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11908
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
11909
0
        constant);
11910
0
}
11911
11912
/************************************************************************/
11913
/*                             operator+()                              */
11914
/************************************************************************/
11915
11916
/** Add this band with another one.
11917
 *
11918
 * The resulting band is lazy evaluated. A reference is taken on both input
11919
 * datasets.
11920
 *
11921
 * @since 3.12
11922
 * @throw std::runtime_error if both bands do not have the same dimensions.
11923
 */
11924
GDALComputedRasterBand
11925
GDALRasterBand::operator+(const GDALRasterBand &other) const
11926
0
{
11927
0
    ThrowIfNotSameDimensions(*this, other);
11928
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11929
0
                                  *this, other);
11930
0
}
11931
11932
/************************************************************************/
11933
/*                             operator+()                              */
11934
/************************************************************************/
11935
11936
/** Add this band with a constant.
11937
 *
11938
 * The resulting band is lazy evaluated. A reference is taken on the input
11939
 * dataset.
11940
 *
11941
 * @since 3.12
11942
 */
11943
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11944
0
{
11945
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11946
0
                                  *this, constant);
11947
0
}
11948
11949
/************************************************************************/
11950
/*                             operator+()                              */
11951
/************************************************************************/
11952
11953
/** Add a band with a constant.
11954
 *
11955
 * The resulting band is lazy evaluated. A reference is taken on the input
11956
 * dataset.
11957
 *
11958
 * @since 3.12
11959
 */
11960
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11961
0
{
11962
0
    return other + constant;
11963
0
}
11964
11965
/************************************************************************/
11966
/*                             operator-()                              */
11967
/************************************************************************/
11968
11969
/** Return a band whose value is the opposite value of the band for each
11970
 * pixel.
11971
 *
11972
 * The resulting band is lazy evaluated. A reference is taken on the input
11973
 * dataset.
11974
 *
11975
 * @since 3.12
11976
 */
11977
GDALComputedRasterBand GDALRasterBand::operator-() const
11978
0
{
11979
0
    return 0 - *this;
11980
0
}
11981
11982
/************************************************************************/
11983
/*                             operator-()                              */
11984
/************************************************************************/
11985
11986
/** Subtract this band with another one.
11987
 *
11988
 * The resulting band is lazy evaluated. A reference is taken on both input
11989
 * datasets.
11990
 *
11991
 * @since 3.12
11992
 * @throw std::runtime_error if both bands do not have the same dimensions.
11993
 */
11994
GDALComputedRasterBand
11995
GDALRasterBand::operator-(const GDALRasterBand &other) const
11996
0
{
11997
0
    ThrowIfNotSameDimensions(*this, other);
11998
0
    return GDALComputedRasterBand(
11999
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
12000
0
}
12001
12002
/************************************************************************/
12003
/*                             operator-()                              */
12004
/************************************************************************/
12005
12006
/** Subtract this band with a constant.
12007
 *
12008
 * The resulting band is lazy evaluated. A reference is taken on the input
12009
 * dataset.
12010
 *
12011
 * @since 3.12
12012
 */
12013
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
12014
0
{
12015
0
    return GDALComputedRasterBand(
12016
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
12017
0
}
12018
12019
/************************************************************************/
12020
/*                             operator-()                              */
12021
/************************************************************************/
12022
12023
/** Subtract a constant with a band.
12024
 *
12025
 * The resulting band is lazy evaluated. A reference is taken on the input
12026
 * dataset.
12027
 *
12028
 * @since 3.12
12029
 */
12030
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
12031
0
{
12032
0
    return other * (-1.0) + constant;
12033
0
}
12034
12035
/************************************************************************/
12036
/*                             operator*()                              */
12037
/************************************************************************/
12038
12039
/** Multiply this band with another one.
12040
 *
12041
 * The resulting band is lazy evaluated. A reference is taken on both input
12042
 * datasets.
12043
 *
12044
 * @since 3.12
12045
 * @throw std::runtime_error if both bands do not have the same dimensions.
12046
 */
12047
GDALComputedRasterBand
12048
GDALRasterBand::operator*(const GDALRasterBand &other) const
12049
0
{
12050
0
    ThrowIfNotSameDimensions(*this, other);
12051
0
    return GDALComputedRasterBand(
12052
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
12053
0
}
12054
12055
/************************************************************************/
12056
/*                             operator*()                              */
12057
/************************************************************************/
12058
12059
/** Multiply this band by a constant.
12060
 *
12061
 * The resulting band is lazy evaluated. A reference is taken on the input
12062
 * dataset.
12063
 *
12064
 * @since 3.12
12065
 */
12066
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
12067
0
{
12068
0
    return GDALComputedRasterBand(
12069
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
12070
0
}
12071
12072
/************************************************************************/
12073
/*                             operator*()                              */
12074
/************************************************************************/
12075
12076
/** Multiply a band with a constant.
12077
 *
12078
 * The resulting band is lazy evaluated. A reference is taken on the input
12079
 * dataset.
12080
 *
12081
 * @since 3.12
12082
 */
12083
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12084
0
{
12085
0
    return other * constant;
12086
0
}
12087
12088
/************************************************************************/
12089
/*                             operator/()                              */
12090
/************************************************************************/
12091
12092
/** Divide this band with another one.
12093
 *
12094
 * The resulting band is lazy evaluated. A reference is taken on both input
12095
 * datasets.
12096
 *
12097
 * @since 3.12
12098
 * @throw std::runtime_error if both bands do not have the same dimensions.
12099
 */
12100
GDALComputedRasterBand
12101
GDALRasterBand::operator/(const GDALRasterBand &other) const
12102
0
{
12103
0
    ThrowIfNotSameDimensions(*this, other);
12104
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12105
0
                                  *this, other);
12106
0
}
12107
12108
/************************************************************************/
12109
/*                             operator/()                              */
12110
/************************************************************************/
12111
12112
/** Divide this band by a constant.
12113
 *
12114
 * The resulting band is lazy evaluated. A reference is taken on the input
12115
 * dataset.
12116
 *
12117
 * @since 3.12
12118
 */
12119
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12120
0
{
12121
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12122
0
                                  *this, constant);
12123
0
}
12124
12125
/************************************************************************/
12126
/*                             operator/()                              */
12127
/************************************************************************/
12128
12129
/** Divide a constant by a band.
12130
 *
12131
 * The resulting band is lazy evaluated. A reference is taken on the input
12132
 * dataset.
12133
 *
12134
 * @since 3.12
12135
 */
12136
GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12137
0
{
12138
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12139
0
                                  constant, other);
12140
0
}
12141
12142
/************************************************************************/
12143
/*                         ThrowIfNotMuparser()                         */
12144
/************************************************************************/
12145
12146
#ifndef HAVE_MUPARSER
12147
static GDALComputedRasterBand ThrowIfNotMuparser()
12148
0
{
12149
0
    throw std::runtime_error("Operator not available on a "
12150
0
                             "GDAL build without muparser");
12151
0
}
12152
#endif
12153
12154
/************************************************************************/
12155
/*                             operator>()                              */
12156
/************************************************************************/
12157
12158
/** Return a band whose value is 1 if the pixel value of the left operand
12159
 * is greater than the pixel value of the right operand.
12160
 *
12161
 * The resulting band is lazy evaluated. A reference is taken on the input
12162
 * dataset.
12163
 *
12164
 * @since 3.12
12165
 */
12166
GDALComputedRasterBand
12167
GDALRasterBand::operator>(const GDALRasterBand &other) const
12168
0
{
12169
0
#ifndef HAVE_MUPARSER
12170
0
    (void)other;
12171
0
    return ThrowIfNotMuparser();
12172
#else
12173
    ThrowIfNotSameDimensions(*this, other);
12174
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12175
                                  *this, other);
12176
#endif
12177
0
}
12178
12179
/************************************************************************/
12180
/*                             operator>()                              */
12181
/************************************************************************/
12182
12183
/** Return a band whose value is 1 if the pixel value of the left operand
12184
 * is greater than the constant.
12185
 *
12186
 * The resulting band is lazy evaluated. A reference is taken on the input
12187
 * dataset.
12188
 *
12189
 * @since 3.12
12190
 */
12191
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12192
0
{
12193
0
#ifndef HAVE_MUPARSER
12194
0
    (void)constant;
12195
0
    return ThrowIfNotMuparser();
12196
#else
12197
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12198
                                  *this, constant);
12199
#endif
12200
0
}
12201
12202
/************************************************************************/
12203
/*                             operator>()                              */
12204
/************************************************************************/
12205
12206
/** Return a band whose value is 1 if the constant is greater than the pixel
12207
 * value of the right operand.
12208
 *
12209
 * The resulting band is lazy evaluated. A reference is taken on the input
12210
 * dataset.
12211
 *
12212
 * @since 3.12
12213
 */
12214
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12215
0
{
12216
0
#ifndef HAVE_MUPARSER
12217
0
    (void)constant;
12218
0
    (void)other;
12219
0
    return ThrowIfNotMuparser();
12220
#else
12221
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12222
                                  constant, other);
12223
#endif
12224
0
}
12225
12226
/************************************************************************/
12227
/*                             operator>=()                             */
12228
/************************************************************************/
12229
12230
/** Return a band whose value is 1 if the pixel value of the left operand
12231
 * is greater or equal to the pixel value of the right operand.
12232
 *
12233
 * The resulting band is lazy evaluated. A reference is taken on the input
12234
 * dataset.
12235
 *
12236
 * @since 3.12
12237
 */
12238
GDALComputedRasterBand
12239
GDALRasterBand::operator>=(const GDALRasterBand &other) const
12240
0
{
12241
0
#ifndef HAVE_MUPARSER
12242
0
    (void)other;
12243
0
    return ThrowIfNotMuparser();
12244
#else
12245
    ThrowIfNotSameDimensions(*this, other);
12246
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12247
                                  *this, other);
12248
#endif
12249
0
}
12250
12251
/************************************************************************/
12252
/*                             operator>=()                             */
12253
/************************************************************************/
12254
12255
/** Return a band whose value is 1 if the pixel value of the left operand
12256
 * is greater or equal to the constant.
12257
 *
12258
 * The resulting band is lazy evaluated. A reference is taken on the input
12259
 * dataset.
12260
 *
12261
 * @since 3.12
12262
 */
12263
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12264
0
{
12265
0
#ifndef HAVE_MUPARSER
12266
0
    (void)constant;
12267
0
    return ThrowIfNotMuparser();
12268
#else
12269
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12270
                                  *this, constant);
12271
#endif
12272
0
}
12273
12274
/************************************************************************/
12275
/*                             operator>=()                             */
12276
/************************************************************************/
12277
12278
/** Return a band whose value is 1 if the constant is greater or equal to
12279
 * the pixel value of the right operand.
12280
 *
12281
 * The resulting band is lazy evaluated. A reference is taken on the input
12282
 * dataset.
12283
 *
12284
 * @since 3.12
12285
 */
12286
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12287
0
{
12288
0
#ifndef HAVE_MUPARSER
12289
0
    (void)constant;
12290
0
    (void)other;
12291
0
    return ThrowIfNotMuparser();
12292
#else
12293
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12294
                                  constant, other);
12295
#endif
12296
0
}
12297
12298
/************************************************************************/
12299
/*                             operator<()                              */
12300
/************************************************************************/
12301
12302
/** Return a band whose value is 1 if the pixel value of the left operand
12303
 * is lesser than the pixel value of the right operand.
12304
 *
12305
 * The resulting band is lazy evaluated. A reference is taken on the input
12306
 * dataset.
12307
 *
12308
 * @since 3.12
12309
 */
12310
GDALComputedRasterBand
12311
GDALRasterBand::operator<(const GDALRasterBand &other) const
12312
0
{
12313
0
#ifndef HAVE_MUPARSER
12314
0
    (void)other;
12315
0
    return ThrowIfNotMuparser();
12316
#else
12317
    ThrowIfNotSameDimensions(*this, other);
12318
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12319
                                  *this, other);
12320
#endif
12321
0
}
12322
12323
/************************************************************************/
12324
/*                             operator<()                              */
12325
/************************************************************************/
12326
12327
/** Return a band whose value is 1 if the pixel value of the left operand
12328
 * is lesser than the constant.
12329
 *
12330
 * The resulting band is lazy evaluated. A reference is taken on the input
12331
 * dataset.
12332
 *
12333
 * @since 3.12
12334
 */
12335
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12336
0
{
12337
0
#ifndef HAVE_MUPARSER
12338
0
    (void)constant;
12339
0
    return ThrowIfNotMuparser();
12340
#else
12341
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12342
                                  *this, constant);
12343
#endif
12344
0
}
12345
12346
/************************************************************************/
12347
/*                             operator<()                              */
12348
/************************************************************************/
12349
12350
/** Return a band whose value is 1 if the constant is lesser than the pixel
12351
 * value of the right operand.
12352
 *
12353
 * The resulting band is lazy evaluated. A reference is taken on the input
12354
 * dataset.
12355
 *
12356
 * @since 3.12
12357
 */
12358
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12359
0
{
12360
0
#ifndef HAVE_MUPARSER
12361
0
    (void)constant;
12362
0
    (void)other;
12363
0
    return ThrowIfNotMuparser();
12364
#else
12365
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12366
                                  constant, other);
12367
#endif
12368
0
}
12369
12370
/************************************************************************/
12371
/*                             operator<=()                             */
12372
/************************************************************************/
12373
12374
/** Return a band whose value is 1 if the pixel value of the left operand
12375
 * is lesser or equal to the pixel value of the right operand.
12376
 *
12377
 * The resulting band is lazy evaluated. A reference is taken on the input
12378
 * dataset.
12379
 *
12380
 * @since 3.12
12381
 */
12382
GDALComputedRasterBand
12383
GDALRasterBand::operator<=(const GDALRasterBand &other) const
12384
0
{
12385
0
#ifndef HAVE_MUPARSER
12386
0
    (void)other;
12387
0
    return ThrowIfNotMuparser();
12388
#else
12389
    ThrowIfNotSameDimensions(*this, other);
12390
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12391
                                  *this, other);
12392
#endif
12393
0
}
12394
12395
/************************************************************************/
12396
/*                             operator<=()                             */
12397
/************************************************************************/
12398
12399
/** Return a band whose value is 1 if the pixel value of the left operand
12400
 * is lesser or equal to the constant.
12401
 *
12402
 * The resulting band is lazy evaluated. A reference is taken on the input
12403
 * dataset.
12404
 *
12405
 * @since 3.12
12406
 */
12407
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12408
0
{
12409
0
#ifndef HAVE_MUPARSER
12410
0
    (void)constant;
12411
0
    return ThrowIfNotMuparser();
12412
#else
12413
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12414
                                  *this, constant);
12415
#endif
12416
0
}
12417
12418
/************************************************************************/
12419
/*                             operator<=()                             */
12420
/************************************************************************/
12421
12422
/** Return a band whose value is 1 if the constant is lesser or equal to
12423
 * the pixel value of the right operand.
12424
 *
12425
 * The resulting band is lazy evaluated. A reference is taken on the input
12426
 * dataset.
12427
 *
12428
 * @since 3.12
12429
 */
12430
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12431
0
{
12432
0
#ifndef HAVE_MUPARSER
12433
0
    (void)constant;
12434
0
    (void)other;
12435
0
    return ThrowIfNotMuparser();
12436
#else
12437
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12438
                                  constant, other);
12439
#endif
12440
0
}
12441
12442
/************************************************************************/
12443
/*                             operator==()                             */
12444
/************************************************************************/
12445
12446
/** Return a band whose value is 1 if the pixel value of the left operand
12447
 * is equal to the pixel value of the right operand.
12448
 *
12449
 * The resulting band is lazy evaluated. A reference is taken on the input
12450
 * dataset.
12451
 *
12452
 * @since 3.12
12453
 */
12454
GDALComputedRasterBand
12455
GDALRasterBand::operator==(const GDALRasterBand &other) const
12456
0
{
12457
0
#ifndef HAVE_MUPARSER
12458
0
    (void)other;
12459
0
    return ThrowIfNotMuparser();
12460
#else
12461
    ThrowIfNotSameDimensions(*this, other);
12462
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12463
                                  *this, other);
12464
#endif
12465
0
}
12466
12467
/************************************************************************/
12468
/*                             operator==()                             */
12469
/************************************************************************/
12470
12471
/** Return a band whose value is 1 if the pixel value of the left operand
12472
 * is equal to the constant.
12473
 *
12474
 * The resulting band is lazy evaluated. A reference is taken on the input
12475
 * dataset.
12476
 *
12477
 * @since 3.12
12478
 */
12479
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12480
0
{
12481
0
#ifndef HAVE_MUPARSER
12482
0
    (void)constant;
12483
0
    return ThrowIfNotMuparser();
12484
#else
12485
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12486
                                  *this, constant);
12487
#endif
12488
0
}
12489
12490
/************************************************************************/
12491
/*                             operator==()                             */
12492
/************************************************************************/
12493
12494
/** Return a band whose value is 1 if the constant is equal to
12495
 * the pixel value of the right operand.
12496
 *
12497
 * The resulting band is lazy evaluated. A reference is taken on the input
12498
 * dataset.
12499
 *
12500
 * @since 3.12
12501
 */
12502
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12503
0
{
12504
0
#ifndef HAVE_MUPARSER
12505
0
    (void)constant;
12506
0
    (void)other;
12507
0
    return ThrowIfNotMuparser();
12508
#else
12509
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12510
                                  constant, other);
12511
#endif
12512
0
}
12513
12514
/************************************************************************/
12515
/*                             operator!=()                             */
12516
/************************************************************************/
12517
12518
/** Return a band whose value is 1 if the pixel value of the left operand
12519
 * is different from the pixel value of the right operand.
12520
 *
12521
 * The resulting band is lazy evaluated. A reference is taken on the input
12522
 * dataset.
12523
 *
12524
 * @since 3.12
12525
 */
12526
GDALComputedRasterBand
12527
GDALRasterBand::operator!=(const GDALRasterBand &other) const
12528
0
{
12529
0
#ifndef HAVE_MUPARSER
12530
0
    (void)other;
12531
0
    return ThrowIfNotMuparser();
12532
#else
12533
    ThrowIfNotSameDimensions(*this, other);
12534
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12535
                                  *this, other);
12536
#endif
12537
0
}
12538
12539
/************************************************************************/
12540
/*                             operator!=()                             */
12541
/************************************************************************/
12542
12543
/** Return a band whose value is 1 if the pixel value of the left operand
12544
 * is different from the constant.
12545
 *
12546
 * The resulting band is lazy evaluated. A reference is taken on the input
12547
 * dataset.
12548
 *
12549
 * @since 3.12
12550
 */
12551
GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12552
0
{
12553
0
#ifndef HAVE_MUPARSER
12554
0
    (void)constant;
12555
0
    return ThrowIfNotMuparser();
12556
#else
12557
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12558
                                  *this, constant);
12559
#endif
12560
0
}
12561
12562
/************************************************************************/
12563
/*                             operator!=()                             */
12564
/************************************************************************/
12565
12566
/** Return a band whose value is 1 if the constant is different from
12567
 * the pixel value of the right operand.
12568
 *
12569
 * The resulting band is lazy evaluated. A reference is taken on the input
12570
 * dataset.
12571
 *
12572
 * @since 3.12
12573
 */
12574
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12575
0
{
12576
0
#ifndef HAVE_MUPARSER
12577
0
    (void)constant;
12578
0
    (void)other;
12579
0
    return ThrowIfNotMuparser();
12580
#else
12581
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12582
                                  constant, other);
12583
#endif
12584
0
}
12585
12586
#if defined(__GNUC__)
12587
#pragma GCC diagnostic push
12588
#pragma GCC diagnostic ignored "-Weffc++"
12589
#endif
12590
12591
/************************************************************************/
12592
/*                             operator&&()                             */
12593
/************************************************************************/
12594
12595
/** Return a band whose value is 1 if the pixel value of the left and right
12596
 * operands is true.
12597
 *
12598
 * The resulting band is lazy evaluated. A reference is taken on the input
12599
 * dataset.
12600
 *
12601
 * @since 3.12
12602
 */
12603
GDALComputedRasterBand
12604
GDALRasterBand::operator&&(const GDALRasterBand &other) const
12605
0
{
12606
0
#ifndef HAVE_MUPARSER
12607
0
    (void)other;
12608
0
    return ThrowIfNotMuparser();
12609
#else
12610
    ThrowIfNotSameDimensions(*this, other);
12611
    return GDALComputedRasterBand(
12612
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12613
#endif
12614
0
}
12615
12616
/************************************************************************/
12617
/*                             operator&&()                             */
12618
/************************************************************************/
12619
12620
/** Return a band whose value is 1 if the pixel value of the left operand
12621
 * is true, as well as the constant
12622
 *
12623
 * The resulting band is lazy evaluated. A reference is taken on the input
12624
 * dataset.
12625
 *
12626
 * @since 3.12
12627
 */
12628
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12629
0
{
12630
0
#ifndef HAVE_MUPARSER
12631
0
    (void)constant;
12632
0
    return ThrowIfNotMuparser();
12633
#else
12634
    return GDALComputedRasterBand(
12635
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12636
#endif
12637
0
}
12638
12639
/************************************************************************/
12640
/*                             operator&&()                             */
12641
/************************************************************************/
12642
12643
/** Return a band whose value is 1 if the constant is true, as well as
12644
 * the pixel value of the right operand.
12645
 *
12646
 * The resulting band is lazy evaluated. A reference is taken on the input
12647
 * dataset.
12648
 *
12649
 * @since 3.12
12650
 */
12651
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12652
0
{
12653
0
#ifndef HAVE_MUPARSER
12654
0
    (void)constant;
12655
0
    (void)other;
12656
0
    return ThrowIfNotMuparser();
12657
#else
12658
    return GDALComputedRasterBand(
12659
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12660
#endif
12661
0
}
12662
12663
/************************************************************************/
12664
/*                             operator||()                             */
12665
/************************************************************************/
12666
12667
/** Return a band whose value is 1 if the pixel value of the left or right
12668
 * operands is true.
12669
 *
12670
 * The resulting band is lazy evaluated. A reference is taken on the input
12671
 * dataset.
12672
 *
12673
 * @since 3.12
12674
 */
12675
GDALComputedRasterBand
12676
GDALRasterBand::operator||(const GDALRasterBand &other) const
12677
0
{
12678
0
#ifndef HAVE_MUPARSER
12679
0
    (void)other;
12680
0
    return ThrowIfNotMuparser();
12681
#else
12682
    ThrowIfNotSameDimensions(*this, other);
12683
    return GDALComputedRasterBand(
12684
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12685
#endif
12686
0
}
12687
12688
/************************************************************************/
12689
/*                             operator||()                             */
12690
/************************************************************************/
12691
12692
/** Return a band whose value is 1 if the pixel value of the left operand
12693
 * is true, or if the constant is true
12694
 *
12695
 * The resulting band is lazy evaluated. A reference is taken on the input
12696
 * dataset.
12697
 *
12698
 * @since 3.12
12699
 */
12700
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12701
0
{
12702
0
#ifndef HAVE_MUPARSER
12703
0
    (void)constant;
12704
0
    return ThrowIfNotMuparser();
12705
#else
12706
    return GDALComputedRasterBand(
12707
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12708
#endif
12709
0
}
12710
12711
/************************************************************************/
12712
/*                             operator||()                             */
12713
/************************************************************************/
12714
12715
/** Return a band whose value is 1 if the constant is true, or
12716
 * the pixel value of the right operand is true
12717
 *
12718
 * The resulting band is lazy evaluated. A reference is taken on the input
12719
 * dataset.
12720
 *
12721
 * @since 3.12
12722
 */
12723
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12724
0
{
12725
0
#ifndef HAVE_MUPARSER
12726
0
    (void)constant;
12727
0
    (void)other;
12728
0
    return ThrowIfNotMuparser();
12729
#else
12730
    return GDALComputedRasterBand(
12731
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12732
#endif
12733
0
}
12734
12735
#if defined(__GNUC__)
12736
#pragma GCC diagnostic pop
12737
#endif
12738
12739
/************************************************************************/
12740
/*                             operator!()                              */
12741
/************************************************************************/
12742
12743
/** Return a band whose value is the logical negation of the pixel value
12744
 *
12745
 * The resulting band is lazy evaluated. A reference is taken on the input
12746
 * dataset.
12747
 *
12748
 * @since 3.12
12749
 */
12750
GDALComputedRasterBand GDALRasterBand::operator!() const
12751
0
{
12752
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12753
0
                                  *this, true);
12754
0
}
12755
12756
namespace gdal
12757
{
12758
12759
/************************************************************************/
12760
/*                             IfThenElse()                             */
12761
/************************************************************************/
12762
12763
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12764
 * is not zero, or the one from elseBand otherwise.
12765
 *
12766
 * Variants of this method exits where thenBand and/or elseBand can be double
12767
 * values.
12768
 *
12769
 * The resulting band is lazy evaluated. A reference is taken on the input
12770
 * datasets.
12771
 *
12772
 * This method is the same as the C function GDALRasterBandIfThenElse()
12773
 *
12774
 * @since 3.12
12775
 */
12776
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12777
                                  const GDALRasterBand &thenBand,
12778
                                  const GDALRasterBand &elseBand)
12779
0
{
12780
0
#ifndef HAVE_MUPARSER
12781
0
    (void)condBand;
12782
0
    (void)thenBand;
12783
0
    (void)elseBand;
12784
0
    return ThrowIfNotMuparser();
12785
#else
12786
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12787
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12788
    return GDALComputedRasterBand(
12789
        GDALComputedRasterBand::Operation::OP_TERNARY,
12790
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12791
#endif
12792
0
}
12793
12794
//! @cond Doxygen_Suppress
12795
12796
/************************************************************************/
12797
/*                             IfThenElse()                             */
12798
/************************************************************************/
12799
12800
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12801
 * is not zero, or the one from elseBand otherwise.
12802
 *
12803
 * The resulting band is lazy evaluated. A reference is taken on the input
12804
 * datasets.
12805
 *
12806
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12807
 * with thenBand = (condBand * 0) + thenValue
12808
 *
12809
 * @since 3.12
12810
 */
12811
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12812
                                  double thenValue,
12813
                                  const GDALRasterBand &elseBand)
12814
0
{
12815
0
#ifndef HAVE_MUPARSER
12816
0
    (void)condBand;
12817
0
    (void)thenValue;
12818
0
    (void)elseBand;
12819
0
    return ThrowIfNotMuparser();
12820
#else
12821
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12822
    auto thenBand =
12823
        (condBand * 0)
12824
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12825
        thenValue;
12826
    return GDALComputedRasterBand(
12827
        GDALComputedRasterBand::Operation::OP_TERNARY,
12828
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12829
#endif
12830
0
}
12831
12832
/************************************************************************/
12833
/*                             IfThenElse()                             */
12834
/************************************************************************/
12835
12836
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12837
 * is not zero, or the one from elseValue otherwise.
12838
 *
12839
 * The resulting band is lazy evaluated. A reference is taken on the input
12840
 * datasets.
12841
 *
12842
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12843
 * with elseBand = (condBand * 0) + elseValue
12844
12845
 * @since 3.12
12846
 */
12847
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12848
                                  const GDALRasterBand &thenBand,
12849
                                  double elseValue)
12850
0
{
12851
0
#ifndef HAVE_MUPARSER
12852
0
    (void)condBand;
12853
0
    (void)thenBand;
12854
0
    (void)elseValue;
12855
0
    return ThrowIfNotMuparser();
12856
#else
12857
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12858
    auto elseBand =
12859
        (condBand * 0)
12860
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12861
        elseValue;
12862
    return GDALComputedRasterBand(
12863
        GDALComputedRasterBand::Operation::OP_TERNARY,
12864
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12865
#endif
12866
0
}
12867
12868
/************************************************************************/
12869
/*                             IfThenElse()                             */
12870
/************************************************************************/
12871
12872
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12873
 * is not zero, or the one from elseValue otherwise.
12874
 *
12875
 * The resulting band is lazy evaluated. A reference is taken on the input
12876
 * datasets.
12877
 *
12878
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12879
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12880
 *
12881
 * @since 3.12
12882
 */
12883
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12884
                                  double thenValue, double elseValue)
12885
0
{
12886
0
#ifndef HAVE_MUPARSER
12887
0
    (void)condBand;
12888
0
    (void)thenValue;
12889
0
    (void)elseValue;
12890
0
    return ThrowIfNotMuparser();
12891
#else
12892
    auto thenBand =
12893
        (condBand * 0)
12894
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12895
        thenValue;
12896
    auto elseBand =
12897
        (condBand * 0)
12898
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12899
        elseValue;
12900
    return GDALComputedRasterBand(
12901
        GDALComputedRasterBand::Operation::OP_TERNARY,
12902
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12903
#endif
12904
0
}
12905
12906
//! @endcond
12907
12908
}  // namespace gdal
12909
12910
/************************************************************************/
12911
/*                      GDALRasterBandIfThenElse()                      */
12912
/************************************************************************/
12913
12914
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12915
 * is not zero, or the one from hElseBand otherwise.
12916
 *
12917
 * The resulting band is lazy evaluated. A reference is taken on the input
12918
 * datasets.
12919
 *
12920
 * This function is the same as the C++ method gdal::IfThenElse()
12921
 *
12922
 * @since 3.12
12923
 */
12924
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12925
                                                 GDALRasterBandH hThenBand,
12926
                                                 GDALRasterBandH hElseBand)
12927
0
{
12928
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12929
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12930
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12931
0
#ifndef HAVE_MUPARSER
12932
0
    CPLError(CE_Failure, CPLE_NotSupported,
12933
0
             "Band comparison operators not available on a GDAL build without "
12934
0
             "muparser");
12935
0
    return nullptr;
12936
#else
12937
12938
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12939
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12940
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12941
    try
12942
    {
12943
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12944
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12945
    }
12946
    catch (const std::exception &e)
12947
    {
12948
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12949
        return nullptr;
12950
    }
12951
    return new GDALComputedRasterBand(
12952
        GDALComputedRasterBand::Operation::OP_TERNARY,
12953
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12954
#endif
12955
0
}
12956
12957
/************************************************************************/
12958
/*                       GDALRasterBand::AsType()                       */
12959
/************************************************************************/
12960
12961
/** Cast this band to another type.
12962
 *
12963
 * The resulting band is lazy evaluated. A reference is taken on the input
12964
 * dataset.
12965
 *
12966
 * This method is the same as the C function GDALRasterBandAsDataType()
12967
 *
12968
 * @since 3.12
12969
 */
12970
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12971
0
{
12972
0
    if (dt == GDT_Unknown)
12973
0
    {
12974
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12975
0
    }
12976
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12977
0
                                  *this, dt);
12978
0
}
12979
12980
/************************************************************************/
12981
/*                      GDALRasterBandAsDataType()                      */
12982
/************************************************************************/
12983
12984
/** Cast this band to another type.
12985
 *
12986
 * The resulting band is lazy evaluated. A reference is taken on the input
12987
 * dataset.
12988
 *
12989
 * This function is the same as the C++ method GDALRasterBand::AsType()
12990
 *
12991
 * @since 3.12
12992
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12993
 */
12994
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12995
                                                 GDALDataType eDT)
12996
0
{
12997
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
12998
0
    if (eDT == GDT_Unknown)
12999
0
    {
13000
0
        CPLError(CE_Failure, CPLE_NotSupported,
13001
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
13002
0
        return nullptr;
13003
0
    }
13004
0
    return new GDALComputedRasterBand(
13005
0
        GDALComputedRasterBand::Operation::OP_CAST,
13006
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
13007
0
}
13008
13009
/************************************************************************/
13010
/*                           GetBandVector()                            */
13011
/************************************************************************/
13012
13013
static std::vector<const GDALRasterBand *>
13014
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
13015
0
{
13016
0
    std::vector<const GDALRasterBand *> bands;
13017
0
    for (size_t i = 0; i < nBandCount; ++i)
13018
0
    {
13019
0
        if (i > 0)
13020
0
        {
13021
0
            GDALRasterBand::ThrowIfNotSameDimensions(
13022
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
13023
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
13024
0
        }
13025
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
13026
0
    }
13027
0
    return bands;
13028
0
}
13029
13030
/************************************************************************/
13031
/*                       GDALOperationOnNBands()                        */
13032
/************************************************************************/
13033
13034
static GDALComputedRasterBandH
13035
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
13036
                      GDALRasterBandH *pahBands)
13037
0
{
13038
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
13039
0
    if (nBandCount == 0)
13040
0
    {
13041
0
        CPLError(CE_Failure, CPLE_AppDefined,
13042
0
                 "At least one band should be passed");
13043
0
        return nullptr;
13044
0
    }
13045
13046
0
    std::vector<const GDALRasterBand *> bands;
13047
0
    try
13048
0
    {
13049
0
        bands = GetBandVector(nBandCount, pahBands);
13050
0
    }
13051
0
    catch (const std::exception &e)
13052
0
    {
13053
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
13054
0
        return nullptr;
13055
0
    }
13056
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
13057
0
}
13058
13059
/************************************************************************/
13060
/*                        GDALMaximumOfNBands()                         */
13061
/************************************************************************/
13062
13063
/** Return a band whose each pixel value is the maximum of the corresponding
13064
 * pixel values in the input bands.
13065
 *
13066
 * The resulting band is lazy evaluated. A reference is taken on input
13067
 * datasets.
13068
 *
13069
 * This function is the same as the C ++ method gdal::max()
13070
 *
13071
 * @since 3.12
13072
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13073
 */
13074
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
13075
                                            GDALRasterBandH *pahBands)
13076
0
{
13077
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
13078
0
                                 nBandCount, pahBands);
13079
0
}
13080
13081
/************************************************************************/
13082
/*                             gdal::max()                              */
13083
/************************************************************************/
13084
13085
namespace gdal
13086
{
13087
/** Return a band whose each pixel value is the maximum of the corresponding
13088
 * pixel values in the inputs (bands or constants)
13089
 *
13090
 * The resulting band is lazy evaluated. A reference is taken on input
13091
 * datasets.
13092
 *
13093
 * Two or more bands can be passed.
13094
 *
13095
 * This method is the same as the C function GDALMaximumOfNBands()
13096
 *
13097
 * @since 3.12
13098
 * @throw std::runtime_error if bands do not have the same dimensions.
13099
 */
13100
GDALComputedRasterBand max(const GDALRasterBand &first,
13101
                           const GDALRasterBand &second)
13102
0
{
13103
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13104
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13105
0
                                  first, second);
13106
0
}
13107
}  // namespace gdal
13108
13109
/************************************************************************/
13110
/*                     GDALRasterBandMaxConstant()                      */
13111
/************************************************************************/
13112
13113
/** Return a band whose each pixel value is the maximum of the corresponding
13114
 * pixel values in the input band and the constant.
13115
 *
13116
 * The resulting band is lazy evaluated. A reference is taken on the input
13117
 * dataset.
13118
 *
13119
 * This function is the same as the C ++ method gdal::max()
13120
 *
13121
 * @since 3.12
13122
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13123
 */
13124
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13125
                                                  double dfConstant)
13126
0
{
13127
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13128
0
        GDALComputedRasterBand::Operation::OP_MAX,
13129
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13130
0
        dfConstant));
13131
0
}
13132
13133
/************************************************************************/
13134
/*                        GDALMinimumOfNBands()                         */
13135
/************************************************************************/
13136
13137
/** Return a band whose each pixel value is the minimum of the corresponding
13138
 * pixel values in the input bands.
13139
 *
13140
 * The resulting band is lazy evaluated. A reference is taken on input
13141
 * datasets.
13142
 *
13143
 * This function is the same as the C ++ method gdal::min()
13144
 *
13145
 * @since 3.12
13146
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13147
 */
13148
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13149
                                            GDALRasterBandH *pahBands)
13150
0
{
13151
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13152
0
                                 nBandCount, pahBands);
13153
0
}
13154
13155
/************************************************************************/
13156
/*                             gdal::min()                              */
13157
/************************************************************************/
13158
13159
namespace gdal
13160
{
13161
/** Return a band whose each pixel value is the minimum of the corresponding
13162
 * pixel values in the inputs (bands or constants)
13163
 *
13164
 * The resulting band is lazy evaluated. A reference is taken on input
13165
 * datasets.
13166
 *
13167
 * Two or more bands can be passed.
13168
 *
13169
 * This method is the same as the C function GDALMinimumOfNBands()
13170
 *
13171
 * @since 3.12
13172
 * @throw std::runtime_error if bands do not have the same dimensions.
13173
 */
13174
GDALComputedRasterBand min(const GDALRasterBand &first,
13175
                           const GDALRasterBand &second)
13176
0
{
13177
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13178
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13179
0
                                  first, second);
13180
0
}
13181
}  // namespace gdal
13182
13183
/************************************************************************/
13184
/*                     GDALRasterBandMinConstant()                      */
13185
/************************************************************************/
13186
13187
/** Return a band whose each pixel value is the minimum of the corresponding
13188
 * pixel values in the input band and the constant.
13189
 *
13190
 * The resulting band is lazy evaluated. A reference is taken on the input
13191
 * dataset.
13192
 *
13193
 * This function is the same as the C ++ method gdal::min()
13194
 *
13195
 * @since 3.12
13196
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13197
 */
13198
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13199
                                                  double dfConstant)
13200
0
{
13201
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13202
0
        GDALComputedRasterBand::Operation::OP_MIN,
13203
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13204
0
        dfConstant));
13205
0
}
13206
13207
/************************************************************************/
13208
/*                          GDALMeanOfNBands()                          */
13209
/************************************************************************/
13210
13211
/** Return a band whose each pixel value is the arithmetic mean of the
13212
 * corresponding pixel values in the input bands.
13213
 *
13214
 * The resulting band is lazy evaluated. A reference is taken on input
13215
 * datasets.
13216
 *
13217
 * This function is the same as the C ++ method gdal::mean()
13218
 *
13219
 * @since 3.12
13220
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13221
 */
13222
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13223
                                         GDALRasterBandH *pahBands)
13224
0
{
13225
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13226
0
                                 nBandCount, pahBands);
13227
0
}
13228
13229
/************************************************************************/
13230
/*                             gdal::mean()                             */
13231
/************************************************************************/
13232
13233
namespace gdal
13234
{
13235
13236
/** Return a band whose each pixel value is the arithmetic mean of the
13237
 * corresponding pixel values in the input bands.
13238
 *
13239
 * The resulting band is lazy evaluated. A reference is taken on input
13240
 * datasets.
13241
 *
13242
 * Two or more bands can be passed.
13243
 *
13244
 * This method is the same as the C function GDALMeanOfNBands()
13245
 *
13246
 * @since 3.12
13247
 * @throw std::runtime_error if bands do not have the same dimensions.
13248
 */
13249
GDALComputedRasterBand mean(const GDALRasterBand &first,
13250
                            const GDALRasterBand &second)
13251
0
{
13252
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13253
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13254
0
                                  first, second);
13255
0
}
13256
}  // namespace gdal
13257
13258
/************************************************************************/
13259
/*                             gdal::abs()                              */
13260
/************************************************************************/
13261
13262
namespace gdal
13263
{
13264
13265
/** Return a band whose each pixel value is the absolute value (or module
13266
 * for complex data type) of the corresponding pixel value in the input band.
13267
 *
13268
 * The resulting band is lazy evaluated. A reference is taken on input
13269
 * datasets.
13270
 *
13271
 * @since 3.12
13272
 */
13273
GDALComputedRasterBand abs(const GDALRasterBand &band)
13274
0
{
13275
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13276
0
                                  band);
13277
0
}
13278
}  // namespace gdal
13279
13280
/************************************************************************/
13281
/*                             gdal::fabs()                             */
13282
/************************************************************************/
13283
13284
namespace gdal
13285
{
13286
13287
/** Return a band whose each pixel value is the absolute value (or module
13288
 * for complex data type) of the corresponding pixel value in the input band.
13289
 *
13290
 * The resulting band is lazy evaluated. A reference is taken on input
13291
 * datasets.
13292
 *
13293
 * @since 3.12
13294
 */
13295
GDALComputedRasterBand fabs(const GDALRasterBand &band)
13296
0
{
13297
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13298
0
                                  band);
13299
0
}
13300
}  // namespace gdal
13301
13302
/************************************************************************/
13303
/*                             gdal::sqrt()                             */
13304
/************************************************************************/
13305
13306
namespace gdal
13307
{
13308
13309
/** Return a band whose each pixel value is the square root of the
13310
 * corresponding pixel value in the input band.
13311
 *
13312
 * The resulting band is lazy evaluated. A reference is taken on input
13313
 * datasets.
13314
 *
13315
 * @since 3.12
13316
 */
13317
GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13318
0
{
13319
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13320
0
                                  band);
13321
0
}
13322
}  // namespace gdal
13323
13324
/************************************************************************/
13325
/*                             gdal::log()                              */
13326
/************************************************************************/
13327
13328
namespace gdal
13329
{
13330
13331
/** Return a band whose each pixel value is the natural logarithm of the
13332
 * corresponding pixel value in the input band.
13333
 *
13334
 * The resulting band is lazy evaluated. A reference is taken on input
13335
 * datasets.
13336
 *
13337
 * @since 3.12
13338
 */
13339
GDALComputedRasterBand log(const GDALRasterBand &band)
13340
0
{
13341
0
#ifndef HAVE_MUPARSER
13342
0
    (void)band;
13343
0
    return ThrowIfNotMuparser();
13344
#else
13345
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13346
                                  band);
13347
#endif
13348
0
}
13349
}  // namespace gdal
13350
13351
/************************************************************************/
13352
/*                            gdal::log10()                             */
13353
/************************************************************************/
13354
13355
namespace gdal
13356
{
13357
13358
/** Return a band whose each pixel value is the logarithm base 10 of the
13359
 * corresponding pixel value in the input band.
13360
 *
13361
 * The resulting band is lazy evaluated. A reference is taken on input
13362
 * datasets.
13363
 *
13364
 * @since 3.12
13365
 */
13366
GDALComputedRasterBand log10(const GDALRasterBand &band)
13367
0
{
13368
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13369
0
                                  band);
13370
0
}
13371
}  // namespace gdal
13372
13373
/************************************************************************/
13374
/*                             gdal::pow()                              */
13375
/************************************************************************/
13376
13377
namespace gdal
13378
{
13379
13380
#ifndef DOXYGEN_SKIP
13381
/** Return a band whose each pixel value is the constant raised to the power of
13382
 * the corresponding pixel value in the input band.
13383
 *
13384
 * The resulting band is lazy evaluated. A reference is taken on input
13385
 * datasets.
13386
 *
13387
 * @since 3.12
13388
 */
13389
GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13390
0
{
13391
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13392
0
                                  constant, band);
13393
0
}
13394
#endif
13395
13396
}  // namespace gdal
13397
13398
/************************************************************************/
13399
/*                             gdal::pow()                              */
13400
/************************************************************************/
13401
13402
namespace gdal
13403
{
13404
13405
/** Return a band whose each pixel value is the the corresponding pixel value
13406
 * in the input band raised to the power of the constant.
13407
 *
13408
 * The resulting band is lazy evaluated. A reference is taken on input
13409
 * datasets.
13410
 *
13411
 * @since 3.12
13412
 */
13413
GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13414
0
{
13415
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13416
0
                                  band, constant);
13417
0
}
13418
}  // namespace gdal
13419
13420
/************************************************************************/
13421
/*                             gdal::pow()                              */
13422
/************************************************************************/
13423
13424
namespace gdal
13425
{
13426
13427
#ifndef DOXYGEN_SKIP
13428
/** Return a band whose each pixel value is the the corresponding pixel value
13429
 * in the input band1 raised to the power of the corresponding pixel value
13430
 * in the input band2
13431
 *
13432
 * The resulting band is lazy evaluated. A reference is taken on input
13433
 * datasets.
13434
 *
13435
 * @since 3.12
13436
 * @throw std::runtime_error if bands do not have the same dimensions.
13437
 */
13438
GDALComputedRasterBand pow(const GDALRasterBand &band1,
13439
                           const GDALRasterBand &band2)
13440
0
{
13441
0
#ifndef HAVE_MUPARSER
13442
0
    (void)band1;
13443
0
    (void)band2;
13444
0
    return ThrowIfNotMuparser();
13445
#else
13446
    GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13447
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13448
                                  band1, band2);
13449
#endif
13450
0
}
13451
#endif
13452
}  // namespace gdal