Coverage Report

Created: 2026-07-25 06:50

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 <algorithm>
19
#include <cassert>
20
#include <climits>
21
#include <cmath>
22
#include <cstdarg>
23
#include <cstddef>
24
#include <cstdio>
25
#include <cstdlib>
26
#include <cstring>
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
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
703
0
    CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
704
0
    CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
705
0
    CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
706
0
    CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
707
0
    sExtraArg.eResampleAlg = eResampleAlg;
708
0
    sExtraArg.pfnProgress = pfnProgress;
709
0
    sExtraArg.pProgressData = pProgressData;
710
0
    sExtraArg.bFloatingPointWindowValidity = true;
711
0
    sExtraArg.dfXOff = dfXOff;
712
0
    sExtraArg.dfYOff = dfYOff;
713
0
    sExtraArg.dfXSize = dfXSize;
714
0
    sExtraArg.dfYSize = dfYSize;
715
716
0
    const int nXOff = static_cast<int>(dfXOff);
717
0
    const int nYOff = static_cast<int>(dfYOff);
718
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
719
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
720
0
    if (nBufXSize == 0 && nBufYSize == 0)
721
0
    {
722
0
        if (static_cast<int>(dfXSize) == dfXSize &&
723
0
            static_cast<int>(dfYSize) == dfYSize)
724
0
        {
725
0
            nBufXSize = static_cast<int>(dfXSize);
726
0
            nBufYSize = static_cast<int>(dfYSize);
727
0
        }
728
0
        else
729
0
        {
730
0
            CPLError(CE_Failure, CPLE_AppDefined,
731
0
                     "nBufXSize and nBufYSize must be provided if dfXSize or "
732
0
                     "dfYSize is not an integer value");
733
0
            return CE_Failure;
734
0
        }
735
0
    }
736
0
    if (nBufXSize == 0 || nBufYSize == 0)
737
0
    {
738
0
        CPLDebug("GDAL",
739
0
                 "RasterIO() skipped for odd window or buffer size.\n"
740
0
                 "  Window = (%d,%d)x%dx%d\n"
741
0
                 "  Buffer = %dx%d\n",
742
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
743
0
                 static_cast<int>(nBufYSize));
744
745
0
        return CE_None;
746
0
    }
747
748
0
    if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
749
0
    {
750
0
        CPLError(CE_Failure, CPLE_AppDefined,
751
0
                 "Provided array is not large enough");
752
0
        return CE_Failure;
753
0
    }
754
755
0
    constexpr GSpacing nPixelSpace = sizeof(T);
756
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
757
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
758
759
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
760
761
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
762
0
                                   static_cast<int>(nBufXSize),
763
0
                                   static_cast<int>(nBufYSize), eBufType,
764
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
765
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
766
767
//! @cond Doxygen_Suppress
768
769
#define INSTANTIATE_READ_RASTER(T)                                             \
770
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
771
        T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
772
        double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
773
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
774
        void *pProgressData) const;
775
776
INSTANTIATE_READ_RASTER(uint8_t)
777
INSTANTIATE_READ_RASTER(int8_t)
778
INSTANTIATE_READ_RASTER(uint16_t)
779
INSTANTIATE_READ_RASTER(int16_t)
780
INSTANTIATE_READ_RASTER(uint32_t)
781
INSTANTIATE_READ_RASTER(int32_t)
782
INSTANTIATE_READ_RASTER(uint64_t)
783
INSTANTIATE_READ_RASTER(int64_t)
784
INSTANTIATE_READ_RASTER(GFloat16)
785
INSTANTIATE_READ_RASTER(float)
786
INSTANTIATE_READ_RASTER(double)
787
// Not allowed by C++ standard
788
// INSTANTIATE_READ_RASTER(std::complex<int16_t>)
789
// INSTANTIATE_READ_RASTER(std::complex<int32_t>)
790
INSTANTIATE_READ_RASTER(std::complex<float>)
791
INSTANTIATE_READ_RASTER(std::complex<double>)
792
793
//! @endcond
794
795
/************************************************************************/
796
/*                             ReadRaster()                             */
797
/************************************************************************/
798
799
/** Read a region of image data for this band.
800
 *
801
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
802
 * for common use cases, like reading a whole band.
803
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
804
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
805
 * float, double, std::complex<float|double>.
806
 *
807
 * To read a whole band (assuming it fits into memory), as a vector of double:
808
 *
809
\code
810
 std::vector<double> myArray;
811
 if (poBand->ReadRaster(myArray) == CE_None)
812
 {
813
     // do something
814
 }
815
\endcode
816
 *
817
 * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
818
 *
819
\code{.cpp}
820
 std::vector<double> myArray;
821
 if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
822
 {
823
     // do something
824
 }
825
\endcode
826
 *
827
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
828
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
829
 * instance of this dataset) concurrently from several threads.
830
 *
831
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
832
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
833
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
834
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
835
 * Or use nLineSpace and a possibly shifted pData value.
836
 *
837
 * @param[out] vData The vector into which the data should be written.
838
 * The vector will be resized, if needed, to contain at least nBufXSize *
839
 * nBufYSize values. The values in the vector are organized in left to right,
840
 * top to bottom pixel order, and fully packed.
841
 * The type of the vector does not need to be the one of GetDataType(). The
842
 * method will perform data type translation (with potential rounding, clamping)
843
 * if needed.
844
 *
845
 * @param dfXOff The pixel offset to the top left corner of the region
846
 * of the band to be accessed. This would be zero to start from the left side.
847
 * Defaults to 0.
848
 *
849
 * @param dfYOff The line offset to the top left corner of the region
850
 * of the band to be accessed. This would be zero to start from the top.
851
 * Defaults to 0.
852
 *
853
 * @param dfXSize The width of the region of the band to be accessed in pixels.
854
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
855
 * dfXSize is set to the band width.
856
 *
857
 * @param dfYSize The height of the region of the band to be accessed in lines.
858
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
859
 * dfYSize is set to the band height.
860
 *
861
 * @param nBufXSize the width of the buffer image into which the desired region
862
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
863
 * then nBufXSize is initialized with dfXSize.
864
 *
865
 * @param nBufYSize the height of the buffer image into which the desired region
866
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
867
 * then nBufYSize is initialized with dfYSize.
868
 *
869
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
870
 *
871
 * @param pfnProgress Progress function. May be nullptr.
872
 *
873
 * @param pProgressData User data of pfnProgress. May be nullptr.
874
 *
875
 * @return CE_Failure if the access fails, otherwise CE_None.
876
 *
877
 * @see GDALRasterBand::RasterIO()
878
 * @since GDAL 3.10
879
 */
880
template <class T>
881
CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
882
                                  double dfYOff, double dfXSize, double dfYSize,
883
                                  size_t nBufXSize, size_t nBufYSize,
884
                                  GDALRIOResampleAlg eResampleAlg,
885
                                  GDALProgressFunc pfnProgress,
886
                                  void *pProgressData) const
887
0
{
888
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
889
0
    {
890
0
        return CE_Failure;
891
0
    }
892
893
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
894
0
    {
895
0
        dfXSize = nRasterXSize;
896
0
        dfYSize = nRasterYSize;
897
0
    }
898
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
899
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
900
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
901
0
             dfYOff + dfYSize > INT_MAX)
902
0
    {
903
0
        return CE_Failure;
904
0
    }
905
906
0
    GDALRasterIOExtraArg sExtraArg;
907
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
908
0
    CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
909
0
    CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
910
0
    CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
911
0
    CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
912
0
    sExtraArg.eResampleAlg = eResampleAlg;
913
0
    sExtraArg.pfnProgress = pfnProgress;
914
0
    sExtraArg.pProgressData = pProgressData;
915
0
    sExtraArg.bFloatingPointWindowValidity = true;
916
0
    sExtraArg.dfXOff = dfXOff;
917
0
    sExtraArg.dfYOff = dfYOff;
918
0
    sExtraArg.dfXSize = dfXSize;
919
0
    sExtraArg.dfYSize = dfYSize;
920
921
0
    const int nXOff = static_cast<int>(dfXOff);
922
0
    const int nYOff = static_cast<int>(dfYOff);
923
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
924
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
925
0
    if (nBufXSize == 0 && nBufYSize == 0)
926
0
    {
927
0
        if (static_cast<int>(dfXSize) == dfXSize &&
928
0
            static_cast<int>(dfYSize) == dfYSize)
929
0
        {
930
0
            nBufXSize = static_cast<int>(dfXSize);
931
0
            nBufYSize = static_cast<int>(dfYSize);
932
0
        }
933
0
        else
934
0
        {
935
0
            CPLError(CE_Failure, CPLE_AppDefined,
936
0
                     "nBufXSize and nBufYSize must be provided if "
937
0
                     "dfXSize or dfYSize is not an integer value");
938
0
            return CE_Failure;
939
0
        }
940
0
    }
941
0
    if (nBufXSize == 0 || nBufYSize == 0)
942
0
    {
943
0
        CPLDebug("GDAL",
944
0
                 "RasterIO() skipped for odd window or buffer size.\n"
945
0
                 "  Window = (%d,%d)x%dx%d\n"
946
0
                 "  Buffer = %dx%d\n",
947
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
948
0
                 static_cast<int>(nBufYSize));
949
950
0
        return CE_None;
951
0
    }
952
953
    if constexpr (SIZEOF_VOIDP < 8)
954
    {
955
        if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
956
        {
957
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
958
            return CE_Failure;
959
        }
960
    }
961
962
0
    if (vData.size() < nBufXSize * nBufYSize)
963
0
    {
964
0
        try
965
0
        {
966
0
            vData.resize(nBufXSize * nBufYSize);
967
0
        }
968
0
        catch (const std::exception &)
969
0
        {
970
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
971
0
            return CE_Failure;
972
0
        }
973
0
    }
974
975
0
    constexpr GSpacing nPixelSpace = sizeof(T);
976
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
977
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
978
979
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
980
981
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
982
0
                                   vData.data(), static_cast<int>(nBufXSize),
983
0
                                   static_cast<int>(nBufYSize), eBufType,
984
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
985
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
986
987
//! @cond Doxygen_Suppress
988
989
#define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
990
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
991
        std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
992
        double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
993
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
994
        void *pProgressData) const;
995
996
INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
997
INSTANTIATE_READ_RASTER_VECTOR(int8_t)
998
INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
999
INSTANTIATE_READ_RASTER_VECTOR(int16_t)
1000
INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
1001
INSTANTIATE_READ_RASTER_VECTOR(int32_t)
1002
INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
1003
INSTANTIATE_READ_RASTER_VECTOR(int64_t)
1004
INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
1005
INSTANTIATE_READ_RASTER_VECTOR(float)
1006
INSTANTIATE_READ_RASTER_VECTOR(double)
1007
// Not allowed by C++ standard
1008
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
1009
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1010
INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1011
INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1012
1013
//! @endcond
1014
1015
/************************************************************************/
1016
/*                             ReadBlock()                              */
1017
/************************************************************************/
1018
1019
/**
1020
 * \brief Read a block of image data efficiently.
1021
 *
1022
 * This method accesses a "natural" block from the raster band without
1023
 * resampling, or data type conversion.  For a more generalized, but
1024
 * potentially less efficient access use RasterIO().
1025
 *
1026
 * This method is the same as the C GDALReadBlock() function.
1027
 *
1028
 * See the GetLockedBlockRef() method for a way of accessing internally cached
1029
 * block oriented data without an extra copy into an application buffer.
1030
 *
1031
 * The following code would efficiently compute a histogram of eight bit
1032
 * raster data.  Note that the final block may be partial ... data beyond
1033
 * the edge of the underlying raster band in these edge blocks is of an
1034
 * undetermined value.
1035
 *
1036
\code{.cpp}
1037
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1038
1039
 {
1040
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1041
1042
     CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1043
1044
     int nXBlockSize, nYBlockSize;
1045
1046
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1047
     int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1048
     int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1049
1050
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1051
1052
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1053
     {
1054
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1055
         {
1056
             int        nXValid, nYValid;
1057
1058
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1059
1060
             // Compute the portion of the block that is valid
1061
             // for partial edge blocks.
1062
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1063
1064
             // Collect the histogram counts.
1065
             for( int iY = 0; iY < nYValid; iY++ )
1066
             {
1067
                 for( int iX = 0; iX < nXValid; iX++ )
1068
                 {
1069
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1070
                 }
1071
             }
1072
         }
1073
     }
1074
 }
1075
\endcode
1076
 *
1077
 * @param nXBlockOff the horizontal block offset, with zero indicating
1078
 * the left most block, 1 the next block and so forth.
1079
 *
1080
 * @param nYBlockOff the vertical block offset, with zero indicating
1081
 * the top most block, 1 the next block and so forth.
1082
 *
1083
 * @param pImage the buffer into which the data will be read.  The buffer
1084
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1085
 * of type GetRasterDataType().
1086
 *
1087
 * @return CE_None on success or CE_Failure on an error.
1088
 */
1089
1090
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1091
1092
0
{
1093
    /* -------------------------------------------------------------------- */
1094
    /*      Validate arguments.                                             */
1095
    /* -------------------------------------------------------------------- */
1096
0
    CPLAssert(pImage != nullptr);
1097
1098
0
    if (!InitBlockInfo())
1099
0
        return CE_Failure;
1100
1101
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1102
0
    {
1103
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1104
0
                    "Illegal nXBlockOff value (%d) in "
1105
0
                    "GDALRasterBand::ReadBlock()\n",
1106
0
                    nXBlockOff);
1107
1108
0
        return (CE_Failure);
1109
0
    }
1110
1111
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1112
0
    {
1113
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1114
0
                    "Illegal nYBlockOff value (%d) in "
1115
0
                    "GDALRasterBand::ReadBlock()\n",
1116
0
                    nYBlockOff);
1117
1118
0
        return (CE_Failure);
1119
0
    }
1120
1121
    /* -------------------------------------------------------------------- */
1122
    /*      Invoke underlying implementation method.                        */
1123
    /* -------------------------------------------------------------------- */
1124
1125
0
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1126
0
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1127
0
    if (bCallLeaveReadWrite)
1128
0
        LeaveReadWrite();
1129
0
    return eErr;
1130
0
}
1131
1132
/************************************************************************/
1133
/*                           GDALReadBlock()                            */
1134
/************************************************************************/
1135
1136
/**
1137
 * \brief Read a block of image data efficiently.
1138
 *
1139
 * @see GDALRasterBand::ReadBlock()
1140
 */
1141
1142
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1143
                                 void *pData)
1144
1145
0
{
1146
0
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1147
1148
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1149
0
    return (poBand->ReadBlock(nXOff, nYOff, pData));
1150
0
}
1151
1152
/************************************************************************/
1153
/*                             IReadBlock()                             */
1154
/************************************************************************/
1155
1156
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1157
 * ) \brief Read a block of data.
1158
 *
1159
 * Default internal implementation ... to be overridden by
1160
 * subclasses that support reading.
1161
 * @param nBlockXOff Block X Offset
1162
 * @param nBlockYOff Block Y Offset
1163
 * @param pData Pixel buffer into which to place read data.
1164
 * @return CE_None on success or CE_Failure on an error.
1165
 */
1166
1167
/************************************************************************/
1168
/*                            IWriteBlock()                             */
1169
/************************************************************************/
1170
1171
/**
1172
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1173
 * Write a block of data.
1174
 *
1175
 * Default internal implementation ... to be overridden by
1176
 * subclasses that support writing.
1177
 * @param nBlockXOff Block X Offset
1178
 * @param nBlockYOff Block Y Offset
1179
 * @param pData Pixel buffer to write
1180
 * @return CE_None on success or CE_Failure on an error.
1181
 */
1182
1183
/**/
1184
/**/
1185
1186
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1187
                                   void * /*pData*/)
1188
1189
0
{
1190
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1191
0
        ReportError(CE_Failure, CPLE_NotSupported,
1192
0
                    "WriteBlock() not supported for this dataset.");
1193
1194
0
    return (CE_Failure);
1195
0
}
1196
1197
/************************************************************************/
1198
/*                             WriteBlock()                             */
1199
/************************************************************************/
1200
1201
/**
1202
 * \brief Write a block of image data efficiently.
1203
 *
1204
 * This method accesses a "natural" block from the raster band without
1205
 * resampling, or data type conversion.  For a more generalized, but
1206
 * potentially less efficient access use RasterIO().
1207
 *
1208
 * This method is the same as the C GDALWriteBlock() function.
1209
 *
1210
 * See ReadBlock() for an example of block oriented data access.
1211
 *
1212
 * @param nXBlockOff the horizontal block offset, with zero indicating
1213
 * the left most block, 1 the next block and so forth.
1214
 *
1215
 * @param nYBlockOff the vertical block offset, with zero indicating
1216
 * the left most block, 1 the next block and so forth.
1217
 *
1218
 * @param pImage the buffer from which the data will be written.  The buffer
1219
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1220
 * of type GetRasterDataType(). Note that the content of the buffer might be
1221
 * temporarily modified during the execution of this method (and eventually
1222
 * restored back to its original content), so it is not safe to use a buffer
1223
 * stored in a read-only section of the calling program.
1224
 *
1225
 * @return CE_None on success or CE_Failure on an error.
1226
 */
1227
1228
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1229
1230
0
{
1231
    /* -------------------------------------------------------------------- */
1232
    /*      Validate arguments.                                             */
1233
    /* -------------------------------------------------------------------- */
1234
0
    CPLAssert(pImage != nullptr);
1235
1236
0
    if (!InitBlockInfo())
1237
0
        return CE_Failure;
1238
1239
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1240
0
    {
1241
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1242
0
                    "Illegal nXBlockOff value (%d) in "
1243
0
                    "GDALRasterBand::WriteBlock()\n",
1244
0
                    nXBlockOff);
1245
1246
0
        return (CE_Failure);
1247
0
    }
1248
1249
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1250
0
    {
1251
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1252
0
                    "Illegal nYBlockOff value (%d) in "
1253
0
                    "GDALRasterBand::WriteBlock()\n",
1254
0
                    nYBlockOff);
1255
1256
0
        return (CE_Failure);
1257
0
    }
1258
1259
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1260
0
    {
1261
0
        return CE_Failure;
1262
0
    }
1263
1264
0
    if (eFlushBlockErr != CE_None)
1265
0
    {
1266
0
        ReportError(eFlushBlockErr, CPLE_AppDefined,
1267
0
                    "An error occurred while writing a dirty block "
1268
0
                    "from GDALRasterBand::WriteBlock");
1269
0
        CPLErr eErr = eFlushBlockErr;
1270
0
        eFlushBlockErr = CE_None;
1271
0
        return eErr;
1272
0
    }
1273
1274
    /* -------------------------------------------------------------------- */
1275
    /*      Invoke underlying implementation method.                        */
1276
    /* -------------------------------------------------------------------- */
1277
1278
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1279
0
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1280
0
    if (bCallLeaveReadWrite)
1281
0
        LeaveReadWrite();
1282
1283
0
    return eErr;
1284
0
}
1285
1286
/************************************************************************/
1287
/*                           GDALWriteBlock()                           */
1288
/************************************************************************/
1289
1290
/**
1291
 * \brief Write a block of image data efficiently.
1292
 *
1293
 * @see GDALRasterBand::WriteBlock()
1294
 */
1295
1296
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1297
                                  void *pData)
1298
1299
0
{
1300
0
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1301
1302
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1303
0
    return (poBand->WriteBlock(nXOff, nYOff, pData));
1304
0
}
1305
1306
/************************************************************************/
1307
/*                EmitErrorMessageIfWriteNotSupported()                 */
1308
/************************************************************************/
1309
1310
/**
1311
 * Emit an error message if a write operation to this band is not supported.
1312
 *
1313
 * The base implementation will emit an error message if the access mode is
1314
 * read-only. Derived classes may implement it to provide a custom message.
1315
 *
1316
 * @param pszCaller Calling function.
1317
 * @return true if an error message has been emitted.
1318
 */
1319
bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1320
    const char *pszCaller) const
1321
0
{
1322
0
    if (eAccess == GA_ReadOnly)
1323
0
    {
1324
0
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1325
0
                    "%s: attempt to write to dataset opened in read-only mode.",
1326
0
                    pszCaller);
1327
1328
0
        return true;
1329
0
    }
1330
0
    return false;
1331
0
}
1332
1333
/************************************************************************/
1334
/*                         GetActualBlockSize()                         */
1335
/************************************************************************/
1336
/**
1337
 * \brief Fetch the actual block size for a given block offset.
1338
 *
1339
 * Handles partial blocks at the edges of the raster and returns the true
1340
 * number of pixels
1341
 *
1342
 * @param nXBlockOff the horizontal block offset for which to calculate the
1343
 * number of valid pixels, with zero indicating the left most block, 1 the next
1344
 * block and so forth.
1345
 *
1346
 * @param nYBlockOff the vertical block offset, with zero indicating
1347
 * the top most block, 1 the next block and so forth.
1348
 *
1349
 * @param pnXValid pointer to an integer in which the number of valid pixels in
1350
 * the x direction will be stored
1351
 *
1352
 * @param pnYValid pointer to an integer in which the number of valid pixels in
1353
 * the y direction will be stored
1354
 *
1355
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
1356
 *
1357
 */
1358
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1359
                                          int *pnXValid, int *pnYValid) const
1360
0
{
1361
0
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
1362
0
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1363
0
        nYBlockOff < 0 || nBlockYSize == 0 ||
1364
0
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1365
0
    {
1366
0
        return CE_Failure;
1367
0
    }
1368
1369
0
    const int nXPixelOff = nXBlockOff * nBlockXSize;
1370
0
    const int nYPixelOff = nYBlockOff * nBlockYSize;
1371
1372
0
    *pnXValid = nBlockXSize;
1373
0
    *pnYValid = nBlockYSize;
1374
1375
0
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
1376
0
    {
1377
0
        *pnXValid = nRasterXSize - nXPixelOff;
1378
0
    }
1379
1380
0
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
1381
0
    {
1382
0
        *pnYValid = nRasterYSize - nYPixelOff;
1383
0
    }
1384
1385
0
    return CE_None;
1386
0
}
1387
1388
/************************************************************************/
1389
/*                       GDALGetActualBlockSize()                       */
1390
/************************************************************************/
1391
1392
/**
1393
 * \brief Retrieve the actual block size for a given block offset.
1394
 *
1395
 * @see GDALRasterBand::GetActualBlockSize()
1396
 */
1397
1398
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1399
                                          int nYBlockOff, int *pnXValid,
1400
                                          int *pnYValid)
1401
1402
0
{
1403
0
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1404
1405
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1406
0
    return (
1407
0
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1408
0
}
1409
1410
/************************************************************************/
1411
/*                   GetSuggestedBlockAccessPattern()                   */
1412
/************************************************************************/
1413
1414
/**
1415
 * \brief Return the suggested/most efficient access pattern to blocks
1416
 *        (for read operations).
1417
 *
1418
 * While all GDAL drivers have to expose a block size, not all can guarantee
1419
 * efficient random access (GSBAP_RANDOM) to any block.
1420
 * Some drivers for example decompress sequentially a compressed stream from
1421
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1422
 * case best performance will be achieved while reading blocks in that order.
1423
 * (accessing blocks in random access in such rasters typically causes the
1424
 * decoding to be re-initialized from the start if accessing blocks in
1425
 * a non-sequential order)
1426
 *
1427
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1428
 * returned by drivers that expose a somewhat artificial block size, because
1429
 * they can extract any part of a raster, but in a rather inefficient way.
1430
 *
1431
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1432
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1433
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1434
 * most efficient strategy is to read as many pixels as possible in the less
1435
 * RasterIO() operations.
1436
 *
1437
 * The return of this method is for example used to determine the swath size
1438
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1439
 *
1440
 * @since GDAL 3.6
1441
 */
1442
1443
GDALSuggestedBlockAccessPattern
1444
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1445
0
{
1446
0
    return GSBAP_UNKNOWN;
1447
0
}
1448
1449
/************************************************************************/
1450
/*                         GetRasterDataType()                          */
1451
/************************************************************************/
1452
1453
/**
1454
 * \brief Fetch the pixel data type for this band.
1455
 *
1456
 * This method is the same as the C function GDALGetRasterDataType().
1457
 *
1458
 * @return the data type of pixels for this band.
1459
 */
1460
1461
GDALDataType GDALRasterBand::GetRasterDataType() const
1462
1463
0
{
1464
0
    return eDataType;
1465
0
}
1466
1467
/************************************************************************/
1468
/*                       GDALGetRasterDataType()                        */
1469
/************************************************************************/
1470
1471
/**
1472
 * \brief Fetch the pixel data type for this band.
1473
 *
1474
 * @see GDALRasterBand::GetRasterDataType()
1475
 */
1476
1477
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1478
1479
0
{
1480
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1481
1482
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1483
0
    return poBand->GetRasterDataType();
1484
0
}
1485
1486
/************************************************************************/
1487
/*                            GetBlockSize()                            */
1488
/************************************************************************/
1489
1490
/**
1491
 * \brief Fetch the "natural" block size of this band.
1492
 *
1493
 * GDAL contains a concept of the natural block size of rasters so that
1494
 * applications can organized data access efficiently for some file formats.
1495
 * The natural block size is the block size that is most efficient for
1496
 * accessing the format.  For many formats this is simple a whole scanline
1497
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1498
 *
1499
 * However, for tiled images this will typically be the tile size.
1500
 *
1501
 * Note that the X and Y block sizes don't have to divide the image size
1502
 * evenly, meaning that right and bottom edge blocks may be incomplete.
1503
 * See ReadBlock() for an example of code dealing with these issues.
1504
 *
1505
 * This method is the same as the C function GDALGetBlockSize().
1506
 *
1507
 * @param pnXSize integer to put the X block size into or NULL.
1508
 *
1509
 * @param pnYSize integer to put the Y block size into or NULL.
1510
 */
1511
1512
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1513
1514
0
{
1515
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1516
0
    {
1517
0
        ReportError(CE_Failure, CPLE_AppDefined,
1518
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1519
0
                    nBlockYSize);
1520
0
        if (pnXSize != nullptr)
1521
0
            *pnXSize = 0;
1522
0
        if (pnYSize != nullptr)
1523
0
            *pnYSize = 0;
1524
0
    }
1525
0
    else
1526
0
    {
1527
0
        if (pnXSize != nullptr)
1528
0
            *pnXSize = nBlockXSize;
1529
0
        if (pnYSize != nullptr)
1530
0
            *pnYSize = nBlockYSize;
1531
0
    }
1532
0
}
1533
1534
/************************************************************************/
1535
/*                          GDALGetBlockSize()                          */
1536
/************************************************************************/
1537
1538
/**
1539
 * \brief Fetch the "natural" block size of this band.
1540
 *
1541
 * @see GDALRasterBand::GetBlockSize()
1542
 */
1543
1544
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1545
                                  int *pnYSize)
1546
1547
0
{
1548
0
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1549
1550
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1551
0
    poBand->GetBlockSize(pnXSize, pnYSize);
1552
0
}
1553
1554
/************************************************************************/
1555
/*                           InitBlockInfo()                            */
1556
/************************************************************************/
1557
1558
//! @cond Doxygen_Suppress
1559
int GDALRasterBand::InitBlockInfo()
1560
1561
0
{
1562
0
    if (poBandBlockCache != nullptr)
1563
0
        return poBandBlockCache->IsInitOK();
1564
1565
    /* Do some validation of raster and block dimensions in case the driver */
1566
    /* would have neglected to do it itself */
1567
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1568
0
    {
1569
0
        ReportError(CE_Failure, CPLE_AppDefined,
1570
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1571
0
                    nBlockYSize);
1572
0
        return FALSE;
1573
0
    }
1574
1575
0
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
1576
0
    {
1577
0
        ReportError(CE_Failure, CPLE_AppDefined,
1578
0
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1579
0
                    nRasterYSize);
1580
0
        return FALSE;
1581
0
    }
1582
1583
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1584
0
    if (nDataTypeSize == 0)
1585
0
    {
1586
0
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1587
0
        return FALSE;
1588
0
    }
1589
1590
#if SIZEOF_VOIDP == 4
1591
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1592
    {
1593
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1594
         * multiplication in other cases */
1595
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1596
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1597
        {
1598
            ReportError(CE_Failure, CPLE_NotSupported,
1599
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1600
                        nBlockYSize);
1601
            return FALSE;
1602
        }
1603
    }
1604
#endif
1605
1606
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1607
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1608
1609
0
    const char *pszBlockStrategy =
1610
0
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1611
0
    bool bUseArray = true;
1612
0
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1613
0
    {
1614
0
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1615
0
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1616
0
        {
1617
0
            GUIntBig nBlockCount =
1618
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1619
0
            if (poDS != nullptr)
1620
0
                nBlockCount *= poDS->GetRasterCount();
1621
0
            bUseArray = (nBlockCount < 1024 * 1024);
1622
0
        }
1623
0
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1624
0
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1625
0
        {
1626
0
            bUseArray = false;
1627
0
        }
1628
0
    }
1629
0
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
1630
0
        bUseArray = false;
1631
0
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1632
0
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1633
0
                 pszBlockStrategy);
1634
1635
0
    if (bUseArray)
1636
0
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1637
0
    else
1638
0
    {
1639
0
        if (nBand == 1)
1640
0
            CPLDebug("GDAL", "Use hashset band block cache");
1641
0
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1642
0
    }
1643
0
    if (poBandBlockCache == nullptr)
1644
0
        return FALSE;
1645
0
    return poBandBlockCache->Init();
1646
0
}
1647
1648
//! @endcond
1649
1650
/************************************************************************/
1651
/*                             FlushCache()                             */
1652
/************************************************************************/
1653
1654
/**
1655
 * \brief Flush raster data cache.
1656
 *
1657
 * This call will recover memory used to cache data blocks for this raster
1658
 * band, and ensure that new requests are referred to the underlying driver.
1659
 *
1660
 * This method is the same as the C function GDALFlushRasterCache().
1661
 *
1662
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1663
 * @return CE_None on success.
1664
 */
1665
1666
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1667
1668
0
{
1669
0
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1670
0
        poBandBlockCache)
1671
0
        poBandBlockCache->DisableDirtyBlockWriting();
1672
1673
0
    CPLErr eGlobalErr = eFlushBlockErr;
1674
1675
0
    if (eFlushBlockErr != CE_None)
1676
0
    {
1677
0
        ReportError(
1678
0
            eFlushBlockErr, CPLE_AppDefined,
1679
0
            "An error occurred while writing a dirty block from FlushCache");
1680
0
        eFlushBlockErr = CE_None;
1681
0
    }
1682
1683
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1684
0
        return eGlobalErr;
1685
1686
0
    return poBandBlockCache->FlushCache();
1687
0
}
1688
1689
/************************************************************************/
1690
/*                        GDALFlushRasterCache()                        */
1691
/************************************************************************/
1692
1693
/**
1694
 * \brief Flush raster data cache.
1695
 *
1696
 * @see GDALRasterBand::FlushCache()
1697
 */
1698
1699
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1700
1701
0
{
1702
0
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1703
1704
0
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1705
0
}
1706
1707
/************************************************************************/
1708
/*                             DropCache()                              */
1709
/************************************************************************/
1710
1711
/**
1712
* \brief Drop raster data cache : data in cache will be lost.
1713
*
1714
* This call will recover memory used to cache data blocks for this raster
1715
* band, and ensure that new requests are referred to the underlying driver.
1716
*
1717
* This method is the same as the C function GDALDropRasterCache().
1718
*
1719
* @return CE_None on success.
1720
* @since 3.9
1721
*/
1722
1723
CPLErr GDALRasterBand::DropCache()
1724
1725
0
{
1726
0
    CPLErr result = CE_None;
1727
1728
0
    if (poBandBlockCache)
1729
0
        poBandBlockCache->DisableDirtyBlockWriting();
1730
1731
0
    CPLErr eGlobalErr = eFlushBlockErr;
1732
1733
0
    if (eFlushBlockErr != CE_None)
1734
0
    {
1735
0
        ReportError(
1736
0
            eFlushBlockErr, CPLE_AppDefined,
1737
0
            "An error occurred while writing a dirty block from DropCache");
1738
0
        eFlushBlockErr = CE_None;
1739
0
    }
1740
1741
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1742
0
        result = eGlobalErr;
1743
0
    else
1744
0
        result = poBandBlockCache->FlushCache();
1745
1746
0
    if (poBandBlockCache)
1747
0
        poBandBlockCache->EnableDirtyBlockWriting();
1748
1749
0
    return result;
1750
0
}
1751
1752
/************************************************************************/
1753
/*                        GDALDropRasterCache()                         */
1754
/************************************************************************/
1755
1756
/**
1757
* \brief Drop raster data cache.
1758
*
1759
* @see GDALRasterBand::DropCache()
1760
* @since 3.9
1761
*/
1762
1763
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1764
1765
0
{
1766
0
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1767
1768
0
    return GDALRasterBand::FromHandle(hBand)->DropCache();
1769
0
}
1770
1771
/************************************************************************/
1772
/*                        UnreferenceBlock()                            */
1773
/*                                                                      */
1774
/*      Unreference the block from our array of blocks                  */
1775
/*      This method should only be called by                            */
1776
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1777
/*      the block cache mutex)                                          */
1778
/************************************************************************/
1779
1780
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1781
0
{
1782
#ifdef notdef
1783
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1784
    {
1785
        if (poBandBlockCache == nullptr)
1786
            printf("poBandBlockCache == NULL\n"); /*ok*/
1787
        else
1788
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1789
        printf("caller = %s\n", pszCaller);            /*ok*/
1790
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1791
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1792
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1793
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1794
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1795
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1796
        poBlock->DumpBlock();
1797
        if (GetDataset() != nullptr)
1798
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1799
        GDALRasterBlock::Verify();
1800
        abort();
1801
    }
1802
#endif
1803
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1804
0
    return poBandBlockCache->UnreferenceBlock(poBlock);
1805
0
}
1806
1807
/************************************************************************/
1808
/*                        AddBlockToFreeList()                          */
1809
/*                                                                      */
1810
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1811
/*      finished with a block about to be free'd, they pass it to that  */
1812
/*      method.                                                         */
1813
/************************************************************************/
1814
1815
//! @cond Doxygen_Suppress
1816
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1817
0
{
1818
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1819
0
    return poBandBlockCache->AddBlockToFreeList(poBlock);
1820
0
}
1821
1822
//! @endcond
1823
1824
/************************************************************************/
1825
/*                           HasDirtyBlocks()                           */
1826
/************************************************************************/
1827
1828
//! @cond Doxygen_Suppress
1829
bool GDALRasterBand::HasDirtyBlocks() const
1830
0
{
1831
0
    return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1832
0
}
1833
1834
//! @endcond
1835
1836
/************************************************************************/
1837
/*                             FlushBlock()                             */
1838
/************************************************************************/
1839
1840
/** Flush a block out of the block cache.
1841
 * @param nXBlockOff block x offset
1842
 * @param nYBlockOff blocky offset
1843
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1844
 * @return CE_None in case of success, an error code otherwise.
1845
 */
1846
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1847
                                  int bWriteDirtyBlock)
1848
1849
0
{
1850
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1851
0
        return (CE_Failure);
1852
1853
    /* -------------------------------------------------------------------- */
1854
    /*      Validate the request                                            */
1855
    /* -------------------------------------------------------------------- */
1856
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1857
0
    {
1858
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1859
0
                    "Illegal nBlockXOff value (%d) in "
1860
0
                    "GDALRasterBand::FlushBlock()\n",
1861
0
                    nXBlockOff);
1862
1863
0
        return (CE_Failure);
1864
0
    }
1865
1866
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1867
0
    {
1868
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1869
0
                    "Illegal nBlockYOff value (%d) in "
1870
0
                    "GDALRasterBand::FlushBlock()\n",
1871
0
                    nYBlockOff);
1872
1873
0
        return (CE_Failure);
1874
0
    }
1875
1876
0
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1877
0
                                        bWriteDirtyBlock);
1878
0
}
1879
1880
/************************************************************************/
1881
/*                        TryGetLockedBlockRef()                        */
1882
/************************************************************************/
1883
1884
/**
1885
 * \brief Try fetching block ref.
1886
 *
1887
 * This method will returned the requested block (locked) if it is already
1888
 * in the block cache for the layer.  If not, nullptr is returned.
1889
 *
1890
 * If a non-NULL value is returned, then a lock for the block will have been
1891
 * acquired on behalf of the caller.  It is absolutely imperative that the
1892
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1893
 * severe problems may result.
1894
 *
1895
 * @param nXBlockOff the horizontal block offset, with zero indicating
1896
 * the left most block, 1 the next block and so forth.
1897
 *
1898
 * @param nYBlockOff the vertical block offset, with zero indicating
1899
 * the top most block, 1 the next block and so forth.
1900
 *
1901
 * @return NULL if block not available, or locked block pointer.
1902
 */
1903
1904
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1905
                                                      int nYBlockOff)
1906
1907
0
{
1908
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1909
0
        return nullptr;
1910
1911
    /* -------------------------------------------------------------------- */
1912
    /*      Validate the request                                            */
1913
    /* -------------------------------------------------------------------- */
1914
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1915
0
    {
1916
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1917
0
                    "Illegal nBlockXOff value (%d) in "
1918
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1919
0
                    nXBlockOff);
1920
1921
0
        return (nullptr);
1922
0
    }
1923
1924
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1925
0
    {
1926
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1927
0
                    "Illegal nBlockYOff value (%d) in "
1928
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1929
0
                    nYBlockOff);
1930
1931
0
        return (nullptr);
1932
0
    }
1933
1934
0
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1935
0
}
1936
1937
/************************************************************************/
1938
/*                         GetLockedBlockRef()                          */
1939
/************************************************************************/
1940
1941
/**
1942
 * \brief Fetch a pointer to an internally cached raster block.
1943
 *
1944
 * This method will returned the requested block (locked) if it is already
1945
 * in the block cache for the layer.  If not, the block will be read from
1946
 * the driver, and placed in the layer block cached, then returned.  If an
1947
 * error occurs reading the block from the driver, a NULL value will be
1948
 * returned.
1949
 *
1950
 * If a non-NULL value is returned, then a lock for the block will have been
1951
 * acquired on behalf of the caller.  It is absolutely imperative that the
1952
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1953
 * severe problems may result.
1954
 *
1955
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1956
 * enable caching.
1957
 *
1958
 * @param nXBlockOff the horizontal block offset, with zero indicating
1959
 * the left most block, 1 the next block and so forth.
1960
 *
1961
 * @param nYBlockOff the vertical block offset, with zero indicating
1962
 * the top most block, 1 the next block and so forth.
1963
 *
1964
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1965
 * but not actually read from the source.  This is useful when it will just
1966
 * be completely set and written back.
1967
 *
1968
 * @return pointer to the block object, or NULL on failure.
1969
 */
1970
1971
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1972
                                                   int nYBlockOff,
1973
                                                   int bJustInitialize)
1974
1975
0
{
1976
    /* -------------------------------------------------------------------- */
1977
    /*      Try and fetch from cache.                                       */
1978
    /* -------------------------------------------------------------------- */
1979
0
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1980
1981
    /* -------------------------------------------------------------------- */
1982
    /*      If we didn't find it in our memory cache, instantiate a         */
1983
    /*      block (potentially load from disk) and "adopt" it into the      */
1984
    /*      cache.                                                          */
1985
    /* -------------------------------------------------------------------- */
1986
0
    if (poBlock == nullptr)
1987
0
    {
1988
0
        if (!InitBlockInfo())
1989
0
            return (nullptr);
1990
1991
        /* --------------------------------------------------------------------
1992
         */
1993
        /*      Validate the request */
1994
        /* --------------------------------------------------------------------
1995
         */
1996
0
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1997
0
        {
1998
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1999
0
                        "Illegal nBlockXOff value (%d) in "
2000
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
2001
0
                        nXBlockOff);
2002
2003
0
            return (nullptr);
2004
0
        }
2005
2006
0
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
2007
0
        {
2008
0
            ReportError(CE_Failure, CPLE_IllegalArg,
2009
0
                        "Illegal nBlockYOff value (%d) in "
2010
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
2011
0
                        nYBlockOff);
2012
2013
0
            return (nullptr);
2014
0
        }
2015
2016
0
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2017
0
        if (poBlock == nullptr)
2018
0
            return nullptr;
2019
2020
0
        poBlock->AddLock();
2021
2022
        /* We need to temporarily drop the read-write lock in the following */
2023
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2024
         */
2025
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2026
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2027
         */
2028
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2029
         */
2030
        /* called and attempt at taking the lock on T2 (already taken).
2031
         * Similarly */
2032
        /* for T2 with D1, hence a deadlock situation (#6163) */
2033
        /* But this may open the door to other problems... */
2034
0
        if (poDS)
2035
0
            poDS->TemporarilyDropReadWriteLock();
2036
        /* allocate data space */
2037
0
        CPLErr eErr = poBlock->Internalize();
2038
0
        if (poDS)
2039
0
            poDS->ReacquireReadWriteLock();
2040
0
        if (eErr != CE_None)
2041
0
        {
2042
0
            poBlock->DropLock();
2043
0
            delete poBlock;
2044
0
            return nullptr;
2045
0
        }
2046
2047
0
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2048
0
        {
2049
0
            poBlock->DropLock();
2050
0
            delete poBlock;
2051
0
            return nullptr;
2052
0
        }
2053
2054
0
        if (!bJustInitialize)
2055
0
        {
2056
0
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2057
0
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2058
0
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2059
0
            if (bCallLeaveReadWrite)
2060
0
                LeaveReadWrite();
2061
0
            if (eErr != CE_None)
2062
0
            {
2063
0
                poBlock->DropLock();
2064
0
                FlushBlock(nXBlockOff, nYBlockOff);
2065
0
                ReportError(CE_Failure, CPLE_AppDefined,
2066
0
                            "IReadBlock failed at X offset %d, Y offset %d%s",
2067
0
                            nXBlockOff, nYBlockOff,
2068
0
                            (nErrorCounter != CPLGetErrorCounter())
2069
0
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2070
0
                                : "");
2071
0
                return nullptr;
2072
0
            }
2073
2074
0
            nBlockReads++;
2075
0
            if (static_cast<GIntBig>(nBlockReads) ==
2076
0
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2077
0
                        1 &&
2078
0
                nBand == 1 && poDS != nullptr)
2079
0
            {
2080
0
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2081
0
                         poDS->GetDescription());
2082
0
            }
2083
0
        }
2084
0
    }
2085
2086
0
    return poBlock;
2087
0
}
2088
2089
/************************************************************************/
2090
/*                                Fill()                                */
2091
/************************************************************************/
2092
2093
/**
2094
 * \brief Fill this band with a constant value.
2095
 *
2096
 * GDAL makes no guarantees
2097
 * about what values pixels in newly created files are set to, so this
2098
 * method can be used to clear a band to a specified "default" value.
2099
 * The fill value is passed in as a double but this will be converted
2100
 * to the underlying type before writing to the file. An optional
2101
 * second argument allows the imaginary component of a complex
2102
 * constant value to be specified.
2103
 *
2104
 * This method is the same as the C function GDALFillRaster().
2105
 *
2106
 * @param dfRealValue Real component of fill value
2107
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2108
 *
2109
 * @return CE_Failure if the write fails, otherwise CE_None
2110
 */
2111
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2112
0
{
2113
2114
    // General approach is to construct a source block of the file's
2115
    // native type containing the appropriate value and then copy this
2116
    // to each block in the image via the RasterBlock cache. Using
2117
    // the cache means we avoid file I/O if it is not necessary, at the
2118
    // expense of some extra memcpy's (since we write to the
2119
    // RasterBlock cache, which is then at some point written to the
2120
    // underlying file, rather than simply directly to the underlying
2121
    // file.)
2122
2123
    // Check we can write to the file.
2124
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2125
0
    {
2126
0
        return CE_Failure;
2127
0
    }
2128
2129
    // Make sure block parameters are set.
2130
0
    if (!InitBlockInfo())
2131
0
        return CE_Failure;
2132
2133
    // Allocate the source block.
2134
0
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2135
0
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2136
0
    auto blockByteSize = blockSize * elementSize;
2137
0
    unsigned char *srcBlock =
2138
0
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2139
0
    if (srcBlock == nullptr)
2140
0
    {
2141
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
2142
0
                    "GDALRasterBand::Fill(): Out of memory "
2143
0
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
2144
0
                    static_cast<GUIntBig>(blockByteSize));
2145
0
        return CE_Failure;
2146
0
    }
2147
2148
    // Initialize the source block.
2149
0
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2150
0
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2151
0
                    elementSize, blockSize);
2152
2153
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2154
2155
    // Write block to block cache
2156
0
    for (int j = 0; j < nBlocksPerColumn; ++j)
2157
0
    {
2158
0
        for (int i = 0; i < nBlocksPerRow; ++i)
2159
0
        {
2160
0
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2161
0
            if (destBlock == nullptr)
2162
0
            {
2163
0
                ReportError(CE_Failure, CPLE_OutOfMemory,
2164
0
                            "GDALRasterBand::Fill(): Error "
2165
0
                            "while retrieving cache block.");
2166
0
                VSIFree(srcBlock);
2167
0
                return CE_Failure;
2168
0
            }
2169
0
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2170
0
            destBlock->MarkDirty();
2171
0
            destBlock->DropLock();
2172
0
        }
2173
0
    }
2174
2175
0
    if (bCallLeaveReadWrite)
2176
0
        LeaveReadWrite();
2177
2178
    // Free up the source block
2179
0
    VSIFree(srcBlock);
2180
2181
0
    return CE_None;
2182
0
}
2183
2184
/************************************************************************/
2185
/*                           GDALFillRaster()                           */
2186
/************************************************************************/
2187
2188
/**
2189
 * \brief Fill this band with a constant value.
2190
 *
2191
 * @see GDALRasterBand::Fill()
2192
 */
2193
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2194
                                  double dfImaginaryValue)
2195
0
{
2196
0
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2197
2198
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2199
0
    return poBand->Fill(dfRealValue, dfImaginaryValue);
2200
0
}
2201
2202
/************************************************************************/
2203
/*                             GetAccess()                              */
2204
/************************************************************************/
2205
2206
/**
2207
 * \brief Find out if we have update permission for this band.
2208
 *
2209
 * This method is the same as the C function GDALGetRasterAccess().
2210
 *
2211
 * @return Either GA_Update or GA_ReadOnly.
2212
 */
2213
2214
GDALAccess GDALRasterBand::GetAccess()
2215
2216
0
{
2217
0
    return eAccess;
2218
0
}
2219
2220
/************************************************************************/
2221
/*                        GDALGetRasterAccess()                         */
2222
/************************************************************************/
2223
2224
/**
2225
 * \brief Find out if we have update permission for this band.
2226
 *
2227
 * @see GDALRasterBand::GetAccess()
2228
 */
2229
2230
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2231
2232
0
{
2233
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2234
2235
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2236
0
    return poBand->GetAccess();
2237
0
}
2238
2239
/************************************************************************/
2240
/*                          GetCategoryNames()                          */
2241
/************************************************************************/
2242
2243
/**
2244
 * \brief Fetch the list of category names for this raster.
2245
 *
2246
 * The return list is a "StringList" in the sense of the CPL functions.
2247
 * That is a NULL terminated array of strings.  Raster values without
2248
 * associated names will have an empty string in the returned list.  The
2249
 * first entry in the list is for raster values of zero, and so on.
2250
 *
2251
 * The returned stringlist should not be altered or freed by the application.
2252
 * It may change on the next GDAL call, so please copy it if it is needed
2253
 * for any period of time.
2254
 *
2255
 * This method is the same as the C function GDALGetRasterCategoryNames().
2256
 *
2257
 * @return list of names, or NULL if none.
2258
 */
2259
2260
char **GDALRasterBand::GetCategoryNames()
2261
2262
0
{
2263
0
    return nullptr;
2264
0
}
2265
2266
/************************************************************************/
2267
/*                     GDALGetRasterCategoryNames()                     */
2268
/************************************************************************/
2269
2270
/**
2271
 * \brief Fetch the list of category names for this raster.
2272
 *
2273
 * @see GDALRasterBand::GetCategoryNames()
2274
 */
2275
2276
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2277
2278
0
{
2279
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2280
2281
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2282
0
    return poBand->GetCategoryNames();
2283
0
}
2284
2285
/************************************************************************/
2286
/*                          SetCategoryNames()                          */
2287
/************************************************************************/
2288
2289
/**
2290
 * \fn GDALRasterBand::SetCategoryNames(char**)
2291
 * \brief Set the category names for this band.
2292
 *
2293
 * See the GetCategoryNames() method for more on the interpretation of
2294
 * category names.
2295
 *
2296
 * This method is the same as the C function GDALSetRasterCategoryNames().
2297
 *
2298
 * @param papszNames the NULL terminated StringList of category names.  May
2299
 * be NULL to just clear the existing list.
2300
 *
2301
 * @return CE_None on success of CE_Failure on failure.  If unsupported
2302
 * by the driver CE_Failure is returned, but no error message is reported.
2303
 */
2304
2305
/**/
2306
/**/
2307
2308
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2309
0
{
2310
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2311
0
        ReportError(CE_Failure, CPLE_NotSupported,
2312
0
                    "SetCategoryNames() not supported for this dataset.");
2313
2314
0
    return CE_Failure;
2315
0
}
2316
2317
/************************************************************************/
2318
/*                        GDALSetCategoryNames()                        */
2319
/************************************************************************/
2320
2321
/**
2322
 * \brief Set the category names for this band.
2323
 *
2324
 * @see GDALRasterBand::SetCategoryNames()
2325
 */
2326
2327
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2328
                                              CSLConstList papszNames)
2329
2330
0
{
2331
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2332
2333
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2334
0
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2335
0
}
2336
2337
/************************************************************************/
2338
/*                           GetNoDataValue()                           */
2339
/************************************************************************/
2340
2341
/**
2342
 * \brief Fetch the no data value for this band.
2343
 *
2344
 * If there is no out of data value, an out of range value will generally
2345
 * be returned.  The no data value for a band is generally a special marker
2346
 * value used to mark pixels that are not valid data.  Such pixels should
2347
 * generally not be displayed, nor contribute to analysis operations.
2348
 *
2349
 * The no data value returned is 'raw', meaning that it has no offset and
2350
 * scale applied.
2351
 *
2352
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2353
 * lossy if the nodata value cannot exactly been represented by a double.
2354
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2355
 *
2356
 * This method is the same as the C function GDALGetRasterNoDataValue().
2357
 *
2358
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2359
 * is actually associated with this layer.  May be NULL (default).
2360
 *
2361
 * @return the nodata value for this band.
2362
 */
2363
2364
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2365
2366
0
{
2367
0
    if (pbSuccess != nullptr)
2368
0
        *pbSuccess = FALSE;
2369
2370
0
    return -1e10;
2371
0
}
2372
2373
/************************************************************************/
2374
/*                      GDALGetRasterNoDataValue()                      */
2375
/************************************************************************/
2376
2377
/**
2378
 * \brief Fetch the no data value for this band.
2379
 *
2380
 * @see GDALRasterBand::GetNoDataValue()
2381
 */
2382
2383
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2384
                                            int *pbSuccess)
2385
2386
0
{
2387
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2388
2389
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2390
0
    return poBand->GetNoDataValue(pbSuccess);
2391
0
}
2392
2393
/************************************************************************/
2394
/*                       GetNoDataValueAsInt64()                        */
2395
/************************************************************************/
2396
2397
/**
2398
 * \brief Fetch the no data value for this band.
2399
 *
2400
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2401
 *
2402
 * If there is no out of data value, an out of range value will generally
2403
 * be returned.  The no data value for a band is generally a special marker
2404
 * value used to mark pixels that are not valid data.  Such pixels should
2405
 * generally not be displayed, nor contribute to analysis operations.
2406
 *
2407
 * The no data value returned is 'raw', meaning that it has no offset and
2408
 * scale applied.
2409
 *
2410
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2411
 *
2412
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2413
 * is actually associated with this layer.  May be NULL (default).
2414
 *
2415
 * @return the nodata value for this band.
2416
 *
2417
 * @since GDAL 3.5
2418
 */
2419
2420
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2421
2422
0
{
2423
0
    if (pbSuccess != nullptr)
2424
0
        *pbSuccess = FALSE;
2425
2426
0
    return std::numeric_limits<int64_t>::min();
2427
0
}
2428
2429
/************************************************************************/
2430
/*                  GDALGetRasterNoDataValueAsInt64()                   */
2431
/************************************************************************/
2432
2433
/**
2434
 * \brief Fetch the no data value for this band.
2435
 *
2436
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2437
 *
2438
 * @see GDALRasterBand::GetNoDataValueAsInt64()
2439
 *
2440
 * @since GDAL 3.5
2441
 */
2442
2443
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2444
                                                    int *pbSuccess)
2445
2446
0
{
2447
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2448
0
                      std::numeric_limits<int64_t>::min());
2449
2450
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2451
0
    return poBand->GetNoDataValueAsInt64(pbSuccess);
2452
0
}
2453
2454
/************************************************************************/
2455
/*                       GetNoDataValueAsUInt64()                       */
2456
/************************************************************************/
2457
2458
/**
2459
 * \brief Fetch the no data value for this band.
2460
 *
2461
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2462
 *
2463
 * If there is no out of data value, an out of range value will generally
2464
 * be returned.  The no data value for a band is generally a special marker
2465
 * value used to mark pixels that are not valid data.  Such pixels should
2466
 * generally not be displayed, nor contribute to analysis operations.
2467
 *
2468
 * The no data value returned is 'raw', meaning that it has no offset and
2469
 * scale applied.
2470
 *
2471
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2472
 *
2473
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2474
 * is actually associated with this layer.  May be NULL (default).
2475
 *
2476
 * @return the nodata value for this band.
2477
 *
2478
 * @since GDAL 3.5
2479
 */
2480
2481
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2482
2483
0
{
2484
0
    if (pbSuccess != nullptr)
2485
0
        *pbSuccess = FALSE;
2486
2487
0
    return std::numeric_limits<uint64_t>::max();
2488
0
}
2489
2490
/************************************************************************/
2491
/*                  GDALGetRasterNoDataValueAsUInt64()                  */
2492
/************************************************************************/
2493
2494
/**
2495
 * \brief Fetch the no data value for this band.
2496
 *
2497
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2498
 *
2499
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
2500
 *
2501
 * @since GDAL 3.5
2502
 */
2503
2504
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2505
                                                      int *pbSuccess)
2506
2507
0
{
2508
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2509
0
                      std::numeric_limits<uint64_t>::max());
2510
2511
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2512
0
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
2513
0
}
2514
2515
/************************************************************************/
2516
/*                       SetNoDataValueAsString()                       */
2517
/************************************************************************/
2518
2519
/**
2520
 * \brief Set the no data value for this band.
2521
 *
2522
 * Depending on drivers, changing the no data value may or may not have an
2523
 * effect on the pixel values of a raster that has just been created. It is
2524
 * thus advised to explicitly called Fill() if the intent is to initialize
2525
 * the raster to the nodata value.
2526
 * In any case, changing an existing no data value, when one already exists and
2527
 * the dataset exists or has been initialized, has no effect on the pixel whose
2528
 * value matched the previous nodata value.
2529
 *
2530
 * To clear the nodata value, use DeleteNoDataValue().
2531
 *
2532
 * @param pszNoData the value to set.
2533
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2534
 *             If the value cannot be exactly represented on the output data
2535
 *             type, *pbCannotBeExactlyRepresented will be set to true.
2536
 *
2537
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2538
 * by the driver, CE_Failure is returned but no error message will have
2539
 * been emitted.
2540
 *
2541
 * @since 3.11
2542
 */
2543
2544
CPLErr
2545
GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2546
                                       bool *pbCannotBeExactlyRepresented)
2547
0
{
2548
0
    if (pbCannotBeExactlyRepresented)
2549
0
        *pbCannotBeExactlyRepresented = false;
2550
0
    if (eDataType == GDT_Int64)
2551
0
    {
2552
0
        if (strchr(pszNoData, '.') ||
2553
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2554
0
        {
2555
0
            char *endptr = nullptr;
2556
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2557
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2558
0
                GDALIsValueExactAs<int64_t>(dfVal))
2559
0
            {
2560
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2561
0
            }
2562
0
        }
2563
0
        else
2564
0
        {
2565
0
            try
2566
0
            {
2567
0
                const auto val = std::stoll(pszNoData);
2568
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2569
0
            }
2570
0
            catch (const std::exception &)
2571
0
            {
2572
0
            }
2573
0
        }
2574
0
    }
2575
0
    else if (eDataType == GDT_UInt64)
2576
0
    {
2577
0
        if (strchr(pszNoData, '.') ||
2578
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2579
0
        {
2580
0
            char *endptr = nullptr;
2581
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2582
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2583
0
                GDALIsValueExactAs<uint64_t>(dfVal))
2584
0
            {
2585
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2586
0
            }
2587
0
        }
2588
0
        else
2589
0
        {
2590
0
            try
2591
0
            {
2592
0
                const auto val = std::stoull(pszNoData);
2593
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2594
0
            }
2595
0
            catch (const std::exception &)
2596
0
            {
2597
0
            }
2598
0
        }
2599
0
    }
2600
0
    else if (eDataType == GDT_Float32)
2601
0
    {
2602
0
        char *endptr = nullptr;
2603
0
        const float fVal = CPLStrtof(pszNoData, &endptr);
2604
0
        if (endptr == pszNoData + strlen(pszNoData))
2605
0
        {
2606
0
            return SetNoDataValue(double(fVal));
2607
0
        }
2608
0
    }
2609
0
    else
2610
0
    {
2611
0
        char *endptr = nullptr;
2612
0
        const double dfVal = CPLStrtod(pszNoData, &endptr);
2613
0
        if (endptr == pszNoData + strlen(pszNoData) &&
2614
0
            GDALIsValueExactAs(dfVal, eDataType))
2615
0
        {
2616
0
            return SetNoDataValue(dfVal);
2617
0
        }
2618
0
    }
2619
0
    if (pbCannotBeExactlyRepresented)
2620
0
        *pbCannotBeExactlyRepresented = true;
2621
0
    return CE_Failure;
2622
0
}
2623
2624
/************************************************************************/
2625
/*                           SetNoDataValue()                           */
2626
/************************************************************************/
2627
2628
/**
2629
 * \fn GDALRasterBand::SetNoDataValue(double)
2630
 * \brief Set the no data value for this band.
2631
 *
2632
 * Depending on drivers, changing the no data value may or may not have an
2633
 * effect on the pixel values of a raster that has just been created. It is
2634
 * thus advised to explicitly called Fill() if the intent is to initialize
2635
 * the raster to the nodata value.
2636
 * In any case, changing an existing no data value, when one already exists and
2637
 * the dataset exists or has been initialized, has no effect on the pixel whose
2638
 * value matched the previous nodata value.
2639
 *
2640
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2641
 * be represented by a double, use SetNoDataValueAsInt64() or
2642
 * SetNoDataValueAsUInt64() instead.
2643
 *
2644
 * To clear the nodata value, use DeleteNoDataValue().
2645
 *
2646
 * This method is the same as the C function GDALSetRasterNoDataValue().
2647
 *
2648
 * @param dfNoData the value to set.
2649
 *
2650
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2651
 * by the driver, CE_Failure is returned but no error message will have
2652
 * been emitted.
2653
 */
2654
2655
/**/
2656
/**/
2657
2658
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2659
2660
0
{
2661
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2662
0
        ReportError(CE_Failure, CPLE_NotSupported,
2663
0
                    "SetNoDataValue() not supported for this dataset.");
2664
2665
0
    return CE_Failure;
2666
0
}
2667
2668
/************************************************************************/
2669
/*                      GDALSetRasterNoDataValue()                      */
2670
/************************************************************************/
2671
2672
/**
2673
 * \brief Set the no data value for this band.
2674
 *
2675
 * Depending on drivers, changing the no data value may or may not have an
2676
 * effect on the pixel values of a raster that has just been created. It is
2677
 * thus advised to explicitly called Fill() if the intent is to initialize
2678
 * the raster to the nodata value.
2679
 * In any case, changing an existing no data value, when one already exists and
2680
 * the dataset exists or has been initialized, has no effect on the pixel whose
2681
 * value matched the previous nodata value.
2682
 *
2683
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2684
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2685
 * GDALSetRasterNoDataValueAsUInt64() instead.
2686
 *
2687
 * @see GDALRasterBand::SetNoDataValue()
2688
 */
2689
2690
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2691
                                            double dfValue)
2692
2693
0
{
2694
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2695
2696
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2697
0
    return poBand->SetNoDataValue(dfValue);
2698
0
}
2699
2700
/************************************************************************/
2701
/*                       SetNoDataValueAsInt64()                        */
2702
/************************************************************************/
2703
2704
/**
2705
 * \brief Set the no data value for this band.
2706
 *
2707
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2708
 *
2709
 * Depending on drivers, changing the no data value may or may not have an
2710
 * effect on the pixel values of a raster that has just been created. It is
2711
 * thus advised to explicitly called Fill() if the intent is to initialize
2712
 * the raster to the nodata value.
2713
 * In ay case, changing an existing no data value, when one already exists and
2714
 * the dataset exists or has been initialized, has no effect on the pixel whose
2715
 * value matched the previous nodata value.
2716
 *
2717
 * To clear the nodata value, use DeleteNoDataValue().
2718
 *
2719
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2720
 *
2721
 * @param nNoDataValue the value to set.
2722
 *
2723
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2724
 * by the driver, CE_Failure is returned but no error message will have
2725
 * been emitted.
2726
 *
2727
 * @since GDAL 3.5
2728
 */
2729
2730
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2731
2732
0
{
2733
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2734
0
        ReportError(CE_Failure, CPLE_NotSupported,
2735
0
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2736
2737
0
    return CE_Failure;
2738
0
}
2739
2740
/************************************************************************/
2741
/*                  GDALSetRasterNoDataValueAsInt64()                   */
2742
/************************************************************************/
2743
2744
/**
2745
 * \brief Set the no data value for this band.
2746
 *
2747
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2748
 *
2749
 * Depending on drivers, changing the no data value may or may not have an
2750
 * effect on the pixel values of a raster that has just been created. It is
2751
 * thus advised to explicitly called Fill() if the intent is to initialize
2752
 * the raster to the nodata value.
2753
 * In ay case, changing an existing no data value, when one already exists and
2754
 * the dataset exists or has been initialized, has no effect on the pixel whose
2755
 * value matched the previous nodata value.
2756
 *
2757
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2758
 *
2759
 * @since GDAL 3.5
2760
 */
2761
2762
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2763
                                                   int64_t nValue)
2764
2765
0
{
2766
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2767
2768
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2769
0
    return poBand->SetNoDataValueAsInt64(nValue);
2770
0
}
2771
2772
/************************************************************************/
2773
/*                       SetNoDataValueAsUInt64()                       */
2774
/************************************************************************/
2775
2776
/**
2777
 * \brief Set the no data value for this band.
2778
 *
2779
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2780
 *
2781
 * Depending on drivers, changing the no data value may or may not have an
2782
 * effect on the pixel values of a raster that has just been created. It is
2783
 * thus advised to explicitly called Fill() if the intent is to initialize
2784
 * the raster to the nodata value.
2785
 * In ay case, changing an existing no data value, when one already exists and
2786
 * the dataset exists or has been initialized, has no effect on the pixel whose
2787
 * value matched the previous nodata value.
2788
 *
2789
 * To clear the nodata value, use DeleteNoDataValue().
2790
 *
2791
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2792
 *
2793
 * @param nNoDataValue the value to set.
2794
 *
2795
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2796
 * by the driver, CE_Failure is returned but no error message will have
2797
 * been emitted.
2798
 *
2799
 * @since GDAL 3.5
2800
 */
2801
2802
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2803
2804
0
{
2805
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2806
0
        ReportError(CE_Failure, CPLE_NotSupported,
2807
0
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2808
2809
0
    return CE_Failure;
2810
0
}
2811
2812
/************************************************************************/
2813
/*                  GDALSetRasterNoDataValueAsUInt64()                  */
2814
/************************************************************************/
2815
2816
/**
2817
 * \brief Set the no data value for this band.
2818
 *
2819
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2820
 *
2821
 * Depending on drivers, changing the no data value may or may not have an
2822
 * effect on the pixel values of a raster that has just been created. It is
2823
 * thus advised to explicitly called Fill() if the intent is to initialize
2824
 * the raster to the nodata value.
2825
 * In ay case, changing an existing no data value, when one already exists and
2826
 * the dataset exists or has been initialized, has no effect on the pixel whose
2827
 * value matched the previous nodata value.
2828
 *
2829
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2830
 *
2831
 * @since GDAL 3.5
2832
 */
2833
2834
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2835
                                                    uint64_t nValue)
2836
2837
0
{
2838
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2839
2840
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2841
0
    return poBand->SetNoDataValueAsUInt64(nValue);
2842
0
}
2843
2844
/************************************************************************/
2845
/*                         DeleteNoDataValue()                          */
2846
/************************************************************************/
2847
2848
/**
2849
 * \brief Remove the no data value for this band.
2850
 *
2851
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2852
 *
2853
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2854
 * by the driver, CE_Failure is returned but no error message will have
2855
 * been emitted.
2856
 *
2857
 */
2858
2859
CPLErr GDALRasterBand::DeleteNoDataValue()
2860
2861
0
{
2862
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2863
0
        ReportError(CE_Failure, CPLE_NotSupported,
2864
0
                    "DeleteNoDataValue() not supported for this dataset.");
2865
2866
0
    return CE_Failure;
2867
0
}
2868
2869
/************************************************************************/
2870
/*                    GDALDeleteRasterNoDataValue()                     */
2871
/************************************************************************/
2872
2873
/**
2874
 * \brief Remove the no data value for this band.
2875
 *
2876
 * @see GDALRasterBand::DeleteNoDataValue()
2877
 *
2878
 */
2879
2880
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2881
2882
0
{
2883
0
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2884
2885
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2886
0
    return poBand->DeleteNoDataValue();
2887
0
}
2888
2889
/************************************************************************/
2890
/*                             GetMaximum()                             */
2891
/************************************************************************/
2892
2893
/**
2894
 * \brief Fetch the maximum value for this band.
2895
 *
2896
 * For file formats that don't know this intrinsically, the maximum supported
2897
 * value for the data type will generally be returned.
2898
 *
2899
 * This method is the same as the C function GDALGetRasterMaximum().
2900
 *
2901
 * @param pbSuccess pointer to a boolean to use to indicate if the
2902
 * returned value is a tight maximum or not.  May be NULL (default).
2903
 *
2904
 * @return the maximum raster value (excluding no data pixels)
2905
 */
2906
2907
double GDALRasterBand::GetMaximum(int *pbSuccess)
2908
2909
0
{
2910
0
    const char *pszValue = nullptr;
2911
2912
0
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2913
0
    {
2914
0
        if (pbSuccess != nullptr)
2915
0
            *pbSuccess = TRUE;
2916
2917
0
        return CPLAtofM(pszValue);
2918
0
    }
2919
2920
0
    if (pbSuccess != nullptr)
2921
0
        *pbSuccess = FALSE;
2922
2923
0
    switch (eDataType)
2924
0
    {
2925
0
        case GDT_UInt8:
2926
0
        {
2927
0
            EnablePixelTypeSignedByteWarning(false);
2928
0
            const char *pszPixelType =
2929
0
                GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
2930
0
            EnablePixelTypeSignedByteWarning(true);
2931
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2932
0
                return 127;
2933
2934
0
            return 255;
2935
0
        }
2936
2937
0
        case GDT_Int8:
2938
0
            return 127;
2939
2940
0
        case GDT_UInt16:
2941
0
            return 65535;
2942
2943
0
        case GDT_Int16:
2944
0
        case GDT_CInt16:
2945
0
            return 32767;
2946
2947
0
        case GDT_Int32:
2948
0
        case GDT_CInt32:
2949
0
            return 2147483647.0;
2950
2951
0
        case GDT_UInt32:
2952
0
            return 4294967295.0;
2953
2954
0
        case GDT_Int64:
2955
0
            return static_cast<double>(std::numeric_limits<GInt64>::max());
2956
2957
0
        case GDT_UInt64:
2958
0
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
2959
2960
0
        case GDT_Float16:
2961
0
        case GDT_CFloat16:
2962
0
            return 65504.0;
2963
2964
0
        case GDT_Float32:
2965
0
        case GDT_CFloat32:
2966
0
            return 4294967295.0;  // Not actually accurate.
2967
2968
0
        case GDT_Float64:
2969
0
        case GDT_CFloat64:
2970
0
            return 4294967295.0;  // Not actually accurate.
2971
2972
0
        case GDT_Unknown:
2973
0
        case GDT_TypeCount:
2974
0
            break;
2975
0
    }
2976
0
    return 4294967295.0;  // Not actually accurate.
2977
0
}
2978
2979
/************************************************************************/
2980
/*                        GDALGetRasterMaximum()                        */
2981
/************************************************************************/
2982
2983
/**
2984
 * \brief Fetch the maximum value for this band.
2985
 *
2986
 * @see GDALRasterBand::GetMaximum()
2987
 */
2988
2989
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2990
2991
0
{
2992
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2993
2994
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2995
0
    return poBand->GetMaximum(pbSuccess);
2996
0
}
2997
2998
/************************************************************************/
2999
/*                             GetMinimum()                             */
3000
/************************************************************************/
3001
3002
/**
3003
 * \brief Fetch the minimum value for this band.
3004
 *
3005
 * For file formats that don't know this intrinsically, the minimum supported
3006
 * value for the data type will generally be returned.
3007
 *
3008
 * This method is the same as the C function GDALGetRasterMinimum().
3009
 *
3010
 * @param pbSuccess pointer to a boolean to use to indicate if the
3011
 * returned value is a tight minimum or not.  May be NULL (default).
3012
 *
3013
 * @return the minimum raster value (excluding no data pixels)
3014
 */
3015
3016
double GDALRasterBand::GetMinimum(int *pbSuccess)
3017
3018
0
{
3019
0
    const char *pszValue = nullptr;
3020
3021
0
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3022
0
    {
3023
0
        if (pbSuccess != nullptr)
3024
0
            *pbSuccess = TRUE;
3025
3026
0
        return CPLAtofM(pszValue);
3027
0
    }
3028
3029
0
    if (pbSuccess != nullptr)
3030
0
        *pbSuccess = FALSE;
3031
3032
0
    switch (eDataType)
3033
0
    {
3034
0
        case GDT_UInt8:
3035
0
        {
3036
0
            EnablePixelTypeSignedByteWarning(false);
3037
0
            const char *pszPixelType =
3038
0
                GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
3039
0
            EnablePixelTypeSignedByteWarning(true);
3040
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3041
0
                return -128;
3042
3043
0
            return 0;
3044
0
        }
3045
3046
0
        case GDT_Int8:
3047
0
            return -128;
3048
3049
0
        case GDT_UInt16:
3050
0
            return 0;
3051
3052
0
        case GDT_Int16:
3053
0
        case GDT_CInt16:
3054
0
            return -32768;
3055
3056
0
        case GDT_Int32:
3057
0
        case GDT_CInt32:
3058
0
            return -2147483648.0;
3059
3060
0
        case GDT_UInt32:
3061
0
            return 0;
3062
3063
0
        case GDT_Int64:
3064
0
            return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3065
3066
0
        case GDT_UInt64:
3067
0
            return 0;
3068
3069
0
        case GDT_Float16:
3070
0
        case GDT_CFloat16:
3071
0
            return -65504.0;
3072
3073
0
        case GDT_Float32:
3074
0
        case GDT_CFloat32:
3075
0
            return -4294967295.0;  // Not actually accurate.
3076
3077
0
        case GDT_Float64:
3078
0
        case GDT_CFloat64:
3079
0
            return -4294967295.0;  // Not actually accurate.
3080
3081
0
        case GDT_Unknown:
3082
0
        case GDT_TypeCount:
3083
0
            break;
3084
0
    }
3085
0
    return -4294967295.0;  // Not actually accurate.
3086
0
}
3087
3088
/************************************************************************/
3089
/*                        GDALGetRasterMinimum()                        */
3090
/************************************************************************/
3091
3092
/**
3093
 * \brief Fetch the minimum value for this band.
3094
 *
3095
 * @see GDALRasterBand::GetMinimum()
3096
 */
3097
3098
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3099
3100
0
{
3101
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3102
3103
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3104
0
    return poBand->GetMinimum(pbSuccess);
3105
0
}
3106
3107
/************************************************************************/
3108
/*                       GetColorInterpretation()                       */
3109
/************************************************************************/
3110
3111
/**
3112
 * \brief How should this band be interpreted as color?
3113
 *
3114
 * GCI_Undefined is returned when the format doesn't know anything
3115
 * about the color interpretation.
3116
 *
3117
 * This method is the same as the C function
3118
 * GDALGetRasterColorInterpretation().
3119
 *
3120
 * @return color interpretation value for band.
3121
 */
3122
3123
GDALColorInterp GDALRasterBand::GetColorInterpretation()
3124
3125
0
{
3126
0
    return GCI_Undefined;
3127
0
}
3128
3129
/************************************************************************/
3130
/*                  GDALGetRasterColorInterpretation()                  */
3131
/************************************************************************/
3132
3133
/**
3134
 * \brief How should this band be interpreted as color?
3135
 *
3136
 * @see GDALRasterBand::GetColorInterpretation()
3137
 */
3138
3139
GDALColorInterp CPL_STDCALL
3140
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3141
3142
0
{
3143
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3144
3145
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3146
0
    return poBand->GetColorInterpretation();
3147
0
}
3148
3149
/************************************************************************/
3150
/*                       SetColorInterpretation()                       */
3151
/************************************************************************/
3152
3153
/**
3154
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3155
 * \brief Set color interpretation of a band.
3156
 *
3157
 * This method is the same as the C function GDALSetRasterColorInterpretation().
3158
 *
3159
 * @param eColorInterp the new color interpretation to apply to this band.
3160
 *
3161
 * @return CE_None on success or CE_Failure if method is unsupported by format.
3162
 */
3163
3164
/**/
3165
/**/
3166
3167
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3168
3169
0
{
3170
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3171
0
        ReportError(CE_Failure, CPLE_NotSupported,
3172
0
                    "SetColorInterpretation() not supported for this dataset.");
3173
0
    return CE_Failure;
3174
0
}
3175
3176
/************************************************************************/
3177
/*                  GDALSetRasterColorInterpretation()                  */
3178
/************************************************************************/
3179
3180
/**
3181
 * \brief Set color interpretation of a band.
3182
 *
3183
 * @see GDALRasterBand::SetColorInterpretation()
3184
 */
3185
3186
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3187
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3188
3189
0
{
3190
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3191
3192
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3193
0
    return poBand->SetColorInterpretation(eColorInterp);
3194
0
}
3195
3196
/************************************************************************/
3197
/*                           GetColorTable()                            */
3198
/************************************************************************/
3199
3200
/**
3201
 * \brief Fetch the color table associated with band.
3202
 *
3203
 * If there is no associated color table, the return result is NULL.  The
3204
 * returned color table remains owned by the GDALRasterBand, and can't
3205
 * be depended on for long, nor should it ever be modified by the caller.
3206
 *
3207
 * This method is the same as the C function GDALGetRasterColorTable().
3208
 *
3209
 * @return internal color table, or NULL.
3210
 */
3211
3212
GDALColorTable *GDALRasterBand::GetColorTable()
3213
3214
0
{
3215
0
    return nullptr;
3216
0
}
3217
3218
/************************************************************************/
3219
/*                      GDALGetRasterColorTable()                       */
3220
/************************************************************************/
3221
3222
/**
3223
 * \brief Fetch the color table associated with band.
3224
 *
3225
 * @see GDALRasterBand::GetColorTable()
3226
 */
3227
3228
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3229
3230
0
{
3231
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3232
3233
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3234
0
    return GDALColorTable::ToHandle(poBand->GetColorTable());
3235
0
}
3236
3237
/************************************************************************/
3238
/*                           SetColorTable()                            */
3239
/************************************************************************/
3240
3241
/**
3242
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3243
 * \brief Set the raster color table.
3244
 *
3245
 * The driver will make a copy of all desired data in the colortable.  It
3246
 * remains owned by the caller after the call.
3247
 *
3248
 * This method is the same as the C function GDALSetRasterColorTable().
3249
 *
3250
 * @param poCT the color table to apply.  This may be NULL to clear the color
3251
 * table (where supported).
3252
 *
3253
 * @return CE_None on success, or CE_Failure on failure.  If the action is
3254
 * unsupported by the driver, a value of CE_Failure is returned, but no
3255
 * error is issued.
3256
 */
3257
3258
/**/
3259
/**/
3260
3261
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3262
3263
0
{
3264
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3265
0
        ReportError(CE_Failure, CPLE_NotSupported,
3266
0
                    "SetColorTable() not supported for this dataset.");
3267
0
    return CE_Failure;
3268
0
}
3269
3270
/************************************************************************/
3271
/*                      GDALSetRasterColorTable()                       */
3272
/************************************************************************/
3273
3274
/**
3275
 * \brief Set the raster color table.
3276
 *
3277
 * @see GDALRasterBand::SetColorTable()
3278
 */
3279
3280
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3281
                                           GDALColorTableH hCT)
3282
3283
0
{
3284
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3285
3286
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3287
0
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3288
0
}
3289
3290
/************************************************************************/
3291
/*                       HasArbitraryOverviews()                        */
3292
/************************************************************************/
3293
3294
/**
3295
 * \brief Check for arbitrary overviews.
3296
 *
3297
 * This returns TRUE if the underlying datastore can compute arbitrary
3298
 * overviews efficiently, such as is the case with OGDI over a network.
3299
 * Datastores with arbitrary overviews don't generally have any fixed
3300
 * overviews, but the RasterIO() method can be used in downsampling mode
3301
 * to get overview data efficiently.
3302
 *
3303
 * This method is the same as the C function GDALHasArbitraryOverviews(),
3304
 *
3305
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
3306
 * FALSE.
3307
 */
3308
3309
int GDALRasterBand::HasArbitraryOverviews()
3310
3311
0
{
3312
0
    return FALSE;
3313
0
}
3314
3315
/************************************************************************/
3316
/*                     GDALHasArbitraryOverviews()                      */
3317
/************************************************************************/
3318
3319
/**
3320
 * \brief Check for arbitrary overviews.
3321
 *
3322
 * @see GDALRasterBand::HasArbitraryOverviews()
3323
 */
3324
3325
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3326
3327
0
{
3328
0
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3329
3330
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3331
0
    return poBand->HasArbitraryOverviews();
3332
0
}
3333
3334
/************************************************************************/
3335
/*                          GetOverviewCount()                          */
3336
/************************************************************************/
3337
3338
/**
3339
 * \brief Return the number of overview layers available.
3340
 *
3341
 * This method is the same as the C function GDALGetOverviewCount().
3342
 *
3343
 * @return overview count, zero if none.
3344
 */
3345
3346
int GDALRasterBand::GetOverviewCount()
3347
3348
0
{
3349
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3350
0
        poDS->AreOverviewsEnabled())
3351
0
        return poDS->oOvManager.GetOverviewCount(nBand);
3352
3353
0
    return 0;
3354
0
}
3355
3356
/************************************************************************/
3357
/*                        GDALGetOverviewCount()                        */
3358
/************************************************************************/
3359
3360
/**
3361
 * \brief Return the number of overview layers available.
3362
 *
3363
 * @see GDALRasterBand::GetOverviewCount()
3364
 */
3365
3366
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3367
3368
0
{
3369
0
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3370
3371
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3372
0
    return poBand->GetOverviewCount();
3373
0
}
3374
3375
/************************************************************************/
3376
/*                            GetOverview()                             */
3377
/************************************************************************/
3378
3379
/**
3380
 * \brief Fetch overview raster band object.
3381
 *
3382
 * This method is the same as the C function GDALGetOverview().
3383
 *
3384
 * @param i overview index between 0 and GetOverviewCount()-1.
3385
 *
3386
 * @return overview GDALRasterBand.
3387
 */
3388
3389
GDALRasterBand *GDALRasterBand::GetOverview(int i)
3390
3391
0
{
3392
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3393
0
        poDS->AreOverviewsEnabled())
3394
0
        return poDS->oOvManager.GetOverview(nBand, i);
3395
3396
0
    return nullptr;
3397
0
}
3398
3399
/************************************************************************/
3400
/*                          GDALGetOverview()                           */
3401
/************************************************************************/
3402
3403
/**
3404
 * \brief Fetch overview raster band object.
3405
 *
3406
 * @see GDALRasterBand::GetOverview()
3407
 */
3408
3409
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3410
3411
0
{
3412
0
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3413
3414
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3415
0
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3416
0
}
3417
3418
/************************************************************************/
3419
/*                      GetRasterSampleOverview()                       */
3420
/************************************************************************/
3421
3422
/**
3423
 * \brief Fetch best sampling overview.
3424
 *
3425
 * Returns the most reduced overview of the given band that still satisfies
3426
 * the desired number of samples.  This function can be used with zero
3427
 * as the number of desired samples to fetch the most reduced overview.
3428
 * The same band as was passed in will be returned if it has not overviews,
3429
 * or if none of the overviews have enough samples.
3430
 *
3431
 * This method is the same as the C functions GDALGetRasterSampleOverview()
3432
 * and GDALGetRasterSampleOverviewEx().
3433
 *
3434
 * @param nDesiredSamples the returned band will have at least this many
3435
 * pixels.
3436
 *
3437
 * @return optimal overview or the band itself.
3438
 */
3439
3440
GDALRasterBand *
3441
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3442
3443
0
{
3444
0
    GDALRasterBand *poBestBand = this;
3445
3446
0
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3447
3448
0
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3449
0
    {
3450
0
        GDALRasterBand *poOBand = GetOverview(iOverview);
3451
3452
0
        if (poOBand == nullptr)
3453
0
            continue;
3454
3455
0
        const double dfOSamples =
3456
0
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3457
3458
0
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3459
0
        {
3460
0
            dfBestSamples = dfOSamples;
3461
0
            poBestBand = poOBand;
3462
0
        }
3463
0
    }
3464
3465
0
    return poBestBand;
3466
0
}
3467
3468
/************************************************************************/
3469
/*                    GDALGetRasterSampleOverview()                     */
3470
/************************************************************************/
3471
3472
/**
3473
 * \brief Fetch best sampling overview.
3474
 *
3475
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3476
 * billion samples.
3477
 *
3478
 * @see GDALRasterBand::GetRasterSampleOverview()
3479
 * @see GDALGetRasterSampleOverviewEx()
3480
 */
3481
3482
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3483
                                                        int nDesiredSamples)
3484
3485
0
{
3486
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3487
3488
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3489
0
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3490
0
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3491
0
}
3492
3493
/************************************************************************/
3494
/*                   GDALGetRasterSampleOverviewEx()                    */
3495
/************************************************************************/
3496
3497
/**
3498
 * \brief Fetch best sampling overview.
3499
 *
3500
 * @see GDALRasterBand::GetRasterSampleOverview()
3501
 */
3502
3503
GDALRasterBandH CPL_STDCALL
3504
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3505
3506
0
{
3507
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3508
3509
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3510
0
    return GDALRasterBand::ToHandle(
3511
0
        poBand->GetRasterSampleOverview(nDesiredSamples));
3512
0
}
3513
3514
/************************************************************************/
3515
/*                           BuildOverviews()                           */
3516
/************************************************************************/
3517
3518
/**
3519
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3520
 * GDALProgressFunc, void*) \brief Build raster overview(s)
3521
 *
3522
 * If the operation is unsupported for the indicated dataset, then
3523
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
3524
 * CPLE_NotSupported.
3525
 *
3526
 * WARNING: Most formats don't support per-band overview computation, but
3527
 * require that overviews are computed for all bands of a dataset, using
3528
 * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3529
 * is the HFA driver which supports this method.
3530
 *
3531
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3532
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3533
 * applied.
3534
 * @param nOverviews number of overviews to build.
3535
 * @param panOverviewList the list of overview decimation factors to build.
3536
 * @param pfnProgress a function to call to report progress, or NULL.
3537
 * @param pProgressData application data to pass to the progress function.
3538
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3539
 *                     key=value pairs, or NULL
3540
 *
3541
 * @return CE_None on success or CE_Failure if the operation doesn't work.
3542
 */
3543
3544
/**/
3545
/**/
3546
3547
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3548
                                      int /*nOverviews*/,
3549
                                      const int * /*panOverviewList*/,
3550
                                      GDALProgressFunc /*pfnProgress*/,
3551
                                      void * /*pProgressData*/,
3552
                                      CSLConstList /* papszOptions */)
3553
3554
0
{
3555
0
    ReportError(CE_Failure, CPLE_NotSupported,
3556
0
                "BuildOverviews() not supported for this dataset.");
3557
3558
0
    return (CE_Failure);
3559
0
}
3560
3561
/************************************************************************/
3562
/*                             GetOffset()                              */
3563
/************************************************************************/
3564
3565
/**
3566
 * \brief Fetch the raster value offset.
3567
 *
3568
 * This value (in combination with the GetScale() value) can be used to
3569
 * transform raw pixel values into the units returned by GetUnitType().
3570
 * For example this might be used to store elevations in GUInt16 bands
3571
 * with a precision of 0.1, and starting from -100.
3572
 *
3573
 * Units value = (raw value * scale) + offset
3574
 *
3575
 * Note that applying scale and offset is of the responsibility of the user,
3576
 * and is not done by methods such as RasterIO() or ReadBlock().
3577
 *
3578
 * For file formats that don't know this intrinsically a value of zero
3579
 * is returned.
3580
 *
3581
 * This method is the same as the C function GDALGetRasterOffset().
3582
 *
3583
 * @param pbSuccess pointer to a boolean to use to indicate if the
3584
 * returned value is meaningful or not.  May be NULL (default).
3585
 *
3586
 * @return the raster offset.
3587
 */
3588
3589
double GDALRasterBand::GetOffset(int *pbSuccess)
3590
3591
0
{
3592
0
    if (pbSuccess != nullptr)
3593
0
        *pbSuccess = FALSE;
3594
3595
0
    return 0.0;
3596
0
}
3597
3598
/************************************************************************/
3599
/*                        GDALGetRasterOffset()                         */
3600
/************************************************************************/
3601
3602
/**
3603
 * \brief Fetch the raster value offset.
3604
 *
3605
 * @see GDALRasterBand::GetOffset()
3606
 */
3607
3608
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3609
3610
0
{
3611
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3612
3613
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3614
0
    return poBand->GetOffset(pbSuccess);
3615
0
}
3616
3617
/************************************************************************/
3618
/*                             SetOffset()                              */
3619
/************************************************************************/
3620
3621
/**
3622
 * \fn GDALRasterBand::SetOffset(double)
3623
 * \brief Set scaling offset.
3624
 *
3625
 * Very few formats implement this method.   When not implemented it will
3626
 * issue a CPLE_NotSupported error and return CE_Failure.
3627
 *
3628
 * This method is the same as the C function GDALSetRasterOffset().
3629
 *
3630
 * @param dfNewOffset the new offset.
3631
 *
3632
 * @return CE_None or success or CE_Failure on failure.
3633
 */
3634
3635
/**/
3636
/**/
3637
3638
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3639
0
{
3640
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3641
0
        ReportError(CE_Failure, CPLE_NotSupported,
3642
0
                    "SetOffset() not supported on this raster band.");
3643
3644
0
    return CE_Failure;
3645
0
}
3646
3647
/************************************************************************/
3648
/*                        GDALSetRasterOffset()                         */
3649
/************************************************************************/
3650
3651
/**
3652
 * \brief Set scaling offset.
3653
 *
3654
 * @see GDALRasterBand::SetOffset()
3655
 */
3656
3657
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3658
                                       double dfNewOffset)
3659
3660
0
{
3661
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3662
3663
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3664
0
    return poBand->SetOffset(dfNewOffset);
3665
0
}
3666
3667
/************************************************************************/
3668
/*                              GetScale()                              */
3669
/************************************************************************/
3670
3671
/**
3672
 * \brief Fetch the raster value scale.
3673
 *
3674
 * This value (in combination with the GetOffset() value) can be used to
3675
 * transform raw pixel values into the units returned by GetUnitType().
3676
 * For example this might be used to store elevations in GUInt16 bands
3677
 * with a precision of 0.1, and starting from -100.
3678
 *
3679
 * Units value = (raw value * scale) + offset
3680
 *
3681
 * Note that applying scale and offset is of the responsibility of the user,
3682
 * and is not done by methods such as RasterIO() or ReadBlock().
3683
 *
3684
 * For file formats that don't know this intrinsically a value of one
3685
 * is returned.
3686
 *
3687
 * This method is the same as the C function GDALGetRasterScale().
3688
 *
3689
 * @param pbSuccess pointer to a boolean to use to indicate if the
3690
 * returned value is meaningful or not.  May be NULL (default).
3691
 *
3692
 * @return the raster scale.
3693
 */
3694
3695
double GDALRasterBand::GetScale(int *pbSuccess)
3696
3697
0
{
3698
0
    if (pbSuccess != nullptr)
3699
0
        *pbSuccess = FALSE;
3700
3701
0
    return 1.0;
3702
0
}
3703
3704
/************************************************************************/
3705
/*                         GDALGetRasterScale()                         */
3706
/************************************************************************/
3707
3708
/**
3709
 * \brief Fetch the raster value scale.
3710
 *
3711
 * @see GDALRasterBand::GetScale()
3712
 */
3713
3714
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3715
3716
0
{
3717
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3718
3719
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3720
0
    return poBand->GetScale(pbSuccess);
3721
0
}
3722
3723
/************************************************************************/
3724
/*                              SetScale()                              */
3725
/************************************************************************/
3726
3727
/**
3728
 * \fn GDALRasterBand::SetScale(double)
3729
 * \brief Set scaling ratio.
3730
 *
3731
 * Very few formats implement this method.   When not implemented it will
3732
 * issue a CPLE_NotSupported error and return CE_Failure.
3733
 *
3734
 * This method is the same as the C function GDALSetRasterScale().
3735
 *
3736
 * @param dfNewScale the new scale.
3737
 *
3738
 * @return CE_None or success or CE_Failure on failure.
3739
 */
3740
3741
/**/
3742
/**/
3743
3744
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3745
3746
0
{
3747
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3748
0
        ReportError(CE_Failure, CPLE_NotSupported,
3749
0
                    "SetScale() not supported on this raster band.");
3750
3751
0
    return CE_Failure;
3752
0
}
3753
3754
/************************************************************************/
3755
/*                         GDALSetRasterScale()                         */
3756
/************************************************************************/
3757
3758
/**
3759
 * \brief Set scaling ratio.
3760
 *
3761
 * @see GDALRasterBand::SetScale()
3762
 */
3763
3764
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3765
3766
0
{
3767
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3768
3769
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3770
0
    return poBand->SetScale(dfNewOffset);
3771
0
}
3772
3773
/************************************************************************/
3774
/*                            GetUnitType()                             */
3775
/************************************************************************/
3776
3777
/**
3778
 * \brief Return raster unit type.
3779
 *
3780
 * Return a name for the units of this raster's values.  For instance, it
3781
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3782
 * units are available, a value of "" will be returned.  The returned string
3783
 * should not be modified, nor freed by the calling application.
3784
 *
3785
 * This method is the same as the C function GDALGetRasterUnitType().
3786
 *
3787
 * @return unit name string.
3788
 */
3789
3790
const char *GDALRasterBand::GetUnitType()
3791
3792
0
{
3793
0
    return "";
3794
0
}
3795
3796
/************************************************************************/
3797
/*                       GDALGetRasterUnitType()                        */
3798
/************************************************************************/
3799
3800
/**
3801
 * \brief Return raster unit type.
3802
 *
3803
 * @see GDALRasterBand::GetUnitType()
3804
 */
3805
3806
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3807
3808
0
{
3809
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3810
3811
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3812
0
    return poBand->GetUnitType();
3813
0
}
3814
3815
/************************************************************************/
3816
/*                            SetUnitType()                             */
3817
/************************************************************************/
3818
3819
/**
3820
 * \fn GDALRasterBand::SetUnitType(const char*)
3821
 * \brief Set unit type.
3822
 *
3823
 * Set the unit type for a raster band.  Values should be one of
3824
 * "" (the default indicating it is unknown), "m" indicating meters,
3825
 * or "ft" indicating feet, though other nonstandard values are allowed.
3826
 *
3827
 * This method is the same as the C function GDALSetRasterUnitType().
3828
 *
3829
 * @param pszNewValue the new unit type value.
3830
 *
3831
 * @return CE_None on success or CE_Failure if not successful, or
3832
 * unsupported.
3833
 */
3834
3835
/**/
3836
/**/
3837
3838
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3839
3840
0
{
3841
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3842
0
        ReportError(CE_Failure, CPLE_NotSupported,
3843
0
                    "SetUnitType() not supported on this raster band.");
3844
0
    return CE_Failure;
3845
0
}
3846
3847
/************************************************************************/
3848
/*                       GDALSetRasterUnitType()                        */
3849
/************************************************************************/
3850
3851
/**
3852
 * \brief Set unit type.
3853
 *
3854
 * @see GDALRasterBand::SetUnitType()
3855
 *
3856
 */
3857
3858
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3859
                                         const char *pszNewValue)
3860
3861
0
{
3862
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3863
3864
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3865
0
    return poBand->SetUnitType(pszNewValue);
3866
0
}
3867
3868
/************************************************************************/
3869
/*                              GetXSize()                              */
3870
/************************************************************************/
3871
3872
/**
3873
 * \brief Fetch XSize of raster.
3874
 *
3875
 * This method is the same as the C function GDALGetRasterBandXSize().
3876
 *
3877
 * @return the width in pixels of this band.
3878
 */
3879
3880
int GDALRasterBand::GetXSize() const
3881
3882
0
{
3883
0
    return nRasterXSize;
3884
0
}
3885
3886
/************************************************************************/
3887
/*                       GDALGetRasterBandXSize()                       */
3888
/************************************************************************/
3889
3890
/**
3891
 * \brief Fetch XSize of raster.
3892
 *
3893
 * @see GDALRasterBand::GetXSize()
3894
 */
3895
3896
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3897
3898
0
{
3899
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3900
3901
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3902
0
    return poBand->GetXSize();
3903
0
}
3904
3905
/************************************************************************/
3906
/*                              GetYSize()                              */
3907
/************************************************************************/
3908
3909
/**
3910
 * \brief Fetch YSize of raster.
3911
 *
3912
 * This method is the same as the C function GDALGetRasterBandYSize().
3913
 *
3914
 * @return the height in pixels of this band.
3915
 */
3916
3917
int GDALRasterBand::GetYSize() const
3918
3919
0
{
3920
0
    return nRasterYSize;
3921
0
}
3922
3923
/************************************************************************/
3924
/*                       GDALGetRasterBandYSize()                       */
3925
/************************************************************************/
3926
3927
/**
3928
 * \brief Fetch YSize of raster.
3929
 *
3930
 * @see GDALRasterBand::GetYSize()
3931
 */
3932
3933
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3934
3935
0
{
3936
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3937
3938
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3939
0
    return poBand->GetYSize();
3940
0
}
3941
3942
/************************************************************************/
3943
/*                              GetBand()                               */
3944
/************************************************************************/
3945
3946
/**
3947
 * \brief Fetch the band number.
3948
 *
3949
 * This method returns the band that this GDALRasterBand objects represents
3950
 * within its dataset.  This method may return a value of 0 to indicate
3951
 * GDALRasterBand objects without an apparently relationship to a dataset,
3952
 * such as GDALRasterBands serving as overviews.
3953
 *
3954
 * This method is the same as the C function GDALGetBandNumber().
3955
 *
3956
 * @return band number (1+) or 0 if the band number isn't known.
3957
 */
3958
3959
int GDALRasterBand::GetBand() const
3960
3961
0
{
3962
0
    return nBand;
3963
0
}
3964
3965
/************************************************************************/
3966
/*                         GDALGetBandNumber()                          */
3967
/************************************************************************/
3968
3969
/**
3970
 * \brief Fetch the band number.
3971
 *
3972
 * @see GDALRasterBand::GetBand()
3973
 */
3974
3975
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3976
3977
0
{
3978
0
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3979
3980
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3981
0
    return poBand->GetBand();
3982
0
}
3983
3984
/************************************************************************/
3985
/*                             GetDataset()                             */
3986
/************************************************************************/
3987
3988
/**
3989
 * \brief Fetch the owning dataset handle.
3990
 *
3991
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3992
 * such as overviews or other "freestanding" bands.
3993
 *
3994
 * This method is the same as the C function GDALGetBandDataset().
3995
 *
3996
 * @return the pointer to the GDALDataset to which this band belongs, or
3997
 * NULL if this cannot be determined.
3998
 */
3999
4000
GDALDataset *GDALRasterBand::GetDataset() const
4001
4002
0
{
4003
0
    return poDS;
4004
0
}
4005
4006
/************************************************************************/
4007
/*                         GDALGetBandDataset()                         */
4008
/************************************************************************/
4009
4010
/**
4011
 * \brief Fetch the owning dataset handle.
4012
 *
4013
 * @see GDALRasterBand::GetDataset()
4014
 */
4015
4016
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4017
4018
0
{
4019
0
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4020
4021
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4022
0
    return GDALDataset::ToHandle(poBand->GetDataset());
4023
0
}
4024
4025
/************************************************************************/
4026
/*                     ComputeFloat16NoDataValue()                      */
4027
/************************************************************************/
4028
4029
static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4030
                                             double dfNoDataValue,
4031
                                             int &bGotNoDataValue,
4032
                                             GFloat16 &hfNoDataValue,
4033
                                             bool &bGotFloat16NoDataValue)
4034
0
{
4035
0
    if (eDataType == GDT_Float16 && bGotNoDataValue)
4036
0
    {
4037
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4038
0
        if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4039
0
        {
4040
0
            hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4041
0
            bGotFloat16NoDataValue = true;
4042
0
            bGotNoDataValue = false;
4043
0
        }
4044
0
    }
4045
0
}
4046
4047
/************************************************************************/
4048
/*                      ComputeFloatNoDataValue()                       */
4049
/************************************************************************/
4050
4051
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4052
                                           double dfNoDataValue,
4053
                                           int &bGotNoDataValue,
4054
                                           float &fNoDataValue,
4055
                                           bool &bGotFloatNoDataValue)
4056
0
{
4057
0
    if (eDataType == GDT_Float32 && bGotNoDataValue)
4058
0
    {
4059
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4060
0
        if (GDALIsValueInRange<float>(dfNoDataValue))
4061
0
        {
4062
0
            fNoDataValue = static_cast<float>(dfNoDataValue);
4063
0
            bGotFloatNoDataValue = true;
4064
0
            bGotNoDataValue = false;
4065
0
        }
4066
0
    }
4067
0
    else if (eDataType == GDT_Int16 && bGotNoDataValue &&
4068
0
             GDALIsValueExactAs<int16_t>(dfNoDataValue))
4069
0
    {
4070
0
        fNoDataValue = static_cast<float>(dfNoDataValue);
4071
0
        bGotFloatNoDataValue = true;
4072
0
    }
4073
0
    else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
4074
0
             GDALIsValueExactAs<uint16_t>(dfNoDataValue))
4075
0
    {
4076
0
        fNoDataValue = static_cast<float>(dfNoDataValue);
4077
0
        bGotFloatNoDataValue = true;
4078
0
    }
4079
0
    else if (eDataType == GDT_Float16 && bGotNoDataValue &&
4080
0
             GDALIsValueExactAs<GFloat16>(dfNoDataValue))
4081
0
    {
4082
0
        fNoDataValue = static_cast<float>(dfNoDataValue);
4083
0
        bGotFloatNoDataValue = true;
4084
0
    }
4085
0
}
4086
4087
/************************************************************************/
4088
/*                       struct GDALNoDataValues                        */
4089
/************************************************************************/
4090
4091
/**
4092
 * \brief No-data-values for all types
4093
 *
4094
 * The functions below pass various no-data-values around. To avoid
4095
 * long argument lists, this struct collects the no-data-values for
4096
 * all types into a single, convenient place.
4097
 **/
4098
4099
struct GDALNoDataValues
4100
{
4101
    int bGotNoDataValue;
4102
    double dfNoDataValue;
4103
4104
    bool bGotInt64NoDataValue;
4105
    int64_t nInt64NoDataValue;
4106
4107
    bool bGotUInt64NoDataValue;
4108
    uint64_t nUInt64NoDataValue;
4109
4110
    bool bGotFloatNoDataValue;
4111
    float fNoDataValue;
4112
4113
    bool bGotFloat16NoDataValue;
4114
    GFloat16 hfNoDataValue;
4115
4116
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4117
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4118
0
          bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4119
0
          bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4120
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4121
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4122
0
    {
4123
0
        if (eDataType == GDT_Int64)
4124
0
        {
4125
0
            int nGot = false;
4126
0
            nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4127
0
            bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4128
0
            if (bGotInt64NoDataValue)
4129
0
            {
4130
0
                dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4131
0
                bGotNoDataValue =
4132
0
                    nInt64NoDataValue <=
4133
0
                        std::numeric_limits<int64_t>::max() - 1024 &&
4134
0
                    static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4135
0
            }
4136
0
            else
4137
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4138
0
        }
4139
0
        else if (eDataType == GDT_UInt64)
4140
0
        {
4141
0
            int nGot = false;
4142
0
            nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4143
0
            bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4144
0
            if (bGotUInt64NoDataValue)
4145
0
            {
4146
0
                dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4147
0
                bGotNoDataValue =
4148
0
                    nUInt64NoDataValue <=
4149
0
                        std::numeric_limits<uint64_t>::max() - 2048 &&
4150
0
                    static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4151
0
            }
4152
0
            else
4153
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4154
0
        }
4155
0
        else
4156
0
        {
4157
0
            dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4158
0
            bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4159
4160
0
            ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4161
0
                                    fNoDataValue, bGotFloatNoDataValue);
4162
4163
0
            ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4164
0
                                      hfNoDataValue, bGotFloat16NoDataValue);
4165
0
        }
4166
0
    }
4167
};
4168
4169
/************************************************************************/
4170
/*                           ARE_REAL_EQUAL()                           */
4171
/************************************************************************/
4172
4173
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4174
0
{
4175
0
    using std::abs;
4176
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4177
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4178
0
                                      abs(dfVal1 + dfVal2) * ulp;
4179
0
}
4180
4181
/************************************************************************/
4182
/*                            GetHistogram()                            */
4183
/************************************************************************/
4184
4185
/**
4186
 * \brief Compute raster histogram.
4187
 *
4188
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4189
 *
4190
 * For example to compute a simple 256 entry histogram of eight bit data,
4191
 * the following would be suitable.  The unusual bounds are to ensure that
4192
 * bucket boundaries don't fall right on integer values causing possible errors
4193
 * due to rounding after scaling.
4194
\code{.cpp}
4195
    GUIntBig anHistogram[256];
4196
4197
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4198
                          GDALDummyProgress, nullptr );
4199
\endcode
4200
 *
4201
 * Note that setting bApproxOK will generally result in a subsampling of the
4202
 * file, and will utilize overviews if available.  It should generally
4203
 * produce a representative histogram for the data that is suitable for use
4204
 * in generating histogram based luts for instance.  Generally bApproxOK is
4205
 * much faster than an exactly computed histogram.
4206
 *
4207
 * This method is the same as the C functions GDALGetRasterHistogram() and
4208
 * GDALGetRasterHistogramEx().
4209
 *
4210
 * @param dfMin the lower bound of the histogram.
4211
 * @param dfMax the upper bound of the histogram.
4212
 * @param nBuckets the number of buckets in panHistogram.
4213
 * @param panHistogram array into which the histogram totals are placed.
4214
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4215
 * mapped into panHistogram[0], and values above will be mapped into
4216
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4217
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4218
 * @param pfnProgress function to report progress to completion.
4219
 * @param pProgressData application data to pass to pfnProgress.
4220
 *
4221
 * @return CE_None on success, or CE_Failure if something goes wrong.
4222
 */
4223
4224
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4225
                                    GUIntBig *panHistogram,
4226
                                    int bIncludeOutOfRange, int bApproxOK,
4227
                                    GDALProgressFunc pfnProgress,
4228
                                    void *pProgressData)
4229
4230
0
{
4231
0
    CPLAssert(nullptr != panHistogram);
4232
4233
0
    if (pfnProgress == nullptr)
4234
0
        pfnProgress = GDALDummyProgress;
4235
4236
    /* -------------------------------------------------------------------- */
4237
    /*      If we have overviews, use them for the histogram.               */
4238
    /* -------------------------------------------------------------------- */
4239
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4240
0
    {
4241
        // FIXME: should we use the most reduced overview here or use some
4242
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4243
        // does?
4244
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4245
4246
0
        if (poBestOverview != this)
4247
0
        {
4248
0
            return poBestOverview->GetHistogram(
4249
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4250
0
                bApproxOK, pfnProgress, pProgressData);
4251
0
        }
4252
0
    }
4253
4254
    /* -------------------------------------------------------------------- */
4255
    /*      Read actual data and build histogram.                           */
4256
    /* -------------------------------------------------------------------- */
4257
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4258
0
    {
4259
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4260
0
        return CE_Failure;
4261
0
    }
4262
4263
    // Written this way to deal with NaN
4264
0
    if (!(dfMax > dfMin))
4265
0
    {
4266
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4267
0
                    "dfMax should be strictly greater than dfMin");
4268
0
        return CE_Failure;
4269
0
    }
4270
4271
0
    GDALRasterIOExtraArg sExtraArg;
4272
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4273
4274
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4275
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4276
0
    {
4277
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4278
0
                    "dfMin and dfMax should be finite values such that "
4279
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4280
0
        return CE_Failure;
4281
0
    }
4282
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4283
4284
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4285
0
    GDALRasterBand *poMaskBand = nullptr;
4286
0
    if (!sNoDataValues.bGotNoDataValue)
4287
0
    {
4288
0
        const int l_nMaskFlags = GetMaskFlags();
4289
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
4290
0
            GetColorInterpretation() != GCI_AlphaBand)
4291
0
        {
4292
0
            poMaskBand = GetMaskBand();
4293
0
        }
4294
0
    }
4295
4296
0
    bool bSignedByte = false;
4297
0
    if (eDataType == GDT_UInt8)
4298
0
    {
4299
0
        EnablePixelTypeSignedByteWarning(false);
4300
0
        const char *pszPixelType =
4301
0
            GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
4302
0
        EnablePixelTypeSignedByteWarning(true);
4303
0
        bSignedByte =
4304
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4305
0
    }
4306
4307
0
    if (bApproxOK && HasArbitraryOverviews())
4308
0
    {
4309
        /* --------------------------------------------------------------------
4310
         */
4311
        /*      Figure out how much the image should be reduced to get an */
4312
        /*      approximate value. */
4313
        /* --------------------------------------------------------------------
4314
         */
4315
0
        const double dfReduction =
4316
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4317
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4318
4319
0
        int nXReduced = nRasterXSize;
4320
0
        int nYReduced = nRasterYSize;
4321
0
        if (dfReduction > 1.0)
4322
0
        {
4323
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4324
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4325
4326
            // Catch the case of huge resizing ratios here
4327
0
            if (nXReduced == 0)
4328
0
                nXReduced = 1;
4329
0
            if (nYReduced == 0)
4330
0
                nYReduced = 1;
4331
0
        }
4332
4333
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4334
0
                                          nXReduced, nYReduced);
4335
0
        if (!pData)
4336
0
            return CE_Failure;
4337
4338
0
        const CPLErr eErr =
4339
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4340
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4341
0
        if (eErr != CE_None)
4342
0
        {
4343
0
            CPLFree(pData);
4344
0
            return eErr;
4345
0
        }
4346
4347
0
        GByte *pabyMaskData = nullptr;
4348
0
        if (poMaskBand)
4349
0
        {
4350
0
            pabyMaskData =
4351
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4352
0
            if (!pabyMaskData)
4353
0
            {
4354
0
                CPLFree(pData);
4355
0
                return CE_Failure;
4356
0
            }
4357
4358
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4359
0
                                     pabyMaskData, nXReduced, nYReduced,
4360
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
4361
0
            {
4362
0
                CPLFree(pData);
4363
0
                CPLFree(pabyMaskData);
4364
0
                return CE_Failure;
4365
0
            }
4366
0
        }
4367
4368
        // This isn't the fastest way to do this, but is easier for now.
4369
0
        for (int iY = 0; iY < nYReduced; iY++)
4370
0
        {
4371
0
            for (int iX = 0; iX < nXReduced; iX++)
4372
0
            {
4373
0
                const int iOffset = iX + iY * nXReduced;
4374
0
                double dfValue = 0.0;
4375
4376
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4377
0
                    continue;
4378
4379
0
                switch (eDataType)
4380
0
                {
4381
0
                    case GDT_UInt8:
4382
0
                    {
4383
0
                        if (bSignedByte)
4384
0
                            dfValue =
4385
0
                                static_cast<signed char *>(pData)[iOffset];
4386
0
                        else
4387
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4388
0
                        break;
4389
0
                    }
4390
0
                    case GDT_Int8:
4391
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4392
0
                        break;
4393
0
                    case GDT_UInt16:
4394
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4395
0
                        break;
4396
0
                    case GDT_Int16:
4397
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4398
0
                        break;
4399
0
                    case GDT_UInt32:
4400
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4401
0
                        break;
4402
0
                    case GDT_Int32:
4403
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4404
0
                        break;
4405
0
                    case GDT_UInt64:
4406
0
                        dfValue = static_cast<double>(
4407
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4408
0
                        break;
4409
0
                    case GDT_Int64:
4410
0
                        dfValue = static_cast<double>(
4411
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4412
0
                        break;
4413
0
                    case GDT_Float16:
4414
0
                    {
4415
0
                        using namespace std;
4416
0
                        const GFloat16 hfValue =
4417
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4418
0
                        if (isnan(hfValue) ||
4419
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4420
0
                             ARE_REAL_EQUAL(hfValue,
4421
0
                                            sNoDataValues.hfNoDataValue)))
4422
0
                            continue;
4423
0
                        dfValue = hfValue;
4424
0
                        break;
4425
0
                    }
4426
0
                    case GDT_Float32:
4427
0
                    {
4428
0
                        const float fValue =
4429
0
                            static_cast<float *>(pData)[iOffset];
4430
0
                        if (std::isnan(fValue) ||
4431
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4432
0
                             ARE_REAL_EQUAL(fValue,
4433
0
                                            sNoDataValues.fNoDataValue)))
4434
0
                            continue;
4435
0
                        dfValue = double(fValue);
4436
0
                        break;
4437
0
                    }
4438
0
                    case GDT_Float64:
4439
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4440
0
                        if (std::isnan(dfValue))
4441
0
                            continue;
4442
0
                        break;
4443
0
                    case GDT_CInt16:
4444
0
                    {
4445
0
                        const double dfReal =
4446
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4447
0
                        const double dfImag =
4448
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4449
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4450
0
                            continue;
4451
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4452
0
                    }
4453
0
                    break;
4454
0
                    case GDT_CInt32:
4455
0
                    {
4456
0
                        const double dfReal =
4457
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4458
0
                        const double dfImag =
4459
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4460
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4461
0
                            continue;
4462
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4463
0
                    }
4464
0
                    break;
4465
0
                    case GDT_CFloat16:
4466
0
                    {
4467
0
                        const double dfReal =
4468
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4469
0
                        const double dfImag =
4470
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4471
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4472
0
                            continue;
4473
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4474
0
                        break;
4475
0
                    }
4476
0
                    case GDT_CFloat32:
4477
0
                    {
4478
0
                        const double dfReal =
4479
0
                            double(static_cast<float *>(pData)[iOffset * 2]);
4480
0
                        const double dfImag = double(
4481
0
                            static_cast<float *>(pData)[iOffset * 2 + 1]);
4482
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4483
0
                            continue;
4484
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4485
0
                        break;
4486
0
                    }
4487
0
                    case GDT_CFloat64:
4488
0
                    {
4489
0
                        const double dfReal =
4490
0
                            static_cast<double *>(pData)[iOffset * 2];
4491
0
                        const double dfImag =
4492
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4493
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4494
0
                            continue;
4495
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4496
0
                        break;
4497
0
                    }
4498
0
                    case GDT_Unknown:
4499
0
                    case GDT_TypeCount:
4500
0
                        CPLAssert(false);
4501
0
                }
4502
4503
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4504
0
                    sNoDataValues.bGotNoDataValue &&
4505
0
                    (GDALDataTypeIsInteger(eDataType)
4506
0
                         ? dfValue == sNoDataValues.dfNoDataValue
4507
0
                         : ARE_REAL_EQUAL(dfValue,
4508
0
                                          sNoDataValues.dfNoDataValue)))
4509
0
                    continue;
4510
4511
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4512
                // finite, the result of the multiplication cannot be NaN
4513
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4514
4515
0
                if (dfIndex < 0)
4516
0
                {
4517
0
                    if (bIncludeOutOfRange)
4518
0
                        panHistogram[0]++;
4519
0
                }
4520
0
                else if (dfIndex >= nBuckets)
4521
0
                {
4522
0
                    if (bIncludeOutOfRange)
4523
0
                        ++panHistogram[nBuckets - 1];
4524
0
                }
4525
0
                else
4526
0
                {
4527
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4528
0
                }
4529
0
            }
4530
0
        }
4531
4532
0
        CPLFree(pData);
4533
0
        CPLFree(pabyMaskData);
4534
0
    }
4535
0
    else  // No arbitrary overviews.
4536
0
    {
4537
0
        if (!InitBlockInfo())
4538
0
            return CE_Failure;
4539
4540
        /* --------------------------------------------------------------------
4541
         */
4542
        /*      Figure out the ratio of blocks we will read to get an */
4543
        /*      approximate value. */
4544
        /* --------------------------------------------------------------------
4545
         */
4546
4547
0
        int nSampleRate = 1;
4548
0
        if (bApproxOK)
4549
0
        {
4550
0
            nSampleRate = static_cast<int>(std::max(
4551
0
                1.0,
4552
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4553
            // We want to avoid probing only the first column of blocks for
4554
            // a square shaped raster, because it is not unlikely that it may
4555
            // be padding only (#6378).
4556
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4557
0
                nSampleRate += 1;
4558
0
        }
4559
4560
0
        GByte *pabyMaskData = nullptr;
4561
0
        if (poMaskBand)
4562
0
        {
4563
0
            pabyMaskData = static_cast<GByte *>(
4564
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4565
0
            if (!pabyMaskData)
4566
0
            {
4567
0
                return CE_Failure;
4568
0
            }
4569
0
        }
4570
4571
        /* --------------------------------------------------------------------
4572
         */
4573
        /*      Read the blocks, and add to histogram. */
4574
        /* --------------------------------------------------------------------
4575
         */
4576
0
        for (GIntBig iSampleBlock = 0;
4577
0
             iSampleBlock <
4578
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4579
0
             iSampleBlock += nSampleRate)
4580
0
        {
4581
0
            if (!pfnProgress(
4582
0
                    static_cast<double>(iSampleBlock) /
4583
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4584
0
                    "Compute Histogram", pProgressData))
4585
0
            {
4586
0
                CPLFree(pabyMaskData);
4587
0
                return CE_Failure;
4588
0
            }
4589
4590
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4591
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4592
4593
0
            int nXCheck = 0, nYCheck = 0;
4594
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4595
4596
0
            if (poMaskBand &&
4597
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4598
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4599
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4600
0
                                     0, nBlockXSize, nullptr) != CE_None)
4601
0
            {
4602
0
                CPLFree(pabyMaskData);
4603
0
                return CE_Failure;
4604
0
            }
4605
4606
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4607
0
            if (poBlock == nullptr)
4608
0
            {
4609
0
                CPLFree(pabyMaskData);
4610
0
                return CE_Failure;
4611
0
            }
4612
4613
0
            void *pData = poBlock->GetDataRef();
4614
4615
            // this is a special case for a common situation.
4616
0
            if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4617
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4618
0
                nXCheck == nBlockXSize && nBuckets == 256)
4619
0
            {
4620
0
                const GPtrDiff_t nPixels =
4621
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4622
0
                GByte *pabyData = static_cast<GByte *>(pData);
4623
4624
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4625
0
                {
4626
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4627
0
                        continue;
4628
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4629
0
                          (pabyData[i] ==
4630
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4631
0
                    {
4632
0
                        panHistogram[pabyData[i]]++;
4633
0
                    }
4634
0
                }
4635
4636
0
                poBlock->DropLock();
4637
0
                continue;  // To next sample block.
4638
0
            }
4639
4640
            // This isn't the fastest way to do this, but is easier for now.
4641
0
            for (int iY = 0; iY < nYCheck; iY++)
4642
0
            {
4643
0
                for (int iX = 0; iX < nXCheck; iX++)
4644
0
                {
4645
0
                    const GPtrDiff_t iOffset =
4646
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4647
4648
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4649
0
                        continue;
4650
4651
0
                    double dfValue = 0.0;
4652
4653
0
                    switch (eDataType)
4654
0
                    {
4655
0
                        case GDT_UInt8:
4656
0
                        {
4657
0
                            if (bSignedByte)
4658
0
                                dfValue =
4659
0
                                    static_cast<signed char *>(pData)[iOffset];
4660
0
                            else
4661
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4662
0
                            break;
4663
0
                        }
4664
0
                        case GDT_Int8:
4665
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4666
0
                            break;
4667
0
                        case GDT_UInt16:
4668
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4669
0
                            break;
4670
0
                        case GDT_Int16:
4671
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4672
0
                            break;
4673
0
                        case GDT_UInt32:
4674
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4675
0
                            break;
4676
0
                        case GDT_Int32:
4677
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4678
0
                            break;
4679
0
                        case GDT_UInt64:
4680
0
                            dfValue = static_cast<double>(
4681
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4682
0
                            break;
4683
0
                        case GDT_Int64:
4684
0
                            dfValue = static_cast<double>(
4685
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4686
0
                            break;
4687
0
                        case GDT_Float16:
4688
0
                        {
4689
0
                            using namespace std;
4690
0
                            const GFloat16 hfValue =
4691
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4692
0
                            if (isnan(hfValue) ||
4693
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4694
0
                                 ARE_REAL_EQUAL(hfValue,
4695
0
                                                sNoDataValues.hfNoDataValue)))
4696
0
                                continue;
4697
0
                            dfValue = hfValue;
4698
0
                            break;
4699
0
                        }
4700
0
                        case GDT_Float32:
4701
0
                        {
4702
0
                            const float fValue =
4703
0
                                static_cast<float *>(pData)[iOffset];
4704
0
                            if (std::isnan(fValue) ||
4705
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4706
0
                                 ARE_REAL_EQUAL(fValue,
4707
0
                                                sNoDataValues.fNoDataValue)))
4708
0
                                continue;
4709
0
                            dfValue = double(fValue);
4710
0
                            break;
4711
0
                        }
4712
0
                        case GDT_Float64:
4713
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4714
0
                            if (std::isnan(dfValue))
4715
0
                                continue;
4716
0
                            break;
4717
0
                        case GDT_CInt16:
4718
0
                        {
4719
0
                            double dfReal =
4720
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4721
0
                            double dfImag =
4722
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4723
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4724
0
                            break;
4725
0
                        }
4726
0
                        case GDT_CInt32:
4727
0
                        {
4728
0
                            double dfReal =
4729
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4730
0
                            double dfImag =
4731
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4732
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4733
0
                            break;
4734
0
                        }
4735
0
                        case GDT_CFloat16:
4736
0
                        {
4737
0
                            double dfReal =
4738
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4739
0
                            double dfImag =
4740
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4741
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4742
0
                                continue;
4743
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4744
0
                            break;
4745
0
                        }
4746
0
                        case GDT_CFloat32:
4747
0
                        {
4748
0
                            double dfReal = double(
4749
0
                                static_cast<float *>(pData)[iOffset * 2]);
4750
0
                            double dfImag = double(
4751
0
                                static_cast<float *>(pData)[iOffset * 2 + 1]);
4752
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4753
0
                                continue;
4754
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4755
0
                            break;
4756
0
                        }
4757
0
                        case GDT_CFloat64:
4758
0
                        {
4759
0
                            double dfReal =
4760
0
                                static_cast<double *>(pData)[iOffset * 2];
4761
0
                            double dfImag =
4762
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4763
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4764
0
                                continue;
4765
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4766
0
                            break;
4767
0
                        }
4768
0
                        case GDT_Unknown:
4769
0
                        case GDT_TypeCount:
4770
0
                            CPLAssert(false);
4771
0
                            CPLFree(pabyMaskData);
4772
0
                            return CE_Failure;
4773
0
                    }
4774
4775
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4776
0
                        sNoDataValues.bGotNoDataValue &&
4777
0
                        (GDALDataTypeIsInteger(eDataType)
4778
0
                             ? dfValue == sNoDataValues.dfNoDataValue
4779
0
                             : ARE_REAL_EQUAL(dfValue,
4780
0
                                              sNoDataValues.dfNoDataValue)))
4781
0
                        continue;
4782
4783
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4784
                    // and finite, the result of the multiplication cannot be
4785
                    // NaN
4786
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4787
4788
0
                    if (dfIndex < 0)
4789
0
                    {
4790
0
                        if (bIncludeOutOfRange)
4791
0
                            panHistogram[0]++;
4792
0
                    }
4793
0
                    else if (dfIndex >= nBuckets)
4794
0
                    {
4795
0
                        if (bIncludeOutOfRange)
4796
0
                            ++panHistogram[nBuckets - 1];
4797
0
                    }
4798
0
                    else
4799
0
                    {
4800
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4801
0
                    }
4802
0
                }
4803
0
            }
4804
4805
0
            poBlock->DropLock();
4806
0
        }
4807
4808
0
        CPLFree(pabyMaskData);
4809
0
    }
4810
4811
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4812
4813
0
    return CE_None;
4814
0
}
4815
4816
/************************************************************************/
4817
/*                       GDALGetRasterHistogram()                       */
4818
/************************************************************************/
4819
4820
/**
4821
 * \brief Compute raster histogram.
4822
 *
4823
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4824
 * exceeding 2 billion.
4825
 *
4826
 * @see GDALRasterBand::GetHistogram()
4827
 * @see GDALGetRasterHistogramEx()
4828
 */
4829
4830
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4831
                                          double dfMax, int nBuckets,
4832
                                          int *panHistogram,
4833
                                          int bIncludeOutOfRange, int bApproxOK,
4834
                                          GDALProgressFunc pfnProgress,
4835
                                          void *pProgressData)
4836
4837
0
{
4838
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4839
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4840
4841
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4842
4843
0
    GUIntBig *panHistogramTemp =
4844
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4845
0
    if (panHistogramTemp == nullptr)
4846
0
    {
4847
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4848
0
                            "Out of memory in GDALGetRasterHistogram().");
4849
0
        return CE_Failure;
4850
0
    }
4851
4852
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4853
0
                                       bIncludeOutOfRange, bApproxOK,
4854
0
                                       pfnProgress, pProgressData);
4855
4856
0
    if (eErr == CE_None)
4857
0
    {
4858
0
        for (int i = 0; i < nBuckets; i++)
4859
0
        {
4860
0
            if (panHistogramTemp[i] > INT_MAX)
4861
0
            {
4862
0
                CPLError(CE_Warning, CPLE_AppDefined,
4863
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4864
0
                         " exceeds maximum 32 bit value",
4865
0
                         i, panHistogramTemp[i]);
4866
0
                panHistogram[i] = INT_MAX;
4867
0
            }
4868
0
            else
4869
0
            {
4870
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4871
0
            }
4872
0
        }
4873
0
    }
4874
4875
0
    CPLFree(panHistogramTemp);
4876
4877
0
    return eErr;
4878
0
}
4879
4880
/************************************************************************/
4881
/*                      GDALGetRasterHistogramEx()                      */
4882
/************************************************************************/
4883
4884
/**
4885
 * \brief Compute raster histogram.
4886
 *
4887
 * @see GDALRasterBand::GetHistogram()
4888
 *
4889
 */
4890
4891
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4892
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4893
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4894
    GDALProgressFunc pfnProgress, void *pProgressData)
4895
4896
0
{
4897
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4898
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4899
4900
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4901
4902
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4903
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4904
0
                                pProgressData);
4905
0
}
4906
4907
/************************************************************************/
4908
/*                        GetDefaultHistogram()                         */
4909
/************************************************************************/
4910
4911
/**
4912
 * \brief Fetch default raster histogram.
4913
 *
4914
 * The default method in GDALRasterBand will compute a default histogram. This
4915
 * method is overridden by derived classes (such as GDALPamRasterBand,
4916
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4917
 * stored histogram.
4918
 *
4919
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4920
 * GDALGetDefaultHistogramEx().
4921
 *
4922
 * @param pdfMin pointer to double value that will contain the lower bound of
4923
 * the histogram.
4924
 * @param pdfMax pointer to double value that will contain the upper bound of
4925
 * the histogram.
4926
 * @param pnBuckets pointer to int value that will contain the number of buckets
4927
 * in *ppanHistogram.
4928
 * @param ppanHistogram pointer to array into which the histogram totals are
4929
 * placed. To be freed with VSIFree
4930
 * @param bForce TRUE to force the computation. If FALSE and no default
4931
 * histogram is available, the method will return CE_Warning
4932
 * @param pfnProgress function to report progress to completion.
4933
 * @param pProgressData application data to pass to pfnProgress.
4934
 *
4935
 * @return CE_None on success, CE_Failure if something goes wrong, or
4936
 * CE_Warning if no default histogram is available.
4937
 */
4938
4939
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4940
                                           int *pnBuckets,
4941
                                           GUIntBig **ppanHistogram, int bForce,
4942
                                           GDALProgressFunc pfnProgress,
4943
                                           void *pProgressData)
4944
4945
0
{
4946
0
    CPLAssert(nullptr != pnBuckets);
4947
0
    CPLAssert(nullptr != ppanHistogram);
4948
0
    CPLAssert(nullptr != pdfMin);
4949
0
    CPLAssert(nullptr != pdfMax);
4950
4951
0
    *pnBuckets = 0;
4952
0
    *ppanHistogram = nullptr;
4953
4954
0
    if (!bForce)
4955
0
        return CE_Warning;
4956
4957
0
    int nBuckets = 256;
4958
4959
0
    bool bSignedByte = false;
4960
0
    if (eDataType == GDT_UInt8)
4961
0
    {
4962
0
        EnablePixelTypeSignedByteWarning(false);
4963
0
        const char *pszPixelType =
4964
0
            GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
4965
0
        EnablePixelTypeSignedByteWarning(true);
4966
0
        bSignedByte =
4967
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4968
0
    }
4969
4970
0
    if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4971
0
    {
4972
0
        *pdfMin = -0.5;
4973
0
        *pdfMax = 255.5;
4974
0
    }
4975
0
    else if (GetRasterDataType() == GDT_Int8)
4976
0
    {
4977
0
        *pdfMin = -128 - 0.5;
4978
0
        *pdfMax = 127 + 0.5;
4979
0
    }
4980
0
    else
4981
0
    {
4982
4983
0
        const CPLErr eErr =
4984
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4985
0
        if (eErr != CE_None)
4986
0
            return eErr;
4987
0
        if (*pdfMin == *pdfMax)
4988
0
        {
4989
0
            nBuckets = 1;
4990
0
            *pdfMin -= 0.5;
4991
0
            *pdfMax += 0.5;
4992
0
        }
4993
0
        else
4994
0
        {
4995
0
            const double dfHalfBucket =
4996
0
                (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4997
0
            *pdfMin -= dfHalfBucket;
4998
0
            *pdfMax += dfHalfBucket;
4999
0
        }
5000
0
    }
5001
5002
0
    *ppanHistogram =
5003
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
5004
0
    if (*ppanHistogram == nullptr)
5005
0
    {
5006
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
5007
0
                    "Out of memory in GetDefaultHistogram().");
5008
0
        return CE_Failure;
5009
0
    }
5010
5011
0
    *pnBuckets = nBuckets;
5012
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
5013
0
                               TRUE, FALSE, pfnProgress, pProgressData);
5014
0
    if (eErr != CE_None)
5015
0
    {
5016
0
        *pnBuckets = 0;
5017
0
    }
5018
0
    return eErr;
5019
0
}
5020
5021
/************************************************************************/
5022
/*                      GDALGetDefaultHistogram()                       */
5023
/************************************************************************/
5024
5025
/**
5026
 * \brief Fetch default raster histogram.
5027
 *
5028
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5029
 * exceeding 2 billion.
5030
 *
5031
 * @see GDALRasterBand::GDALGetDefaultHistogram()
5032
 * @see GDALGetRasterHistogramEx()
5033
 */
5034
5035
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5036
                                           double *pdfMin, double *pdfMax,
5037
                                           int *pnBuckets, int **ppanHistogram,
5038
                                           int bForce,
5039
                                           GDALProgressFunc pfnProgress,
5040
                                           void *pProgressData)
5041
5042
0
{
5043
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5044
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5045
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5046
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5047
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5048
5049
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5050
0
    GUIntBig *panHistogramTemp = nullptr;
5051
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5052
0
                                              &panHistogramTemp, bForce,
5053
0
                                              pfnProgress, pProgressData);
5054
0
    if (eErr == CE_None)
5055
0
    {
5056
0
        const int nBuckets = *pnBuckets;
5057
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5058
0
        if (*ppanHistogram == nullptr)
5059
0
        {
5060
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5061
0
                                "Out of memory in GDALGetDefaultHistogram().");
5062
0
            VSIFree(panHistogramTemp);
5063
0
            return CE_Failure;
5064
0
        }
5065
5066
0
        for (int i = 0; i < nBuckets; ++i)
5067
0
        {
5068
0
            if (panHistogramTemp[i] > INT_MAX)
5069
0
            {
5070
0
                CPLError(CE_Warning, CPLE_AppDefined,
5071
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
5072
0
                         " exceeds maximum 32 bit value",
5073
0
                         i, panHistogramTemp[i]);
5074
0
                (*ppanHistogram)[i] = INT_MAX;
5075
0
            }
5076
0
            else
5077
0
            {
5078
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5079
0
            }
5080
0
        }
5081
5082
0
        CPLFree(panHistogramTemp);
5083
0
    }
5084
0
    else
5085
0
    {
5086
0
        *ppanHistogram = nullptr;
5087
0
    }
5088
5089
0
    return eErr;
5090
0
}
5091
5092
/************************************************************************/
5093
/*                     GDALGetDefaultHistogramEx()                      */
5094
/************************************************************************/
5095
5096
/**
5097
 * \brief Fetch default raster histogram.
5098
 *
5099
 * @see GDALRasterBand::GetDefaultHistogram()
5100
 *
5101
 */
5102
5103
CPLErr CPL_STDCALL
5104
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5105
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5106
                          GDALProgressFunc pfnProgress, void *pProgressData)
5107
5108
0
{
5109
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5110
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5111
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5112
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5113
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5114
5115
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5116
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5117
0
                                       bForce, pfnProgress, pProgressData);
5118
0
}
5119
5120
/************************************************************************/
5121
/*                             AdviseRead()                             */
5122
/************************************************************************/
5123
5124
/**
5125
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5126
 * \brief Advise driver of upcoming read requests.
5127
 *
5128
 * Some GDAL drivers operate more efficiently if they know in advance what
5129
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5130
 * an application to notify the driver of the region of interest,
5131
 * and at what resolution the region will be read.
5132
 *
5133
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5134
 * accelerate access via some drivers.
5135
 *
5136
 * Depending on call paths, drivers might receive several calls to
5137
 * AdviseRead() with the same parameters.
5138
 *
5139
 * @param nXOff The pixel offset to the top left corner of the region
5140
 * of the band to be accessed.  This would be zero to start from the left side.
5141
 *
5142
 * @param nYOff The line offset to the top left corner of the region
5143
 * of the band to be accessed.  This would be zero to start from the top.
5144
 *
5145
 * @param nXSize The width of the region of the band to be accessed in pixels.
5146
 *
5147
 * @param nYSize The height of the region of the band to be accessed in lines.
5148
 *
5149
 * @param nBufXSize the width of the buffer image into which the desired region
5150
 * is to be read, or from which it is to be written.
5151
 *
5152
 * @param nBufYSize the height of the buffer image into which the desired
5153
 * region is to be read, or from which it is to be written.
5154
 *
5155
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5156
 * pixel values will automatically be translated to/from the GDALRasterBand
5157
 * data type as needed.
5158
 *
5159
 * @param papszOptions a list of name=value strings with special control
5160
 * options.  Normally this is NULL.
5161
 *
5162
 * @return CE_Failure if the request is invalid and CE_None if it works or
5163
 * is ignored.
5164
 */
5165
5166
/**/
5167
/**/
5168
5169
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5170
                                  int /*nYSize*/, int /*nBufXSize*/,
5171
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5172
                                  CSLConstList /*papszOptions*/)
5173
0
{
5174
0
    return CE_None;
5175
0
}
5176
5177
/************************************************************************/
5178
/*                        GDALRasterAdviseRead()                        */
5179
/************************************************************************/
5180
5181
/**
5182
 * \brief Advise driver of upcoming read requests.
5183
 *
5184
 * @see GDALRasterBand::AdviseRead()
5185
 */
5186
5187
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5188
                                        int nYOff, int nXSize, int nYSize,
5189
                                        int nBufXSize, int nBufYSize,
5190
                                        GDALDataType eDT,
5191
                                        CSLConstList papszOptions)
5192
5193
0
{
5194
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5195
5196
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5197
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5198
0
                              nBufYSize, eDT,
5199
0
                              const_cast<char **>(papszOptions));
5200
0
}
5201
5202
/************************************************************************/
5203
/*                           GetStatistics()                            */
5204
/************************************************************************/
5205
5206
/**
5207
 * \brief Fetch image statistics.
5208
 *
5209
 * Returns the minimum, maximum, mean and standard deviation of all
5210
 * pixel values in this band.  If approximate statistics are sufficient,
5211
 * the bApproxOK flag can be set to true in which case overviews, or a
5212
 * subset of image tiles may be used in computing the statistics.
5213
 *
5214
 * If bForce is FALSE results will only be returned if it can be done
5215
 * quickly (i.e. without scanning the image, typically by using pre-existing
5216
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5217
 * returned efficiently, the method will return CE_Warning but no warning will
5218
 * be issued. This is a non-standard use of the CE_Warning return value
5219
 * to indicate "nothing done".
5220
 *
5221
 * If bForce is TRUE, and results are quickly available without scanning the
5222
 * image, they will be used. If bForce is TRUE and results are not quickly
5223
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5224
 * which will scan the image.
5225
 *
5226
 * To always force recomputation of statistics, use ComputeStatistics() instead
5227
 * of this method.
5228
 *
5229
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5230
 * will generally cache statistics in the .pam file allowing fast fetch
5231
 * after the first request.
5232
 *
5233
 * This method is the same as the C function GDALGetRasterStatistics().
5234
 *
5235
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5236
 * or a subset of all tiles.
5237
 *
5238
 * @param bForce If FALSE statistics will only be returned if it can
5239
 * be done without rescanning the image. If TRUE, statistics computation will
5240
 * be forced if pre-existing values are not quickly available.
5241
 *
5242
 * @param pdfMin Location into which to load image minimum (may be NULL).
5243
 *
5244
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5245
 *
5246
 * @param pdfMean Location into which to load image mean (may be NULL).
5247
 *
5248
 * @param pdfStdDev Location into which to load image standard deviation
5249
 * (may be NULL).
5250
 *
5251
 * @return CE_None on success, CE_Warning if no values returned,
5252
 * CE_Failure if an error occurs.
5253
 */
5254
5255
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5256
                                     double *pdfMax, double *pdfMean,
5257
                                     double *pdfStdDev)
5258
5259
0
{
5260
    /* -------------------------------------------------------------------- */
5261
    /*      Do we already have metadata items for the requested values?     */
5262
    /* -------------------------------------------------------------------- */
5263
0
    if ((pdfMin == nullptr ||
5264
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5265
0
        (pdfMax == nullptr ||
5266
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5267
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5268
0
        (pdfStdDev == nullptr ||
5269
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5270
0
    {
5271
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5272
0
        {
5273
0
            if (pdfMin != nullptr)
5274
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5275
0
            if (pdfMax != nullptr)
5276
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5277
0
            if (pdfMean != nullptr)
5278
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5279
0
            if (pdfStdDev != nullptr)
5280
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5281
5282
0
            return CE_None;
5283
0
        }
5284
0
    }
5285
5286
    /* -------------------------------------------------------------------- */
5287
    /*      Does the driver already know the min/max?                       */
5288
    /* -------------------------------------------------------------------- */
5289
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5290
0
    {
5291
0
        int bSuccessMin = FALSE;
5292
0
        int bSuccessMax = FALSE;
5293
5294
0
        const double dfMin = GetMinimum(&bSuccessMin);
5295
0
        const double dfMax = GetMaximum(&bSuccessMax);
5296
5297
0
        if (bSuccessMin && bSuccessMax)
5298
0
        {
5299
0
            if (pdfMin != nullptr)
5300
0
                *pdfMin = dfMin;
5301
0
            if (pdfMax != nullptr)
5302
0
                *pdfMax = dfMax;
5303
0
            return CE_None;
5304
0
        }
5305
0
    }
5306
5307
    /* -------------------------------------------------------------------- */
5308
    /*      Either return without results, or force computation.            */
5309
    /* -------------------------------------------------------------------- */
5310
0
    if (!bForce)
5311
0
        return CE_Warning;
5312
0
    else
5313
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5314
0
                                 GDALDummyProgress, nullptr, nullptr);
5315
0
}
5316
5317
/************************************************************************/
5318
/*                      GDALGetRasterStatistics()                       */
5319
/************************************************************************/
5320
5321
/**
5322
 * \brief Fetch image statistics.
5323
 *
5324
 * @see GDALRasterBand::GetStatistics()
5325
 */
5326
5327
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5328
                                           int bForce, double *pdfMin,
5329
                                           double *pdfMax, double *pdfMean,
5330
                                           double *pdfStdDev)
5331
5332
0
{
5333
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5334
5335
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5336
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5337
0
                                 pdfStdDev);
5338
0
}
5339
5340
/************************************************************************/
5341
/*                             GDALUInt128                              */
5342
/************************************************************************/
5343
5344
#ifdef HAVE_UINT128_T
5345
class GDALUInt128
5346
{
5347
    __uint128_t val;
5348
5349
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5350
0
    {
5351
0
    }
5352
5353
  public:
5354
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5355
0
    {
5356
        // Evaluates to just a single mul on x86_64
5357
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5358
0
    }
5359
5360
    GDALUInt128 operator-(const GDALUInt128 &other) const
5361
0
    {
5362
0
        return GDALUInt128(val - other.val);
5363
0
    }
5364
5365
    operator double() const
5366
0
    {
5367
0
        return static_cast<double>(val);
5368
0
    }
5369
};
5370
#else
5371
5372
#if defined(_MSC_VER) && defined(_M_X64)
5373
#include <intrin.h>
5374
#endif
5375
5376
class GDALUInt128
5377
{
5378
    GUIntBig low, high;
5379
5380
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5381
    {
5382
    }
5383
5384
  public:
5385
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5386
    {
5387
#if defined(_MSC_VER) && defined(_M_X64)
5388
        GUIntBig highRes;
5389
        GUIntBig lowRes = _umul128(first, second, &highRes);
5390
        return GDALUInt128(lowRes, highRes);
5391
#else
5392
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5393
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5394
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5395
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5396
        GUIntBig highRes = 0;
5397
        const GUIntBig firstLowSecondHigh =
5398
            static_cast<GUIntBig>(firstLow) * secondHigh;
5399
        const GUIntBig firstHighSecondLow =
5400
            static_cast<GUIntBig>(firstHigh) * secondLow;
5401
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5402
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5403
            highRes += static_cast<GUIntBig>(1) << 32;
5404
        const GUIntBig firstLowSecondLow =
5405
            static_cast<GUIntBig>(firstLow) * secondLow;
5406
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5407
        if (lowRes < firstLowSecondLow)  // check for overflow
5408
            highRes++;
5409
        highRes +=
5410
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5411
        return GDALUInt128(lowRes, highRes);
5412
#endif
5413
    }
5414
5415
    GDALUInt128 operator-(const GDALUInt128 &other) const
5416
    {
5417
        GUIntBig highRes = high - other.high;
5418
        GUIntBig lowRes = low - other.low;
5419
        if (lowRes > low)  // check for underflow
5420
            --highRes;
5421
        return GDALUInt128(lowRes, highRes);
5422
    }
5423
5424
    operator double() const
5425
    {
5426
        const double twoPow64 = 18446744073709551616.0;
5427
        return high * twoPow64 + low;
5428
    }
5429
};
5430
#endif
5431
5432
/************************************************************************/
5433
/*                     ComputeStatisticsInternal()                      */
5434
/************************************************************************/
5435
5436
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5437
// not needed.
5438
0
#define static_cast_for_coverity_scan static_cast
5439
5440
// The rationale for below optimizations is detailed in statistics.txt
5441
5442
// Use with T = GByte or GUInt16 only !
5443
template <class T, bool COMPUTE_OTHER_STATS>
5444
struct ComputeStatisticsInternalGeneric
5445
{
5446
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5447
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5448
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5449
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5450
0
    {
5451
0
        static_assert(std::is_same<T, GByte>::value ||
5452
0
                          std::is_same<T, GUInt16>::value,
5453
0
                      "bad type for T");
5454
0
        if (bHasNoData)
5455
0
        {
5456
            // General case
5457
0
            for (int iY = 0; iY < nYCheck; iY++)
5458
0
            {
5459
0
                for (int iX = 0; iX < nXCheck; iX++)
5460
0
                {
5461
0
                    const GPtrDiff_t iOffset =
5462
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5463
0
                    const GUInt32 nValue = pData[iOffset];
5464
0
                    if (nValue == nNoDataValue)
5465
0
                        continue;
5466
0
                    if (nValue < nMin)
5467
0
                        nMin = nValue;
5468
0
                    if (nValue > nMax)
5469
0
                        nMax = nValue;
5470
                    if constexpr (COMPUTE_OTHER_STATS)
5471
0
                    {
5472
0
                        nValidCount++;
5473
0
                        nSum += nValue;
5474
0
                        nSumSquare +=
5475
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5476
0
                            nValue;
5477
0
                    }
5478
0
                }
5479
0
            }
5480
            if constexpr (COMPUTE_OTHER_STATS)
5481
0
            {
5482
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5483
0
            }
5484
0
        }
5485
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5486
0
                 nMax == std::numeric_limits<T>::max())
5487
0
        {
5488
            if constexpr (COMPUTE_OTHER_STATS)
5489
0
            {
5490
                // Optimization when there is no nodata and we know we have already
5491
                // reached the min and max
5492
0
                for (int iY = 0; iY < nYCheck; iY++)
5493
0
                {
5494
0
                    int iX;
5495
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5496
0
                    {
5497
0
                        const GPtrDiff_t iOffset =
5498
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5499
0
                        const GUIntBig nValue = pData[iOffset];
5500
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5501
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5502
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5503
0
                        nSum += nValue;
5504
0
                        nSumSquare += nValue * nValue;
5505
0
                        nSum += nValue2;
5506
0
                        nSumSquare += nValue2 * nValue2;
5507
0
                        nSum += nValue3;
5508
0
                        nSumSquare += nValue3 * nValue3;
5509
0
                        nSum += nValue4;
5510
0
                        nSumSquare += nValue4 * nValue4;
5511
0
                    }
5512
0
                    for (; iX < nXCheck; ++iX)
5513
0
                    {
5514
0
                        const GPtrDiff_t iOffset =
5515
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5516
0
                        const GUIntBig nValue = pData[iOffset];
5517
0
                        nSum += nValue;
5518
0
                        nSumSquare += nValue * nValue;
5519
0
                    }
5520
0
                }
5521
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5522
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5523
0
            }
5524
0
        }
5525
0
        else
5526
0
        {
5527
0
            for (int iY = 0; iY < nYCheck; iY++)
5528
0
            {
5529
0
                int iX;
5530
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5531
0
                {
5532
0
                    const GPtrDiff_t iOffset =
5533
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5534
0
                    const GUInt32 nValue = pData[iOffset];
5535
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5536
0
                    if (nValue < nValue2)
5537
0
                    {
5538
0
                        if (nValue < nMin)
5539
0
                            nMin = nValue;
5540
0
                        if (nValue2 > nMax)
5541
0
                            nMax = nValue2;
5542
0
                    }
5543
0
                    else
5544
0
                    {
5545
0
                        if (nValue2 < nMin)
5546
0
                            nMin = nValue2;
5547
0
                        if (nValue > nMax)
5548
0
                            nMax = nValue;
5549
0
                    }
5550
                    if constexpr (COMPUTE_OTHER_STATS)
5551
0
                    {
5552
0
                        nSum += nValue;
5553
0
                        nSumSquare +=
5554
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5555
0
                            nValue;
5556
0
                        nSum += nValue2;
5557
0
                        nSumSquare +=
5558
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5559
0
                            nValue2;
5560
0
                    }
5561
0
                }
5562
0
                if (iX < nXCheck)
5563
0
                {
5564
0
                    const GPtrDiff_t iOffset =
5565
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5566
0
                    const GUInt32 nValue = pData[iOffset];
5567
0
                    if (nValue < nMin)
5568
0
                        nMin = nValue;
5569
0
                    if (nValue > nMax)
5570
0
                        nMax = nValue;
5571
0
                    if (COMPUTE_OTHER_STATS)
5572
0
                    {
5573
0
                        nSum += nValue;
5574
0
                        nSumSquare +=
5575
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5576
0
                            nValue;
5577
0
                    }
5578
0
                }
5579
0
            }
5580
            if constexpr (COMPUTE_OTHER_STATS)
5581
0
            {
5582
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5583
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5584
0
            }
5585
0
        }
5586
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&)
5587
};
5588
5589
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5590
// using 64bit accumulators in internal loops. This also slightly helps in
5591
// 64bit mode.
5592
template <bool COMPUTE_OTHER_STATS>
5593
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5594
{
5595
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5596
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5597
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5598
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5599
0
    {
5600
0
        int nOuterLoops = nXCheck / 65536;
5601
0
        if (nXCheck % 65536)
5602
0
            nOuterLoops++;
5603
5604
0
        if (bHasNoData)
5605
0
        {
5606
            // General case
5607
0
            for (int iY = 0; iY < nYCheck; iY++)
5608
0
            {
5609
0
                int iX = 0;
5610
0
                for (int k = 0; k < nOuterLoops; k++)
5611
0
                {
5612
0
                    int iMax = iX + 65536;
5613
0
                    if (iMax > nXCheck)
5614
0
                        iMax = nXCheck;
5615
0
                    GUInt32 nSum32bit = 0;
5616
0
                    GUInt32 nSumSquare32bit = 0;
5617
0
                    GUInt32 nValidCount32bit = 0;
5618
0
                    GUInt32 nSampleCount32bit = 0;
5619
0
                    for (; iX < iMax; iX++)
5620
0
                    {
5621
0
                        const GPtrDiff_t iOffset =
5622
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5623
0
                        const GUInt32 nValue = pData[iOffset];
5624
5625
0
                        nSampleCount32bit++;
5626
0
                        if (nValue == nNoDataValue)
5627
0
                            continue;
5628
0
                        if (nValue < nMin)
5629
0
                            nMin = nValue;
5630
0
                        if (nValue > nMax)
5631
0
                            nMax = nValue;
5632
                        if constexpr (COMPUTE_OTHER_STATS)
5633
0
                        {
5634
0
                            nValidCount32bit++;
5635
0
                            nSum32bit += nValue;
5636
0
                            nSumSquare32bit += nValue * nValue;
5637
0
                        }
5638
0
                    }
5639
                    if constexpr (COMPUTE_OTHER_STATS)
5640
0
                    {
5641
0
                        nSampleCount += nSampleCount32bit;
5642
0
                        nValidCount += nValidCount32bit;
5643
0
                        nSum += nSum32bit;
5644
0
                        nSumSquare += nSumSquare32bit;
5645
0
                    }
5646
0
                }
5647
0
            }
5648
0
        }
5649
0
        else if (nMin == 0 && nMax == 255)
5650
0
        {
5651
            if constexpr (COMPUTE_OTHER_STATS)
5652
0
            {
5653
                // Optimization when there is no nodata and we know we have already
5654
                // reached the min and max
5655
0
                for (int iY = 0; iY < nYCheck; iY++)
5656
0
                {
5657
0
                    int iX = 0;
5658
0
                    for (int k = 0; k < nOuterLoops; k++)
5659
0
                    {
5660
0
                        int iMax = iX + 65536;
5661
0
                        if (iMax > nXCheck)
5662
0
                            iMax = nXCheck;
5663
0
                        GUInt32 nSum32bit = 0;
5664
0
                        GUInt32 nSumSquare32bit = 0;
5665
0
                        for (; iX + 3 < iMax; iX += 4)
5666
0
                        {
5667
0
                            const GPtrDiff_t iOffset =
5668
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5669
0
                            const GUInt32 nValue = pData[iOffset];
5670
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5671
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5672
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5673
0
                            nSum32bit += nValue;
5674
0
                            nSumSquare32bit += nValue * nValue;
5675
0
                            nSum32bit += nValue2;
5676
0
                            nSumSquare32bit += nValue2 * nValue2;
5677
0
                            nSum32bit += nValue3;
5678
0
                            nSumSquare32bit += nValue3 * nValue3;
5679
0
                            nSum32bit += nValue4;
5680
0
                            nSumSquare32bit += nValue4 * nValue4;
5681
0
                        }
5682
0
                        nSum += nSum32bit;
5683
0
                        nSumSquare += nSumSquare32bit;
5684
0
                    }
5685
0
                    for (; iX < nXCheck; ++iX)
5686
0
                    {
5687
0
                        const GPtrDiff_t iOffset =
5688
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5689
0
                        const GUIntBig nValue = pData[iOffset];
5690
0
                        nSum += nValue;
5691
0
                        nSumSquare += nValue * nValue;
5692
0
                    }
5693
0
                }
5694
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5695
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5696
0
            }
5697
0
        }
5698
0
        else
5699
0
        {
5700
0
            for (int iY = 0; iY < nYCheck; iY++)
5701
0
            {
5702
0
                int iX = 0;
5703
0
                for (int k = 0; k < nOuterLoops; k++)
5704
0
                {
5705
0
                    int iMax = iX + 65536;
5706
0
                    if (iMax > nXCheck)
5707
0
                        iMax = nXCheck;
5708
0
                    GUInt32 nSum32bit = 0;
5709
0
                    GUInt32 nSumSquare32bit = 0;
5710
0
                    for (; iX + 1 < iMax; iX += 2)
5711
0
                    {
5712
0
                        const GPtrDiff_t iOffset =
5713
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5714
0
                        const GUInt32 nValue = pData[iOffset];
5715
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5716
0
                        if (nValue < nValue2)
5717
0
                        {
5718
0
                            if (nValue < nMin)
5719
0
                                nMin = nValue;
5720
0
                            if (nValue2 > nMax)
5721
0
                                nMax = nValue2;
5722
0
                        }
5723
0
                        else
5724
0
                        {
5725
0
                            if (nValue2 < nMin)
5726
0
                                nMin = nValue2;
5727
0
                            if (nValue > nMax)
5728
0
                                nMax = nValue;
5729
0
                        }
5730
                        if constexpr (COMPUTE_OTHER_STATS)
5731
0
                        {
5732
0
                            nSum32bit += nValue;
5733
0
                            nSumSquare32bit += nValue * nValue;
5734
0
                            nSum32bit += nValue2;
5735
0
                            nSumSquare32bit += nValue2 * nValue2;
5736
0
                        }
5737
0
                    }
5738
                    if constexpr (COMPUTE_OTHER_STATS)
5739
0
                    {
5740
0
                        nSum += nSum32bit;
5741
0
                        nSumSquare += nSumSquare32bit;
5742
0
                    }
5743
0
                }
5744
0
                if (iX < nXCheck)
5745
0
                {
5746
0
                    const GPtrDiff_t iOffset =
5747
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5748
0
                    const GUInt32 nValue = pData[iOffset];
5749
0
                    if (nValue < nMin)
5750
0
                        nMin = nValue;
5751
0
                    if (nValue > nMax)
5752
0
                        nMax = nValue;
5753
                    if constexpr (COMPUTE_OTHER_STATS)
5754
0
                    {
5755
0
                        nSum += nValue;
5756
0
                        nSumSquare +=
5757
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5758
0
                            nValue;
5759
0
                    }
5760
0
                }
5761
0
            }
5762
            if constexpr (COMPUTE_OTHER_STATS)
5763
0
            {
5764
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5765
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5766
0
            }
5767
0
        }
5768
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&)
5769
};
5770
5771
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5772
{
5773
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5774
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5775
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5776
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5777
    {
5778
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5779
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5780
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5781
    }
5782
};
5783
5784
constexpr int ALIGNMENT_AVX2_OPTIM = 32;
5785
5786
#if (defined(__x86_64__) || defined(_M_X64) ||                                 \
5787
     defined(USE_NEON_OPTIMIZATIONS)) &&                                       \
5788
    (defined(__GNUC__) || defined(_MSC_VER))
5789
5790
#include "gdal_avx2_emulation.hpp"
5791
5792
0
#define ZERO256 GDALmm256_setzero_si256()
5793
5794
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5795
static void
5796
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5797
                              // assumed to be aligned on 256 bits
5798
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5799
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5800
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5801
0
{
5802
    // 32-byte alignment may not be enforced by linker, so do it at hand
5803
0
    GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
5804
0
                             ALIGNMENT_AVX2_OPTIM +
5805
0
                             (COMPUTE_OTHER_STATS
5806
0
                                  ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
5807
0
                                  : 0)];
5808
0
    GByte *paby32ByteAligned =
5809
0
        aby32ByteUnaligned +
5810
0
        (ALIGNMENT_AVX2_OPTIM -
5811
0
         (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
5812
0
          ALIGNMENT_AVX2_OPTIM));
5813
0
    GByte *pabyMin = paby32ByteAligned;
5814
0
    GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
5815
0
    GUInt32 *panSum = COMPUTE_OTHER_STATS
5816
0
                          ? reinterpret_cast<GUInt32 *>(
5817
0
                                paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
5818
0
                          : nullptr;
5819
0
    GUInt32 *panSumSquare =
5820
0
        COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
5821
0
                                  paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
5822
0
                            : nullptr;
5823
5824
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
5825
5826
0
    GPtrDiff_t i = 0;
5827
    // Make sure that sumSquare can fit on uint32
5828
    // * 8 since we can hold 8 sums per vector register
5829
0
    const int nMaxIterationsPerInnerLoop =
5830
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5831
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5832
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5833
0
        nOuterLoops++;
5834
5835
0
    GDALm256i ymm_min =
5836
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5837
0
    GDALm256i ymm_max = ymm_min;
5838
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5839
5840
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5841
0
    {
5842
0
        const auto iMax =
5843
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5844
5845
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5846
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5847
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5848
0
            ZERO256;  // holds 8 uint32 sums
5849
0
        for (; i + 31 < iMax; i += 32)
5850
0
        {
5851
0
            const GDALm256i ymm = GDALmm256_load_si256(
5852
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5853
0
            if (COMPUTE_MIN)
5854
0
            {
5855
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5856
0
            }
5857
0
            if (COMPUTE_MAX)
5858
0
            {
5859
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5860
0
            }
5861
5862
            if constexpr (COMPUTE_OTHER_STATS)
5863
0
            {
5864
                // Extract even-8bit values
5865
0
                const GDALm256i ymm_even =
5866
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5867
                // Compute square of those 16 values as 32 bit result
5868
                // and add adjacent pairs
5869
0
                const GDALm256i ymm_even_square =
5870
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5871
                // Add to the sumsquare accumulator
5872
0
                ymm_sumsquare =
5873
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5874
5875
                // Extract odd-8bit values
5876
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5877
0
                const GDALm256i ymm_odd_square =
5878
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5879
0
                ymm_sumsquare =
5880
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5881
5882
                // Now compute the sums
5883
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5884
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5885
0
            }
5886
0
        }
5887
5888
        if constexpr (COMPUTE_OTHER_STATS)
5889
0
        {
5890
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5891
0
                                  ymm_sum);
5892
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5893
0
                                  ymm_sumsquare);
5894
5895
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5896
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5897
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5898
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5899
0
                          panSumSquare[7];
5900
0
        }
5901
0
    }
5902
5903
    if constexpr (COMPUTE_MIN)
5904
0
    {
5905
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5906
0
    }
5907
    if constexpr (COMPUTE_MAX)
5908
0
    {
5909
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5910
0
    }
5911
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5912
0
    {
5913
0
        for (int j = 0; j < 32; j++)
5914
0
        {
5915
            if constexpr (COMPUTE_MIN)
5916
0
            {
5917
0
                if (pabyMin[j] < nMin)
5918
0
                    nMin = pabyMin[j];
5919
0
            }
5920
            if constexpr (COMPUTE_MAX)
5921
0
            {
5922
0
                if (pabyMax[j] > nMax)
5923
0
                    nMax = pabyMax[j];
5924
0
            }
5925
0
        }
5926
0
    }
5927
5928
0
    for (; i < nBlockPixels; i++)
5929
0
    {
5930
0
        const GUInt32 nValue = pData[i];
5931
        if constexpr (COMPUTE_MIN)
5932
0
        {
5933
0
            if (nValue < nMin)
5934
0
                nMin = nValue;
5935
0
        }
5936
        if constexpr (COMPUTE_MAX)
5937
0
        {
5938
0
            if (nValue > nMax)
5939
0
                nMax = nValue;
5940
0
        }
5941
        if constexpr (COMPUTE_OTHER_STATS)
5942
0
        {
5943
0
            nSum += nValue;
5944
0
            nSumSquare +=
5945
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5946
0
        }
5947
0
    }
5948
5949
    if constexpr (COMPUTE_OTHER_STATS)
5950
0
    {
5951
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5952
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5953
0
    }
5954
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&)
5955
5956
// SSE2/AVX2 optimization for GByte case
5957
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5958
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5959
// there are strictly equivalent to 2 parallel SSE2 streams.
5960
template <bool COMPUTE_OTHER_STATS>
5961
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5962
{
5963
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5964
                  // assumed to be aligned on 256 bits
5965
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5966
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5967
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5968
                  GUIntBig &nValidCount)
5969
0
    {
5970
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5971
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5972
0
            nMin <= nMax)
5973
0
        {
5974
            // 32-byte alignment may not be enforced by linker, so do it at hand
5975
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5976
0
            GByte *paby32ByteAligned =
5977
0
                aby32ByteUnaligned +
5978
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5979
0
            GByte *pabyMin = paby32ByteAligned;
5980
0
            GByte *pabyMax = paby32ByteAligned + 32;
5981
0
            GUInt32 *panSum =
5982
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5983
0
            GUInt32 *panSumSquare =
5984
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5985
5986
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5987
5988
0
            GPtrDiff_t i = 0;
5989
            // Make sure that sumSquare can fit on uint32
5990
            // * 8 since we can hold 8 sums per vector register
5991
0
            const int nMaxIterationsPerInnerLoop =
5992
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5993
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5994
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5995
0
                nOuterLoops++;
5996
5997
0
            const GDALm256i ymm_nodata =
5998
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5999
            // any non noData value in [min,max] would do.
6000
0
            const GDALm256i ymm_neutral =
6001
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
6002
0
            GDALm256i ymm_min = ymm_neutral;
6003
0
            GDALm256i ymm_max = ymm_neutral;
6004
0
            [[maybe_unused]] const auto ymm_mask_8bits =
6005
0
                GDALmm256_set1_epi16(0xFF);
6006
6007
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
6008
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
6009
0
            const bool bComputeMinMax =
6010
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
6011
6012
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
6013
0
            {
6014
0
                const auto iMax =
6015
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6016
6017
                // holds 4 uint32 sums in [0], [2], [4] and [6]
6018
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
6019
                // holds 8 uint32 sums
6020
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
6021
                // holds 4 uint32 sums in [0], [2], [4] and [6]
6022
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
6023
0
                const auto iInit = i;
6024
0
                for (; i + 31 < iMax; i += 32)
6025
0
                {
6026
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6027
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6028
6029
                    // Check which values are nodata
6030
0
                    const GDALm256i ymm_eq_nodata =
6031
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6032
                    if constexpr (COMPUTE_OTHER_STATS)
6033
0
                    {
6034
                        // Count how many values are nodata (due to cmpeq
6035
                        // putting 255 when condition is met, this will actually
6036
                        // be 255 times the number of nodata value, spread in 4
6037
                        // 64 bits words). We can use add_epi32 as the counter
6038
                        // will not overflow uint32
6039
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6040
0
                            ymm_count_nodata_mul_255,
6041
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6042
0
                    }
6043
                    // Replace all nodata values by zero for the purpose of sum
6044
                    // and sumquare.
6045
0
                    const GDALm256i ymm_nodata_by_zero =
6046
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6047
0
                    if (bComputeMinMax)
6048
0
                    {
6049
                        // Replace all nodata values by a neutral value for the
6050
                        // purpose of min and max.
6051
0
                        const GDALm256i ymm_nodata_by_neutral =
6052
0
                            GDALmm256_or_si256(
6053
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6054
0
                                ymm_nodata_by_zero);
6055
6056
0
                        ymm_min =
6057
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6058
0
                        ymm_max =
6059
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6060
0
                    }
6061
6062
                    if constexpr (COMPUTE_OTHER_STATS)
6063
0
                    {
6064
                        // Extract even-8bit values
6065
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
6066
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
6067
                        // Compute square of those 16 values as 32 bit result
6068
                        // and add adjacent pairs
6069
0
                        const GDALm256i ymm_even_square =
6070
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
6071
                        // Add to the sumsquare accumulator
6072
0
                        ymm_sumsquare =
6073
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6074
6075
                        // Extract odd-8bit values
6076
0
                        const GDALm256i ymm_odd =
6077
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6078
0
                        const GDALm256i ymm_odd_square =
6079
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6080
0
                        ymm_sumsquare =
6081
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6082
6083
                        // Now compute the sums
6084
0
                        ymm_sum = GDALmm256_add_epi32(
6085
0
                            ymm_sum,
6086
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6087
0
                    }
6088
0
                }
6089
6090
                if constexpr (COMPUTE_OTHER_STATS)
6091
0
                {
6092
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
6093
0
                    GDALmm256_store_si256(
6094
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6095
0
                        ymm_count_nodata_mul_255);
6096
6097
0
                    nSampleCount += (i - iInit);
6098
6099
0
                    nValidCount +=
6100
0
                        (i - iInit) -
6101
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6102
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6103
0
                            255;
6104
6105
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6106
0
                                          ymm_sum);
6107
0
                    GDALmm256_store_si256(
6108
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
6109
0
                        ymm_sumsquare);
6110
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6111
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6112
0
                                  panSumSquare[1] + panSumSquare[2] +
6113
0
                                  panSumSquare[3] + panSumSquare[4] +
6114
0
                                  panSumSquare[5] + panSumSquare[6] +
6115
0
                                  panSumSquare[7];
6116
0
                }
6117
0
            }
6118
6119
0
            if (bComputeMinMax)
6120
0
            {
6121
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6122
0
                                      ymm_min);
6123
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6124
0
                                      ymm_max);
6125
0
                for (int j = 0; j < 32; j++)
6126
0
                {
6127
0
                    if (pabyMin[j] < nMin)
6128
0
                        nMin = pabyMin[j];
6129
0
                    if (pabyMax[j] > nMax)
6130
0
                        nMax = pabyMax[j];
6131
0
                }
6132
0
            }
6133
6134
            if constexpr (COMPUTE_OTHER_STATS)
6135
0
            {
6136
0
                nSampleCount += nBlockPixels - i;
6137
0
            }
6138
0
            for (; i < nBlockPixels; i++)
6139
0
            {
6140
0
                const GUInt32 nValue = pData[i];
6141
0
                if (nValue == nNoDataValue)
6142
0
                    continue;
6143
0
                if (nValue < nMin)
6144
0
                    nMin = nValue;
6145
0
                if (nValue > nMax)
6146
0
                    nMax = nValue;
6147
                if constexpr (COMPUTE_OTHER_STATS)
6148
0
                {
6149
0
                    nValidCount++;
6150
0
                    nSum += nValue;
6151
0
                    nSumSquare +=
6152
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6153
0
                        nValue;
6154
0
                }
6155
0
            }
6156
0
        }
6157
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6158
0
        {
6159
0
            if (nMin > 0)
6160
0
            {
6161
0
                if (nMax < 255)
6162
0
                {
6163
0
                    ComputeStatisticsByteNoNodata<true, true,
6164
0
                                                  COMPUTE_OTHER_STATS>(
6165
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6166
0
                        nSampleCount, nValidCount);
6167
0
                }
6168
0
                else
6169
0
                {
6170
0
                    ComputeStatisticsByteNoNodata<true, false,
6171
0
                                                  COMPUTE_OTHER_STATS>(
6172
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6173
0
                        nSampleCount, nValidCount);
6174
0
                }
6175
0
            }
6176
0
            else
6177
0
            {
6178
0
                if (nMax < 255)
6179
0
                {
6180
0
                    ComputeStatisticsByteNoNodata<false, true,
6181
0
                                                  COMPUTE_OTHER_STATS>(
6182
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6183
0
                        nSampleCount, nValidCount);
6184
0
                }
6185
0
                else
6186
0
                {
6187
0
                    ComputeStatisticsByteNoNodata<false, false,
6188
0
                                                  COMPUTE_OTHER_STATS>(
6189
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6190
0
                        nSampleCount, nValidCount);
6191
0
                }
6192
0
            }
6193
0
        }
6194
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6195
0
                 (nBlockXSize % 32) == 0)
6196
0
        {
6197
0
            for (int iY = 0; iY < nYCheck; iY++)
6198
0
            {
6199
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6200
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6201
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6202
0
            }
6203
0
        }
6204
0
        else
6205
0
        {
6206
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6207
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6208
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6209
0
        }
6210
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&)
6211
};
6212
6213
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6214
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6215
                             GUIntBig i)
6216
0
{
6217
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6218
0
}
6219
6220
// AVX2/SSE2 optimization for GUInt16 case
6221
template <bool COMPUTE_OTHER_STATS>
6222
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6223
{
6224
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6225
                  // assumed to be aligned on 128 bits
6226
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6227
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6228
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6229
                  GUIntBig &nValidCount)
6230
0
    {
6231
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6232
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6233
0
        {
6234
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6235
6236
0
            GPtrDiff_t i = 0;
6237
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6238
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6239
            // Furthermore the shift is also needed to use madd_epi16
6240
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6241
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6242
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6243
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6244
0
            GDALm256i ymm_max = ymm_min;
6245
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6246
0
                ZERO256;  // holds 4 uint64 sums
6247
6248
            // Make sure that sum can fit on uint32
6249
            // * 8 since we can hold 8 sums per vector register
6250
0
            const int nMaxIterationsPerInnerLoop =
6251
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6252
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6253
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6254
0
                nOuterLoops++;
6255
6256
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6257
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6258
0
                GDALmm256_set1_epi32(0xFFFF);
6259
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6260
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6261
6262
0
            GUIntBig nSumThis = 0;
6263
0
            for (int k = 0; k < nOuterLoops; k++)
6264
0
            {
6265
0
                const auto iMax =
6266
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6267
6268
0
                [[maybe_unused]] GDALm256i ymm_sum =
6269
0
                    ZERO256;  // holds 8 uint32 sums
6270
0
                for (; i + 15 < iMax; i += 16)
6271
0
                {
6272
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6273
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6274
0
                    const GDALm256i ymm_shifted =
6275
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6276
0
                    if (bComputeMinMax)
6277
0
                    {
6278
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6279
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6280
0
                    }
6281
6282
                    if constexpr (COMPUTE_OTHER_STATS)
6283
0
                    {
6284
                        // Note: the int32 range can overflow for (0-32768)^2 +
6285
                        // (0-32768)^2 = 0x80000000, but as we know the result
6286
                        // is positive, this is OK as we interpret is a uint32.
6287
0
                        const GDALm256i ymm_square =
6288
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6289
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6290
0
                            ymm_sumsquare,
6291
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6292
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6293
0
                            ymm_sumsquare,
6294
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6295
6296
                        // Now compute the sums
6297
0
                        ymm_sum = GDALmm256_add_epi32(
6298
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6299
0
                        ymm_sum = GDALmm256_add_epi32(
6300
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6301
0
                    }
6302
0
                }
6303
6304
                if constexpr (COMPUTE_OTHER_STATS)
6305
0
                {
6306
0
                    GUInt32 anSum[8];
6307
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6308
0
                                           ymm_sum);
6309
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6310
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6311
0
                                anSum[6] + anSum[7];
6312
0
                }
6313
0
            }
6314
6315
0
            if (bComputeMinMax)
6316
0
            {
6317
0
                GUInt16 anMin[16];
6318
0
                GUInt16 anMax[16];
6319
6320
                // Unshift the result
6321
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6322
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6323
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6324
0
                                       ymm_min);
6325
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6326
0
                                       ymm_max);
6327
0
                for (int j = 0; j < 16; j++)
6328
0
                {
6329
0
                    if (anMin[j] < nMin)
6330
0
                        nMin = anMin[j];
6331
0
                    if (anMax[j] > nMax)
6332
0
                        nMax = anMax[j];
6333
0
                }
6334
0
            }
6335
6336
            if constexpr (COMPUTE_OTHER_STATS)
6337
0
            {
6338
0
                GUIntBig anSumSquare[4];
6339
0
                GDALmm256_storeu_si256(
6340
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6341
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6342
0
                              anSumSquare[3];
6343
6344
                // Unshift the sum of squares
6345
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6346
0
                                 static_cast<GUIntBig>(i));
6347
6348
0
                nSum += nSumThis;
6349
6350
0
                for (; i < nBlockPixels; i++)
6351
0
                {
6352
0
                    const GUInt32 nValue = pData[i];
6353
0
                    if (nValue < nMin)
6354
0
                        nMin = nValue;
6355
0
                    if (nValue > nMax)
6356
0
                        nMax = nValue;
6357
0
                    nSum += nValue;
6358
0
                    nSumSquare +=
6359
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6360
0
                        nValue;
6361
0
                }
6362
6363
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6364
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6365
0
            }
6366
0
        }
6367
0
        else
6368
0
        {
6369
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6370
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6371
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6372
0
        }
6373
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&)
6374
};
6375
6376
#endif
6377
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6378
// defined(_MSC_VER))
6379
6380
/************************************************************************/
6381
/*                           GetPixelValue()                            */
6382
/************************************************************************/
6383
6384
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6385
                                   const void *pData, GPtrDiff_t iOffset,
6386
                                   const GDALNoDataValues &sNoDataValues,
6387
                                   bool &bValid)
6388
0
{
6389
0
    bValid = true;
6390
0
    double dfValue = 0;
6391
0
    switch (eDataType)
6392
0
    {
6393
0
        case GDT_UInt8:
6394
0
        {
6395
0
            if (bSignedByte)
6396
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6397
0
            else
6398
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6399
0
            break;
6400
0
        }
6401
0
        case GDT_Int8:
6402
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6403
0
            break;
6404
0
        case GDT_UInt16:
6405
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6406
0
            break;
6407
0
        case GDT_Int16:
6408
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6409
0
            break;
6410
0
        case GDT_UInt32:
6411
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6412
0
            break;
6413
0
        case GDT_Int32:
6414
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6415
0
            break;
6416
0
        case GDT_UInt64:
6417
0
            dfValue = static_cast<double>(
6418
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6419
0
            break;
6420
0
        case GDT_Int64:
6421
0
            dfValue = static_cast<double>(
6422
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6423
0
            break;
6424
0
        case GDT_Float16:
6425
0
        {
6426
0
            using namespace std;
6427
0
            const GFloat16 hfValue =
6428
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6429
0
            if (isnan(hfValue) ||
6430
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6431
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6432
0
            {
6433
0
                bValid = false;
6434
0
                return 0.0;
6435
0
            }
6436
0
            dfValue = hfValue;
6437
0
            return dfValue;
6438
0
        }
6439
0
        case GDT_Float32:
6440
0
        {
6441
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6442
0
            if (std::isnan(fValue) ||
6443
0
                (sNoDataValues.bGotFloatNoDataValue &&
6444
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6445
0
            {
6446
0
                bValid = false;
6447
0
                return 0.0;
6448
0
            }
6449
0
            dfValue = double(fValue);
6450
0
            return dfValue;
6451
0
        }
6452
0
        case GDT_Float64:
6453
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6454
0
            if (std::isnan(dfValue))
6455
0
            {
6456
0
                bValid = false;
6457
0
                return 0.0;
6458
0
            }
6459
0
            break;
6460
0
        case GDT_CInt16:
6461
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6462
0
            break;
6463
0
        case GDT_CInt32:
6464
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6465
0
            break;
6466
0
        case GDT_CFloat16:
6467
0
            dfValue = static_cast<const GFloat16 *>(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_CFloat32:
6475
0
            dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6476
0
            if (std::isnan(dfValue))
6477
0
            {
6478
0
                bValid = false;
6479
0
                return 0.0;
6480
0
            }
6481
0
            break;
6482
0
        case GDT_CFloat64:
6483
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6484
0
            if (std::isnan(dfValue))
6485
0
            {
6486
0
                bValid = false;
6487
0
                return 0.0;
6488
0
            }
6489
0
            break;
6490
0
        case GDT_Unknown:
6491
0
        case GDT_TypeCount:
6492
0
            CPLAssert(false);
6493
0
            break;
6494
0
    }
6495
6496
0
    if (sNoDataValues.bGotNoDataValue &&
6497
0
        (GDALDataTypeIsInteger(eDataType)
6498
0
             ? dfValue == sNoDataValues.dfNoDataValue
6499
0
             : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue)))
6500
0
    {
6501
0
        bValid = false;
6502
0
        return 0.0;
6503
0
    }
6504
0
    return dfValue;
6505
0
}
6506
6507
/************************************************************************/
6508
/*                          SetValidPercent()                           */
6509
/************************************************************************/
6510
6511
//! @cond Doxygen_Suppress
6512
/**
6513
 * \brief Set percentage of valid (not nodata) pixels.
6514
 *
6515
 * Stores the percentage of valid pixels in the metadata item
6516
 * STATISTICS_VALID_PERCENT
6517
 *
6518
 * @param nSampleCount Number of sampled pixels.
6519
 *
6520
 * @param nValidCount Number of valid pixels.
6521
 */
6522
6523
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6524
                                     GUIntBig nValidCount)
6525
0
{
6526
0
    if (nValidCount == 0)
6527
0
    {
6528
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6529
0
    }
6530
0
    else if (nValidCount == nSampleCount)
6531
0
    {
6532
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6533
0
    }
6534
0
    else /* nValidCount < nSampleCount */
6535
0
    {
6536
0
        char szValue[128] = {0};
6537
6538
        /* percentage is only an indicator: limit precision */
6539
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6540
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6541
6542
0
        if (EQUAL(szValue, "100"))
6543
0
        {
6544
            /* don't set 100 percent valid
6545
             * because some of the sampled pixels were nodata */
6546
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6547
0
        }
6548
0
        else
6549
0
        {
6550
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6551
0
        }
6552
0
    }
6553
0
}
6554
6555
//! @endcond
6556
6557
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6558
6559
#ifdef __AVX2__
6560
6561
#define set1_ps _mm256_set1_ps
6562
#define loadu_ps _mm256_loadu_ps
6563
#define or_ps _mm256_or_ps
6564
#define min_ps _mm256_min_ps
6565
#define max_ps _mm256_max_ps
6566
#define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6567
#define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6568
#define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6569
#define movemask_ps _mm256_movemask_ps
6570
#define storeu_ps _mm256_storeu_ps
6571
#define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6572
#define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6573
6574
#define unpacklo_ps _mm256_unpacklo_ps
6575
#define castps_pd _mm256_castps_pd
6576
6577
inline __m256 dup_hi_ps(__m256 x)
6578
{
6579
    const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6580
    return _mm256_permutevar8x32_ps(x, idx);
6581
}
6582
6583
#define setzero_pd _mm256_setzero_pd
6584
#define set1_pd _mm256_set1_pd
6585
#define loadu_pd _mm256_loadu_pd
6586
#define or_pd _mm256_or_pd
6587
#define min_pd _mm256_min_pd
6588
#define max_pd _mm256_max_pd
6589
#define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6590
#define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6591
#define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6592
#define movemask_pd _mm256_movemask_pd
6593
#define add_pd _mm256_add_pd
6594
#define sub_pd _mm256_sub_pd
6595
#define mul_pd _mm256_mul_pd
6596
#define div_pd _mm256_div_pd
6597
#define storeu_pd _mm256_storeu_pd
6598
#define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6599
#define blendv_pd _mm256_blendv_pd
6600
#ifdef __FMA__
6601
#define fmadd_pd _mm256_fmadd_pd
6602
#else
6603
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6604
#endif
6605
6606
#else
6607
6608
0
#define set1_ps _mm_set1_ps
6609
0
#define loadu_ps _mm_loadu_ps
6610
0
#define or_ps _mm_or_ps
6611
0
#define min_ps _mm_min_ps
6612
0
#define max_ps _mm_max_ps
6613
0
#define cmpeq_ps _mm_cmpeq_ps
6614
0
#define cmpneq_ps _mm_cmpneq_ps
6615
0
#define cmpunord_ps _mm_cmpunord_ps
6616
0
#define movemask_ps _mm_movemask_ps
6617
0
#define storeu_ps _mm_storeu_ps
6618
0
#define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6619
0
#define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6620
0
#define unpacklo_ps _mm_unpacklo_ps
6621
0
#define castps_pd _mm_castps_pd
6622
0
#define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6623
6624
0
#define setzero_pd _mm_setzero_pd
6625
0
#define set1_pd _mm_set1_pd
6626
0
#define loadu_pd _mm_loadu_pd
6627
0
#define or_pd _mm_or_pd
6628
0
#define min_pd _mm_min_pd
6629
0
#define max_pd _mm_max_pd
6630
0
#define cmpeq_pd _mm_cmpeq_pd
6631
0
#define cmpneq_pd _mm_cmpneq_pd
6632
0
#define cmpunord_pd _mm_cmpunord_pd
6633
0
#define movemask_pd _mm_movemask_pd
6634
0
#define add_pd _mm_add_pd
6635
0
#define sub_pd _mm_sub_pd
6636
0
#define mul_pd _mm_mul_pd
6637
0
#define div_pd _mm_div_pd
6638
0
#define storeu_pd _mm_storeu_pd
6639
0
#define cvtsd_f64 _mm_cvtsd_f64
6640
#ifdef __FMA__
6641
#define fmadd_pd _mm_fmadd_pd
6642
#else
6643
0
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6644
#endif
6645
6646
inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6647
0
{
6648
#if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6649
    return _mm_blendv_pd(a, b, mask);
6650
#else
6651
0
    return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6652
0
#endif
6653
0
}
6654
#endif
6655
6656
0
#define dup_lo_ps(x) unpacklo_ps((x), (x))
6657
6658
/************************************************************************/
6659
/*                   ComputeStatisticsFloat32_SSE2()                    */
6660
/************************************************************************/
6661
6662
template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6663
#if defined(__GNUC__)
6664
__attribute__((noinline))
6665
#endif
6666
static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
6667
                                         [[maybe_unused]] float fNoDataValue,
6668
                                         int iX, int nCount, float &fMin,
6669
                                         float &fMax, double &dfBlockMean,
6670
                                         double &dfBlockM2,
6671
                                         double &dfBlockValidCount)
6672
0
{
6673
0
    auto vValidCount = setzero_pd();
6674
0
    const auto vOne = set1_pd(1);
6675
0
    [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6676
6677
0
    auto vMin = set1_ps(fMin);
6678
0
    auto vMax = set1_ps(fMax);
6679
6680
0
    auto vMean_lo = setzero_pd();
6681
0
    auto vM2_lo = setzero_pd();
6682
6683
0
    auto vMean_hi = setzero_pd();
6684
0
    auto vM2_hi = setzero_pd();
6685
6686
0
    constexpr int VALS_PER_LOOP =
6687
0
        static_cast<int>(sizeof(vOne) / sizeof(float));
6688
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6689
0
    {
6690
0
        const auto vValues = loadu_ps(pafData + iX);
6691
6692
        if constexpr (HAS_NAN)
6693
0
        {
6694
0
            auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6695
            if constexpr (HAS_NODATA)
6696
0
            {
6697
0
                isNaNOrNoData =
6698
0
                    or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6699
0
            }
6700
0
            if (movemask_ps(isNaNOrNoData))
6701
0
            {
6702
0
                break;
6703
0
            }
6704
        }
6705
        else if constexpr (HAS_NODATA)
6706
0
        {
6707
0
            if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6708
0
            {
6709
0
                break;
6710
0
            }
6711
0
        }
6712
6713
0
        vMin = min_ps(vMin, vValues);
6714
0
        vMax = max_ps(vMax, vValues);
6715
6716
0
        const auto vValues_lo = cvtps_lo_pd(vValues);
6717
0
        const auto vValues_hi = cvtps_hi_pd(vValues);
6718
0
        [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6719
6720
0
        vValidCount = add_pd(vValidCount, vOne);
6721
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6722
6723
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6724
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6725
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6726
0
        {
6727
0
            const auto vMinNotSameAsMax_lo =
6728
0
                castps_pd(dup_lo_ps(vMinNotSameAsMax));
6729
0
            vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6730
0
            const auto vNewM2_lo =
6731
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6732
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6733
        }
6734
        else
6735
0
        {
6736
0
            vMean_lo = vNewMean_lo;
6737
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6738
0
        }
6739
6740
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6741
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6742
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6743
0
        {
6744
0
            const auto vMinNotSameAsMax_hi =
6745
0
                castps_pd(dup_hi_ps(vMinNotSameAsMax));
6746
0
            vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6747
0
            const auto vNewM2_hi =
6748
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6749
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6750
        }
6751
        else
6752
0
        {
6753
0
            vMean_hi = vNewMean_hi;
6754
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6755
0
        }
6756
0
    }
6757
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6758
0
    if (dfValidVectorCount > 0)
6759
0
    {
6760
0
        float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6761
0
        storeu_ps(afMin, vMin);
6762
0
        storeu_ps(afMax, vMax);
6763
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6764
0
        {
6765
0
            fMin = std::min(fMin, afMin[i]);
6766
0
            fMax = std::max(fMax, afMax[i]);
6767
0
        }
6768
6769
0
        double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6770
0
        storeu_pd(adfMean, vMean_lo);
6771
0
        storeu_pd(adfM2, vM2_lo);
6772
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6773
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6774
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6775
0
        {
6776
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6777
0
            dfBlockM2 += adfM2[i];
6778
0
            if (adfMean[i] != dfBlockMean)
6779
0
            {
6780
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6781
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6782
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6783
0
                             dfValidVectorCount / dfNewValidCount;
6784
0
            }
6785
0
            dfBlockValidCount = dfNewValidCount;
6786
0
        }
6787
0
    }
6788
6789
0
    return iX;
6790
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&)
6791
6792
/************************************************************************/
6793
/*                   ComputeStatisticsFloat64_SSE2()                    */
6794
/************************************************************************/
6795
6796
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6797
#if defined(__GNUC__)
6798
__attribute__((noinline))
6799
#endif
6800
static int ComputeStatisticsFloat64_SSE2(const double *padfData,
6801
                                         [[maybe_unused]] double dfNoDataValue,
6802
                                         int iX, int nCount, double &dfMin,
6803
                                         double &dfMax, double &dfBlockMean,
6804
                                         double &dfBlockM2,
6805
                                         double &dfBlockValidCount)
6806
0
{
6807
0
    auto vValidCount = setzero_pd();
6808
0
    const auto vOne = set1_pd(1);
6809
0
    [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6810
6811
0
    auto vMin_lo = set1_pd(dfMin);
6812
0
    auto vMax_lo = set1_pd(dfMax);
6813
0
    auto vMean_lo = setzero_pd();
6814
0
    auto vM2_lo = setzero_pd();
6815
6816
0
    auto vMin_hi = vMin_lo;
6817
0
    auto vMax_hi = vMax_lo;
6818
0
    auto vMean_hi = setzero_pd();
6819
0
    auto vM2_hi = setzero_pd();
6820
6821
0
    constexpr int VALS_PER_LOOP =
6822
0
        2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6823
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6824
0
    {
6825
0
        const auto vValues_lo = loadu_pd(padfData + iX);
6826
0
        const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6827
        // Check if there's at least one NaN in both vectors
6828
0
        auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6829
        if constexpr (HAS_NODATA)
6830
0
        {
6831
0
            isNaNOrNoData =
6832
0
                or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6833
0
                                           cmpeq_pd(vValues_hi, vNoData)));
6834
0
        }
6835
0
        if (movemask_pd(isNaNOrNoData))
6836
0
        {
6837
0
            break;
6838
0
        }
6839
6840
0
        vValidCount = add_pd(vValidCount, vOne);
6841
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6842
6843
0
        vMin_lo = min_pd(vMin_lo, vValues_lo);
6844
0
        vMax_lo = max_pd(vMax_lo, vValues_lo);
6845
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6846
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6847
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6848
0
        {
6849
0
            const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6850
0
            vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6851
0
            const auto vNewM2_lo =
6852
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6853
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6854
        }
6855
        else
6856
0
        {
6857
0
            vMean_lo = vNewMean_lo;
6858
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6859
0
        }
6860
6861
0
        vMin_hi = min_pd(vMin_hi, vValues_hi);
6862
0
        vMax_hi = max_pd(vMax_hi, vValues_hi);
6863
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6864
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6865
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6866
0
        {
6867
0
            const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6868
0
            vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6869
0
            const auto vNewM2_hi =
6870
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6871
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6872
        }
6873
        else
6874
0
        {
6875
0
            vMean_hi = vNewMean_hi;
6876
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6877
0
        }
6878
0
    }
6879
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6880
0
    if (dfValidVectorCount > 0)
6881
0
    {
6882
0
        double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6883
0
            adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6884
0
        storeu_pd(adfMin, vMin_lo);
6885
0
        storeu_pd(adfMax, vMax_lo);
6886
0
        storeu_pd(adfMean, vMean_lo);
6887
0
        storeu_pd(adfM2, vM2_lo);
6888
0
        storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6889
0
        storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6890
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6891
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6892
6893
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6894
0
        {
6895
0
            dfMin = std::min(dfMin, adfMin[i]);
6896
0
            dfMax = std::max(dfMax, adfMax[i]);
6897
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6898
0
            dfBlockM2 += adfM2[i];
6899
0
            if (adfMean[i] != dfBlockMean)
6900
0
            {
6901
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6902
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6903
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6904
0
                             dfValidVectorCount / dfNewValidCount;
6905
0
            }
6906
0
            dfBlockValidCount = dfNewValidCount;
6907
0
        }
6908
0
    }
6909
6910
0
    return iX;
6911
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&)
6912
6913
#endif
6914
6915
/************************************************************************/
6916
/*                   ComputeBlockStatisticsFloat32()                    */
6917
/************************************************************************/
6918
6919
template <bool HAS_NAN, bool HAS_NODATA>
6920
static void ComputeBlockStatisticsFloat32(
6921
    const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6922
    const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6923
    float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6924
    double &dfBlockValidCountInOut)
6925
0
{
6926
0
    float fMin = fMinInOut;
6927
0
    float fMax = fMaxInOut;
6928
0
    double dfBlockMean = dfBlockMeanInOut;
6929
0
    double dfBlockM2 = dfBlockM2InOut;
6930
0
    double dfBlockValidCount = dfBlockValidCountInOut;
6931
6932
0
    for (int iY = 0; iY < nYCheck; iY++)
6933
0
    {
6934
0
        const int iOffset = iY * nBlockXSize;
6935
0
        if (dfBlockValidCount > 0 && fMin != fMax)
6936
0
        {
6937
0
            int iX = 0;
6938
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6939
0
            iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6940
0
                                               /* bCheckMinEqMax = */ false,
6941
0
                                               HAS_NODATA>(
6942
0
                pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6943
0
                fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6944
0
#endif
6945
0
            for (; iX < nXCheck; iX++)
6946
0
            {
6947
0
                const float fValue = pafSrcData[iOffset + iX];
6948
                if constexpr (HAS_NAN)
6949
0
                {
6950
0
                    if (std::isnan(fValue))
6951
0
                        continue;
6952
0
                }
6953
                if constexpr (HAS_NODATA)
6954
0
                {
6955
0
                    if (fValue == sNoDataValues.fNoDataValue)
6956
0
                        continue;
6957
0
                }
6958
0
                fMin = std::min(fMin, fValue);
6959
0
                fMax = std::max(fMax, fValue);
6960
0
                dfBlockValidCount += 1.0;
6961
0
                const double dfValue = static_cast<double>(fValue);
6962
0
                const double dfDelta = dfValue - dfBlockMean;
6963
0
                dfBlockMean += dfDelta / dfBlockValidCount;
6964
0
                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6965
0
            }
6966
0
        }
6967
0
        else
6968
0
        {
6969
0
            int iX = 0;
6970
0
            if (dfBlockValidCount == 0)
6971
0
            {
6972
0
                while (iX < nXCheck)
6973
0
                {
6974
0
                    const float fValue = pafSrcData[iOffset + iX];
6975
0
                    ++iX;
6976
                    if constexpr (HAS_NAN)
6977
0
                    {
6978
0
                        if (std::isnan(fValue))
6979
0
                            continue;
6980
0
                    }
6981
                    if constexpr (HAS_NODATA)
6982
0
                    {
6983
0
                        if (fValue == sNoDataValues.fNoDataValue)
6984
0
                            continue;
6985
0
                    }
6986
0
                    fMin = std::min(fMin, fValue);
6987
0
                    fMax = std::max(fMax, fValue);
6988
0
                    dfBlockValidCount = 1;
6989
0
                    dfBlockMean = static_cast<double>(fValue);
6990
0
                    break;
6991
0
                }
6992
0
            }
6993
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6994
0
            iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6995
0
                                               /* bCheckMinEqMax = */ true,
6996
0
                                               HAS_NODATA>(
6997
0
                pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6998
0
                fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6999
0
#endif
7000
0
            for (; iX < nXCheck; iX++)
7001
0
            {
7002
0
                const float fValue = pafSrcData[iOffset + iX];
7003
                if constexpr (HAS_NAN)
7004
0
                {
7005
0
                    if (std::isnan(fValue))
7006
0
                        continue;
7007
0
                }
7008
                if constexpr (HAS_NODATA)
7009
0
                {
7010
0
                    if (fValue == sNoDataValues.fNoDataValue)
7011
0
                        continue;
7012
0
                }
7013
0
                fMin = std::min(fMin, fValue);
7014
0
                fMax = std::max(fMax, fValue);
7015
0
                dfBlockValidCount += 1.0;
7016
0
                if (fMin != fMax)
7017
0
                {
7018
0
                    const double dfValue = static_cast<double>(fValue);
7019
0
                    const double dfDelta = dfValue - dfBlockMean;
7020
0
                    dfBlockMean += dfDelta / dfBlockValidCount;
7021
0
                    dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7022
0
                }
7023
0
            }
7024
0
        }
7025
0
    }
7026
7027
0
    fMinInOut = fMin;
7028
0
    fMaxInOut = fMax;
7029
0
    dfBlockMeanInOut = dfBlockMean;
7030
0
    dfBlockM2InOut = dfBlockM2;
7031
0
    dfBlockValidCountInOut = dfBlockValidCount;
7032
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&)
7033
7034
/************************************************************************/
7035
/*                        StatisticsTaskFloat32                         */
7036
/************************************************************************/
7037
7038
namespace
7039
{
7040
struct StatisticsTaskFloat32
7041
{
7042
    double dfBlockMean = 0;
7043
    double dfBlockM2 = 0;
7044
    double dfBlockValidCount = 0;
7045
    GDALDataType eDataType = GDT_Unknown;
7046
    bool bHasNoData = false;
7047
    GDALNoDataValues *psNoDataValues = nullptr;
7048
    const float *pafSrcData = nullptr;
7049
    float fMin = std::numeric_limits<float>::infinity();
7050
    float fMax = -std::numeric_limits<float>::infinity();
7051
    int nChunkXSize = 0;
7052
    int nXCheck = 0;
7053
    int nYCheck = 0;
7054
7055
    void Perform()
7056
0
    {
7057
0
        if (GDALDataTypeIsInteger(eDataType))
7058
0
        {
7059
0
            if (bHasNoData)
7060
0
            {
7061
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7062
0
                                              /* HAS_NODATA = */ true>(
7063
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7064
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7065
0
            }
7066
0
            else
7067
0
            {
7068
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7069
0
                                              /* HAS_NODATA = */ false>(
7070
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7071
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7072
0
            }
7073
0
        }
7074
0
        else
7075
0
        {
7076
0
            if (bHasNoData)
7077
0
            {
7078
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7079
0
                                              /* HAS_NODATA = */ true>(
7080
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7081
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7082
0
            }
7083
0
            else
7084
0
            {
7085
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7086
0
                                              /* HAS_NODATA = */ false>(
7087
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7088
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7089
0
            }
7090
0
        }
7091
0
    }
7092
};
7093
}  // namespace
7094
7095
/************************************************************************/
7096
/*                         ComputeStatistics()                          */
7097
/************************************************************************/
7098
7099
/**
7100
 * \brief Compute image statistics.
7101
 *
7102
 * Returns the minimum, maximum, mean and standard deviation of all
7103
 * pixel values in this band.  If approximate statistics are sufficient,
7104
 * the bApproxOK flag can be set to true in which case overviews, or a
7105
 * subset of image tiles may be used in computing the statistics.
7106
 *
7107
 * Once computed, the statistics will generally be "set" back on the
7108
 * raster band using SetStatistics().
7109
 *
7110
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7111
 *
7112
 * This method is the same as the C functions GDALComputeRasterStatistics()
7113
 * and GDALComputeRasterStatisticsEx().
7114
 *
7115
 * @param bApproxOK If TRUE statistics may be computed based on overviews
7116
 * or a subset of all tiles.
7117
 *
7118
 * @param pdfMin Location into which to load image minimum (may be NULL).
7119
 *
7120
 * @param pdfMax Location into which to load image maximum (may be NULL).-
7121
 *
7122
 * @param pdfMean Location into which to load image mean (may be NULL).
7123
 *
7124
 * @param pdfStdDev Location into which to load image standard deviation
7125
 * (may be NULL).
7126
 *
7127
 * @param pfnProgress a function to call to report progress, or NULL.
7128
 *
7129
 * @param pProgressData application data to pass to the progress function.
7130
 *
7131
 * @param papszOptions (added in 3.14) NULL, or NULL terminated list of options.
7132
 *                     Currently supported option is SET_STATISTICS=FALSE to
7133
 *                     avoid setting statistics in metadata items.
7134
 *
7135
 * @return CE_None on success, or CE_Failure if an error occurs or processing
7136
 * is terminated by the user.
7137
 */
7138
7139
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7140
                                         double *pdfMax, double *pdfMean,
7141
                                         double *pdfStdDev,
7142
                                         GDALProgressFunc pfnProgress,
7143
                                         void *pProgressData,
7144
                                         CSLConstList papszOptions)
7145
7146
0
{
7147
0
    if (pfnProgress == nullptr)
7148
0
        pfnProgress = GDALDummyProgress;
7149
7150
0
    const bool bSetStatistics =
7151
0
        CPLFetchBool(papszOptions, "SET_STATISTICS", true);
7152
7153
    /* -------------------------------------------------------------------- */
7154
    /*      If we have overview bands, use them for statistics.             */
7155
    /* -------------------------------------------------------------------- */
7156
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7157
0
    {
7158
0
        GDALRasterBand *poBand =
7159
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7160
7161
0
        if (poBand != this)
7162
0
        {
7163
0
            CPLErr eErr = poBand->ComputeStatistics(
7164
0
                FALSE, pdfMin, pdfMax, pdfMean, pdfStdDev, pfnProgress,
7165
0
                pProgressData, papszOptions);
7166
0
            if (eErr == CE_None && bSetStatistics)
7167
0
            {
7168
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7169
0
                {
7170
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7171
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7172
0
                }
7173
7174
                /* transfer metadata from overview band to this */
7175
0
                const char *pszPercentValid =
7176
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7177
7178
0
                if (pszPercentValid != nullptr)
7179
0
                {
7180
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
7181
0
                                    pszPercentValid);
7182
0
                }
7183
0
            }
7184
0
            return eErr;
7185
0
        }
7186
0
    }
7187
7188
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7189
0
    {
7190
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7191
0
        return CE_Failure;
7192
0
    }
7193
7194
    /* -------------------------------------------------------------------- */
7195
    /*      Read actual data and compute statistics.                        */
7196
    /* -------------------------------------------------------------------- */
7197
    // Using Welford algorithm:
7198
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7199
    // to compute standard deviation in a more numerically robust way than
7200
    // the difference of the sum of square values with the square of the sum.
7201
    // dfMean and dfM2 are updated at each sample.
7202
    // dfM2 is the sum of square of differences to the current mean.
7203
0
    double dfMin = std::numeric_limits<double>::infinity();
7204
0
    double dfMax = -std::numeric_limits<double>::infinity();
7205
0
    double dfMean = 0.0;
7206
0
    double dfM2 = 0.0;
7207
7208
0
    GDALRasterIOExtraArg sExtraArg;
7209
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7210
7211
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7212
0
    GDALRasterBand *poMaskBand = nullptr;
7213
0
    if (!sNoDataValues.bGotNoDataValue)
7214
0
    {
7215
0
        const int l_nMaskFlags = GetMaskFlags();
7216
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
7217
0
            GetColorInterpretation() != GCI_AlphaBand)
7218
0
        {
7219
0
            poMaskBand = GetMaskBand();
7220
0
        }
7221
0
    }
7222
7223
0
    bool bSignedByte = false;
7224
0
    if (eDataType == GDT_UInt8)
7225
0
    {
7226
0
        EnablePixelTypeSignedByteWarning(false);
7227
0
        const char *pszPixelType =
7228
0
            GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
7229
0
        EnablePixelTypeSignedByteWarning(true);
7230
0
        bSignedByte =
7231
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7232
0
    }
7233
7234
0
    GUIntBig nSampleCount = 0;
7235
0
    GUIntBig nValidCount = 0;
7236
7237
0
    if (bApproxOK && HasArbitraryOverviews())
7238
0
    {
7239
        /* --------------------------------------------------------------------
7240
         */
7241
        /*      Figure out how much the image should be reduced to get an */
7242
        /*      approximate value. */
7243
        /* --------------------------------------------------------------------
7244
         */
7245
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7246
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7247
7248
0
        int nXReduced = nRasterXSize;
7249
0
        int nYReduced = nRasterYSize;
7250
0
        if (dfReduction > 1.0)
7251
0
        {
7252
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7253
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7254
7255
            // Catch the case of huge resizing ratios here
7256
0
            if (nXReduced == 0)
7257
0
                nXReduced = 1;
7258
0
            if (nYReduced == 0)
7259
0
                nYReduced = 1;
7260
0
        }
7261
7262
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
7263
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7264
7265
0
        const CPLErr eErr =
7266
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7267
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7268
0
        if (eErr != CE_None)
7269
0
        {
7270
0
            CPLFree(pData);
7271
0
            return eErr;
7272
0
        }
7273
7274
0
        GByte *pabyMaskData = nullptr;
7275
0
        if (poMaskBand)
7276
0
        {
7277
0
            pabyMaskData =
7278
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7279
0
            if (!pabyMaskData)
7280
0
            {
7281
0
                CPLFree(pData);
7282
0
                return CE_Failure;
7283
0
            }
7284
7285
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7286
0
                                     pabyMaskData, nXReduced, nYReduced,
7287
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
7288
0
            {
7289
0
                CPLFree(pData);
7290
0
                CPLFree(pabyMaskData);
7291
0
                return CE_Failure;
7292
0
            }
7293
0
        }
7294
7295
        /* this isn't the fastest way to do this, but is easier for now */
7296
0
        for (int iY = 0; iY < nYReduced; iY++)
7297
0
        {
7298
0
            for (int iX = 0; iX < nXReduced; iX++)
7299
0
            {
7300
0
                const int iOffset = iX + iY * nXReduced;
7301
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7302
0
                    continue;
7303
7304
0
                bool bValid = true;
7305
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7306
0
                                               iOffset, sNoDataValues, bValid);
7307
0
                if (!bValid)
7308
0
                    continue;
7309
7310
0
                dfMin = std::min(dfMin, dfValue);
7311
0
                dfMax = std::max(dfMax, dfValue);
7312
7313
0
                nValidCount++;
7314
0
                if (dfMin == dfMax)
7315
0
                {
7316
0
                    if (nValidCount == 1)
7317
0
                        dfMean = dfMin;
7318
0
                }
7319
0
                else
7320
0
                {
7321
0
                    const double dfDelta = dfValue - dfMean;
7322
0
                    dfMean += dfDelta / nValidCount;
7323
0
                    dfM2 += dfDelta * (dfValue - dfMean);
7324
0
                }
7325
0
            }
7326
0
        }
7327
7328
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7329
7330
0
        CPLFree(pData);
7331
0
        CPLFree(pabyMaskData);
7332
0
    }
7333
7334
0
    else  // No arbitrary overviews.
7335
0
    {
7336
0
        if (!InitBlockInfo())
7337
0
            return CE_Failure;
7338
7339
        /* --------------------------------------------------------------------
7340
         */
7341
        /*      Figure out the ratio of blocks we will read to get an */
7342
        /*      approximate value. */
7343
        /* --------------------------------------------------------------------
7344
         */
7345
0
        int nSampleRate = 1;
7346
0
        if (bApproxOK)
7347
0
        {
7348
0
            nSampleRate = static_cast<int>(std::max(
7349
0
                1.0,
7350
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7351
            // We want to avoid probing only the first column of blocks for
7352
            // a square shaped raster, because it is not unlikely that it may
7353
            // be padding only (#6378)
7354
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7355
0
                nSampleRate += 1;
7356
0
        }
7357
0
        if (nSampleRate == 1)
7358
0
            bApproxOK = false;
7359
7360
        // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7361
        // for each block, and possibly for the whole raster.
7362
0
        if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7363
0
                            eDataType == GDT_UInt16))
7364
0
        {
7365
            // We can do integer computation on the whole raster in the Byte case
7366
            // only if the number of pixels explored is lower than
7367
            // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7368
            // Should be 99.99999% of cases.
7369
            // For GUInt16, this limits to raster of 4 giga pixels
7370
7371
0
            const bool bIntegerStats =
7372
0
                ((eDataType == GDT_UInt8 &&
7373
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7374
0
                          nSampleRate <
7375
0
                      GUINTBIG_MAX / (255U * 255U) /
7376
0
                          (static_cast<GUInt64>(nBlockXSize) *
7377
0
                           static_cast<GUInt64>(nBlockYSize))) ||
7378
0
                 (eDataType == GDT_UInt16 &&
7379
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7380
0
                          nSampleRate <
7381
0
                      GUINTBIG_MAX / (65535U * 65535U) /
7382
0
                          (static_cast<GUInt64>(nBlockXSize) *
7383
0
                           static_cast<GUInt64>(nBlockYSize)))) &&
7384
                // Can be set to NO for easier debugging of the !bIntegerStats
7385
                // case which requires huge rasters to trigger
7386
0
                CPLTestBool(
7387
0
                    CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7388
7389
0
            const GUInt32 nMaxValueType =
7390
0
                (eDataType == GDT_UInt8) ? 255 : 65535;
7391
0
            GUInt32 nMin = nMaxValueType;
7392
0
            GUInt32 nMax = 0;
7393
0
            GUIntBig nSum = 0;
7394
0
            GUIntBig nSumSquare = 0;
7395
            // If no valid nodata, map to invalid value (256 for Byte)
7396
0
            const GUInt32 nNoDataValue =
7397
0
                (sNoDataValues.bGotNoDataValue &&
7398
0
                 sNoDataValues.dfNoDataValue >= 0 &&
7399
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
7400
0
                 fabs(sNoDataValues.dfNoDataValue -
7401
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7402
0
                                           1e-10)) < 1e-10)
7403
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7404
0
                    : nMaxValueType + 1;
7405
7406
0
            int nChunkXSize = nBlockXSize;
7407
0
            int nChunkYSize = nBlockYSize;
7408
0
            int nChunksPerRow = nBlocksPerRow;
7409
0
            int nChunksPerCol = nBlocksPerColumn;
7410
7411
0
            int nThreads = 1;
7412
0
            if (nChunkYSize > 1)
7413
0
            {
7414
0
                nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7415
0
                                             /* bDefaultToAllCPUs = */ false);
7416
0
            }
7417
7418
0
            int nNewChunkXSize = nChunkXSize;
7419
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
7420
0
            if (!bApproxOK && nThreads > 1 &&
7421
0
                MayMultiBlockReadingBeMultiThreaded())
7422
0
            {
7423
0
                const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7424
0
                const size_t nChunkPixels =
7425
0
                    static_cast<size_t>(nChunkXSize) * nChunkYSize;
7426
0
                if (nRAMAmount > 0 &&
7427
0
                    nChunkPixels <=
7428
0
                        std::numeric_limits<size_t>::max() / nDTSize)
7429
0
                {
7430
0
                    const size_t nBlockSize = nDTSize * nChunkPixels;
7431
0
                    const int64_t nBlockCount = nRAMAmount / nBlockSize;
7432
0
                    if (nBlockCount >= 2)
7433
0
                    {
7434
0
                        nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7435
0
                            nChunkXSize * std::min<int64_t>(
7436
0
                                              nBlockCount,
7437
0
                                              (std::numeric_limits<int>::max() -
7438
0
                                               ALIGNMENT_AVX2_OPTIM) /
7439
0
                                                  nChunkPixels),
7440
0
                            nRasterXSize));
7441
7442
0
                        CPLAssert(nChunkXSize <
7443
0
                                  std::numeric_limits<int>::max() /
7444
0
                                      nChunkYSize);
7445
0
                    }
7446
0
                }
7447
0
            }
7448
7449
0
            std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
7450
0
            GByte *pabyTemp = nullptr;
7451
0
            if (nNewChunkXSize != nBlockXSize)
7452
0
            {
7453
0
                pabyTempUnaligned.reset(static_cast<GByte *>(
7454
0
                    VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
7455
0
                              ALIGNMENT_AVX2_OPTIM)));
7456
0
                if (pabyTempUnaligned)
7457
0
                {
7458
0
                    pabyTemp = reinterpret_cast<GByte *>(
7459
0
                        reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
7460
0
                        (ALIGNMENT_AVX2_OPTIM -
7461
0
                         (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
7462
0
                          ALIGNMENT_AVX2_OPTIM)));
7463
0
                    nChunkXSize = nNewChunkXSize;
7464
0
                    nChunksPerRow =
7465
0
                        cpl::div_round_up(nRasterXSize, nChunkXSize);
7466
0
                }
7467
0
            }
7468
7469
0
            for (GIntBig iSampleBlock = 0;
7470
0
                 iSampleBlock <
7471
0
                 static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7472
0
                 iSampleBlock += nSampleRate)
7473
0
            {
7474
0
                const int iYBlock =
7475
0
                    static_cast<int>(iSampleBlock / nChunksPerRow);
7476
0
                const int iXBlock =
7477
0
                    static_cast<int>(iSampleBlock % nChunksPerRow);
7478
7479
0
                const int nXCheck =
7480
0
                    std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7481
0
                const int nYCheck =
7482
0
                    std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7483
7484
0
                GDALRasterBlock *poBlock = nullptr;
7485
0
                if (pabyTemp)
7486
0
                {
7487
0
                    if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7488
0
                                 iYBlock * nChunkYSize, nXCheck, nYCheck,
7489
0
                                 pabyTemp, nXCheck, nYCheck, eDataType, 0,
7490
0
                                 static_cast<GSpacing>(nChunkXSize) * nDTSize,
7491
0
                                 nullptr) != CE_None)
7492
0
                    {
7493
0
                        return CE_Failure;
7494
0
                    }
7495
0
                }
7496
0
                else
7497
0
                {
7498
0
                    poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7499
0
                    if (poBlock == nullptr)
7500
0
                    {
7501
0
                        return CE_Failure;
7502
0
                    }
7503
0
                }
7504
7505
0
                const void *const pData =
7506
0
                    poBlock ? poBlock->GetDataRef() : pabyTemp;
7507
7508
0
                GUIntBig nBlockSum = 0;
7509
0
                GUIntBig nBlockSumSquare = 0;
7510
0
                GUIntBig nBlockSampleCount = 0;
7511
0
                GUIntBig nBlockValidCount = 0;
7512
0
                GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7513
0
                GUIntBig &nBlockSumSquareRef =
7514
0
                    bIntegerStats ? nSumSquare : nBlockSumSquare;
7515
0
                GUIntBig &nBlockSampleCountRef =
7516
0
                    bIntegerStats ? nSampleCount : nBlockSampleCount;
7517
0
                GUIntBig &nBlockValidCountRef =
7518
0
                    bIntegerStats ? nValidCount : nBlockValidCount;
7519
7520
0
                if (eDataType == GDT_UInt8)
7521
0
                {
7522
0
                    ComputeStatisticsInternal<
7523
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
7524
0
                        f(nXCheck, nChunkXSize, nYCheck,
7525
0
                          static_cast<const GByte *>(pData),
7526
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7527
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7528
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7529
0
                }
7530
0
                else
7531
0
                {
7532
0
                    ComputeStatisticsInternal<
7533
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7534
0
                        f(nXCheck, nChunkXSize, nYCheck,
7535
0
                          static_cast<const GUInt16 *>(pData),
7536
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7537
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7538
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7539
0
                }
7540
7541
0
                if (poBlock)
7542
0
                    poBlock->DropLock();
7543
7544
0
                if (!bIntegerStats)
7545
0
                {
7546
0
                    nSampleCount += nBlockSampleCount;
7547
0
                    if (nBlockValidCount)
7548
0
                    {
7549
                        // Update the global mean and M2 (the difference of the
7550
                        // square to the mean) from the values of the block
7551
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7552
0
                        const double dfBlockValidCount =
7553
0
                            static_cast<double>(nBlockValidCount);
7554
0
                        const double dfBlockMean =
7555
0
                            static_cast<double>(nBlockSum) / dfBlockValidCount;
7556
0
                        const double dfBlockM2 =
7557
0
                            static_cast<double>(
7558
0
                                GDALUInt128::Mul(nBlockSumSquare,
7559
0
                                                 nBlockValidCount) -
7560
0
                                GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7561
0
                            dfBlockValidCount;
7562
0
                        const double dfDelta = dfBlockMean - dfMean;
7563
0
                        const auto nNewValidCount =
7564
0
                            nValidCount + nBlockValidCount;
7565
0
                        const double dfNewValidCount =
7566
0
                            static_cast<double>(nNewValidCount);
7567
0
                        dfMean +=
7568
0
                            dfDelta * (dfBlockValidCount / dfNewValidCount);
7569
0
                        dfM2 +=
7570
0
                            dfBlockM2 + dfDelta * dfDelta *
7571
0
                                            static_cast<double>(nValidCount) *
7572
0
                                            dfBlockValidCount / dfNewValidCount;
7573
0
                        nValidCount = nNewValidCount;
7574
0
                    }
7575
0
                }
7576
7577
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
7578
0
                                     (static_cast<double>(nChunksPerRow) *
7579
0
                                      nChunksPerCol),
7580
0
                                 "Compute Statistics", pProgressData))
7581
0
                {
7582
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
7583
0
                                "User terminated");
7584
0
                    return CE_Failure;
7585
0
                }
7586
0
            }
7587
7588
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7589
0
            {
7590
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7591
0
                return CE_Failure;
7592
0
            }
7593
7594
0
            double dfStdDev = 0;
7595
0
            if (bIntegerStats)
7596
0
            {
7597
0
                if (nValidCount)
7598
0
                    dfMean = static_cast<double>(nSum) / nValidCount;
7599
7600
                // To avoid potential precision issues when doing the difference,
7601
                // we need to do that computation on 128 bit rather than casting
7602
                // to double
7603
0
                const GDALUInt128 nTmpForStdDev(
7604
0
                    GDALUInt128::Mul(nSumSquare, nValidCount) -
7605
0
                    GDALUInt128::Mul(nSum, nSum));
7606
0
                dfStdDev =
7607
0
                    nValidCount > 0
7608
0
                        ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7609
0
                        : 0.0;
7610
0
            }
7611
0
            else if (nValidCount > 0)
7612
0
            {
7613
0
                dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7614
0
            }
7615
7616
            /// Save computed information
7617
0
            if (bSetStatistics)
7618
0
            {
7619
0
                if (nValidCount > 0)
7620
0
                {
7621
0
                    if (bApproxOK)
7622
0
                    {
7623
0
                        SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7624
0
                    }
7625
0
                    else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7626
0
                    {
7627
0
                        SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7628
0
                    }
7629
0
                    SetStatistics(nMin, nMax, dfMean, dfStdDev);
7630
0
                }
7631
7632
0
                SetValidPercent(nSampleCount, nValidCount);
7633
0
            }
7634
7635
            /* --------------------------------------------------------------------
7636
             */
7637
            /*      Record results. */
7638
            /* --------------------------------------------------------------------
7639
             */
7640
0
            if (pdfMin != nullptr)
7641
0
                *pdfMin = nValidCount ? nMin : 0;
7642
0
            if (pdfMax != nullptr)
7643
0
                *pdfMax = nValidCount ? nMax : 0;
7644
7645
0
            if (pdfMean != nullptr)
7646
0
                *pdfMean = dfMean;
7647
7648
0
            if (pdfStdDev != nullptr)
7649
0
                *pdfStdDev = dfStdDev;
7650
7651
0
            if (nValidCount > 0)
7652
0
                return CE_None;
7653
7654
0
            ReportError(CE_Failure, CPLE_AppDefined,
7655
0
                        "Failed to compute statistics, no valid pixels found "
7656
0
                        "in sampling.");
7657
0
            return CE_Failure;
7658
0
        }
7659
7660
0
        GByte *pabyMaskData = nullptr;
7661
0
        if (poMaskBand)
7662
0
        {
7663
0
            pabyMaskData = static_cast<GByte *>(
7664
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7665
0
            if (!pabyMaskData)
7666
0
            {
7667
0
                return CE_Failure;
7668
0
            }
7669
0
        }
7670
7671
0
        float fMin = std::numeric_limits<float>::infinity();
7672
0
        float fMax = -std::numeric_limits<float>::infinity();
7673
0
        bool bFloat32Optim =
7674
0
            (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7675
0
             eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7676
0
            !pabyMaskData &&
7677
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7678
0
            CPLTestBool(
7679
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7680
0
        std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7681
7682
0
        int nChunkXSize = nBlockXSize;
7683
0
        int nChunkYSize = nBlockYSize;
7684
0
        int nChunksPerRow = nBlocksPerRow;
7685
0
        int nChunksPerCol = nBlocksPerColumn;
7686
7687
0
#define nBlockXSize use_nChunkXSize_instead
7688
0
#define nBlockYSize use_nChunkYSize_instead
7689
0
#define nBlocksPerRow use_nChunksPerRow_instead
7690
0
#define nBlocksPerColumn use_nChunksPerCol_instead
7691
7692
0
        int nThreads = 1;
7693
0
        CPLWorkerThreadPool *psThreadPool = nullptr;
7694
0
        if (bFloat32Optim)
7695
0
        {
7696
0
            if (nChunkYSize > 1)
7697
0
            {
7698
0
                nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7699
0
                                             /* bDefaultToAllCPUs = */ false);
7700
0
            }
7701
7702
0
            int nNewChunkXSize = nChunkXSize;
7703
0
            if (!bApproxOK && nThreads > 1 &&
7704
0
                MayMultiBlockReadingBeMultiThreaded())
7705
0
            {
7706
0
                const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7707
0
                const size_t nChunkPixels =
7708
0
                    static_cast<size_t>(nChunkXSize) * nChunkYSize;
7709
0
                if (nRAMAmount > 0 &&
7710
0
                    nChunkPixels <=
7711
0
                        std::numeric_limits<size_t>::max() / sizeof(float))
7712
0
                {
7713
0
                    const size_t nBlockSizeAsFloat32 =
7714
0
                        sizeof(float) * nChunkPixels;
7715
0
                    const int64_t nBlockCount =
7716
0
                        nRAMAmount / nBlockSizeAsFloat32;
7717
0
                    if (nBlockCount >= 2)
7718
0
                    {
7719
0
                        nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7720
0
                            nChunkXSize * std::min<int64_t>(
7721
0
                                              nBlockCount,
7722
0
                                              std::numeric_limits<int>::max() /
7723
0
                                                  nChunkPixels),
7724
0
                            nRasterXSize));
7725
7726
0
                        CPLAssert(nChunkXSize <
7727
0
                                  std::numeric_limits<int>::max() /
7728
0
                                      nChunkYSize);
7729
0
                    }
7730
0
                }
7731
0
            }
7732
0
            if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7733
0
            {
7734
0
                pafTemp.reset(static_cast<float *>(
7735
0
                    VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7736
0
                bFloat32Optim = pafTemp != nullptr;
7737
0
                if (bFloat32Optim)
7738
0
                {
7739
0
                    nChunkXSize = nNewChunkXSize;
7740
0
                    nChunksPerRow =
7741
0
                        cpl::div_round_up(nRasterXSize, nChunkXSize);
7742
0
                }
7743
0
            }
7744
0
            CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7745
0
                     nChunkXSize, nChunkYSize);
7746
0
        }
7747
7748
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7749
0
        const bool bFloat64Optim =
7750
0
            eDataType == GDT_Float64 && !pabyMaskData &&
7751
0
            nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7752
0
            CPLTestBool(
7753
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7754
0
#endif
7755
7756
0
        std::vector<StatisticsTaskFloat32> tasksFloat32;
7757
7758
0
        for (GIntBig iSampleBlock = 0;
7759
0
             iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7760
0
             iSampleBlock += nSampleRate)
7761
0
        {
7762
0
            const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7763
0
            const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7764
7765
0
            const int nXCheck =
7766
0
                std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7767
0
            const int nYCheck =
7768
0
                std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7769
7770
0
            if (poMaskBand &&
7771
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7772
0
                                     iYBlock * nChunkYSize, nXCheck, nYCheck,
7773
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7774
0
                                     0, nChunkXSize, nullptr) != CE_None)
7775
0
            {
7776
0
                CPLFree(pabyMaskData);
7777
0
                return CE_Failure;
7778
0
            }
7779
7780
0
            GDALRasterBlock *poBlock = nullptr;
7781
0
            if (pafTemp)
7782
0
            {
7783
0
                if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7784
0
                             iYBlock * nChunkYSize, nXCheck, nYCheck,
7785
0
                             pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7786
0
                             static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7787
0
                             nullptr) != CE_None)
7788
0
                {
7789
0
                    CPLFree(pabyMaskData);
7790
0
                    return CE_Failure;
7791
0
                }
7792
0
            }
7793
0
            else
7794
0
            {
7795
0
                poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7796
0
                if (poBlock == nullptr)
7797
0
                {
7798
0
                    CPLFree(pabyMaskData);
7799
0
                    return CE_Failure;
7800
0
                }
7801
0
            }
7802
7803
0
            const void *const pData =
7804
0
                poBlock ? poBlock->GetDataRef() : pafTemp.get();
7805
7806
0
            if (bFloat32Optim)
7807
0
            {
7808
0
                const float *const pafSrcData =
7809
0
                    static_cast<const float *>(pData);
7810
7811
0
                const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7812
0
                                        !std::isnan(sNoDataValues.fNoDataValue);
7813
0
                const int nTasks = std::min(nYCheck, nThreads);
7814
0
                const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7815
0
                tasksFloat32.clear();
7816
0
                for (int i = 0; i < nTasks; ++i)
7817
0
                {
7818
0
                    StatisticsTaskFloat32 task;
7819
0
                    task.eDataType = eDataType;
7820
0
                    task.bHasNoData = bHasNoData;
7821
0
                    task.psNoDataValues = &sNoDataValues;
7822
0
                    task.nChunkXSize = nChunkXSize;
7823
0
                    task.fMin = fMin;
7824
0
                    task.fMax = fMax;
7825
0
                    task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7826
0
                                                       nRowsPerTask *
7827
0
                                                       nChunkXSize;
7828
0
                    task.nXCheck = nXCheck;
7829
0
                    task.nYCheck =
7830
0
                        std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7831
0
                    tasksFloat32.emplace_back(std::move(task));
7832
0
                }
7833
0
                if (psThreadPool)
7834
0
                {
7835
0
                    auto poJobQueue = psThreadPool->CreateJobQueue();
7836
0
                    for (auto &task : tasksFloat32)
7837
0
                    {
7838
0
                        poJobQueue->SubmitJob([&task]() { task.Perform(); });
7839
0
                    }
7840
0
                    poJobQueue->WaitCompletion();
7841
0
                }
7842
0
                else
7843
0
                {
7844
0
                    tasksFloat32[0].Perform();
7845
0
                }
7846
7847
0
                for (const auto &task : tasksFloat32)
7848
0
                {
7849
0
                    if (task.dfBlockValidCount > 0)
7850
0
                    {
7851
0
                        fMin = std::min(fMin, task.fMin);
7852
0
                        fMax = std::max(fMax, task.fMax);
7853
7854
                        // Update the global mean and M2 (the difference of the
7855
                        // square to the mean) from the values of the block
7856
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7857
0
                        const auto nNewValidCount =
7858
0
                            nValidCount +
7859
0
                            static_cast<int>(task.dfBlockValidCount);
7860
0
                        dfM2 += task.dfBlockM2;
7861
0
                        if (task.dfBlockMean != dfMean)
7862
0
                        {
7863
0
                            if (nValidCount == 0)
7864
0
                            {
7865
0
                                dfMean = task.dfBlockMean;
7866
0
                            }
7867
0
                            else
7868
0
                            {
7869
0
                                const double dfDelta =
7870
0
                                    task.dfBlockMean - dfMean;
7871
0
                                const double dfNewValidCount =
7872
0
                                    static_cast<double>(nNewValidCount);
7873
0
                                dfMean += dfDelta * (task.dfBlockValidCount /
7874
0
                                                     dfNewValidCount);
7875
0
                                dfM2 += dfDelta * dfDelta *
7876
0
                                        static_cast<double>(nValidCount) *
7877
0
                                        task.dfBlockValidCount /
7878
0
                                        dfNewValidCount;
7879
0
                            }
7880
0
                        }
7881
0
                        nValidCount = nNewValidCount;
7882
0
                    }
7883
0
                }
7884
0
            }
7885
7886
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7887
0
            else if (bFloat64Optim)
7888
0
            {
7889
0
                const bool bHasNoData =
7890
0
                    sNoDataValues.bGotNoDataValue &&
7891
0
                    !std::isnan(sNoDataValues.dfNoDataValue);
7892
0
                double dfBlockMean = 0;
7893
0
                double dfBlockM2 = 0;
7894
0
                double dfBlockValidCount = 0;
7895
0
                for (int iY = 0; iY < nYCheck; iY++)
7896
0
                {
7897
0
                    const int iOffset = iY * nChunkXSize;
7898
0
                    if (dfBlockValidCount != 0 && dfMin != dfMax)
7899
0
                    {
7900
0
                        int iX = 0;
7901
0
                        if (bHasNoData)
7902
0
                        {
7903
0
                            iX = ComputeStatisticsFloat64_SSE2<
7904
0
                                /* bCheckMinEqMax = */ false,
7905
0
                                /* bHasNoData = */ true>(
7906
0
                                static_cast<const double *>(pData) + iOffset,
7907
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7908
0
                                dfMax, dfBlockMean, dfBlockM2,
7909
0
                                dfBlockValidCount);
7910
0
                        }
7911
0
                        else
7912
0
                        {
7913
0
                            iX = ComputeStatisticsFloat64_SSE2<
7914
0
                                /* bCheckMinEqMax = */ false,
7915
0
                                /* bHasNoData = */ false>(
7916
0
                                static_cast<const double *>(pData) + iOffset,
7917
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7918
0
                                dfMax, dfBlockMean, dfBlockM2,
7919
0
                                dfBlockValidCount);
7920
0
                        }
7921
0
                        for (; iX < nXCheck; iX++)
7922
0
                        {
7923
0
                            const double dfValue = static_cast<const double *>(
7924
0
                                pData)[iOffset + iX];
7925
0
                            if (std::isnan(dfValue) ||
7926
0
                                (bHasNoData &&
7927
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7928
0
                                continue;
7929
0
                            dfMin = std::min(dfMin, dfValue);
7930
0
                            dfMax = std::max(dfMax, dfValue);
7931
0
                            dfBlockValidCount += 1.0;
7932
0
                            const double dfDelta = dfValue - dfBlockMean;
7933
0
                            dfBlockMean += dfDelta / dfBlockValidCount;
7934
0
                            dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7935
0
                        }
7936
0
                    }
7937
0
                    else
7938
0
                    {
7939
0
                        int iX = 0;
7940
0
                        if (dfBlockValidCount == 0)
7941
0
                        {
7942
0
                            for (; iX < nXCheck; iX++)
7943
0
                            {
7944
0
                                const double dfValue =
7945
0
                                    static_cast<const double *>(
7946
0
                                        pData)[iOffset + iX];
7947
0
                                if (std::isnan(dfValue) ||
7948
0
                                    (bHasNoData &&
7949
0
                                     dfValue == sNoDataValues.dfNoDataValue))
7950
0
                                    continue;
7951
0
                                dfMin = std::min(dfMin, dfValue);
7952
0
                                dfMax = std::max(dfMax, dfValue);
7953
0
                                dfBlockValidCount = 1;
7954
0
                                dfBlockMean = dfValue;
7955
0
                                iX++;
7956
0
                                break;
7957
0
                            }
7958
0
                        }
7959
0
                        if (bHasNoData)
7960
0
                        {
7961
0
                            iX = ComputeStatisticsFloat64_SSE2<
7962
0
                                /* bCheckMinEqMax = */ true,
7963
0
                                /* bHasNoData = */ true>(
7964
0
                                static_cast<const double *>(pData) + iOffset,
7965
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7966
0
                                dfMax, dfBlockMean, dfBlockM2,
7967
0
                                dfBlockValidCount);
7968
0
                        }
7969
0
                        else
7970
0
                        {
7971
0
                            iX = ComputeStatisticsFloat64_SSE2<
7972
0
                                /* bCheckMinEqMax = */ true,
7973
0
                                /* bHasNoData = */ false>(
7974
0
                                static_cast<const double *>(pData) + iOffset,
7975
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7976
0
                                dfMax, dfBlockMean, dfBlockM2,
7977
0
                                dfBlockValidCount);
7978
0
                        }
7979
0
                        for (; iX < nXCheck; iX++)
7980
0
                        {
7981
0
                            const double dfValue = static_cast<const double *>(
7982
0
                                pData)[iOffset + iX];
7983
0
                            if (std::isnan(dfValue) ||
7984
0
                                (bHasNoData &&
7985
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7986
0
                                continue;
7987
0
                            dfMin = std::min(dfMin, dfValue);
7988
0
                            dfMax = std::max(dfMax, dfValue);
7989
0
                            dfBlockValidCount += 1.0;
7990
0
                            if (dfMin != dfMax)
7991
0
                            {
7992
0
                                const double dfDelta = dfValue - dfBlockMean;
7993
0
                                dfBlockMean += dfDelta / dfBlockValidCount;
7994
0
                                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7995
0
                            }
7996
0
                        }
7997
0
                    }
7998
0
                }
7999
8000
0
                if (dfBlockValidCount > 0)
8001
0
                {
8002
                    // Update the global mean and M2 (the difference of the
8003
                    // square to the mean) from the values of the block
8004
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
8005
0
                    const auto nNewValidCount =
8006
0
                        nValidCount + static_cast<int>(dfBlockValidCount);
8007
0
                    dfM2 += dfBlockM2;
8008
0
                    if (dfBlockMean != dfMean)
8009
0
                    {
8010
0
                        if (nValidCount == 0)
8011
0
                        {
8012
0
                            dfMean = dfBlockMean;
8013
0
                        }
8014
0
                        else
8015
0
                        {
8016
0
                            const double dfDelta = dfBlockMean - dfMean;
8017
0
                            const double dfNewValidCount =
8018
0
                                static_cast<double>(nNewValidCount);
8019
0
                            dfMean +=
8020
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
8021
0
                            dfM2 += dfDelta * dfDelta *
8022
0
                                    static_cast<double>(nValidCount) *
8023
0
                                    dfBlockValidCount / dfNewValidCount;
8024
0
                        }
8025
0
                    }
8026
0
                    nValidCount = nNewValidCount;
8027
0
                }
8028
0
            }
8029
0
#endif  // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
8030
8031
0
            else
8032
0
            {
8033
                // This isn't the fastest way to do this, but is easier for now.
8034
0
                for (int iY = 0; iY < nYCheck; iY++)
8035
0
                {
8036
0
                    if (nValidCount && dfMin != dfMax)
8037
0
                    {
8038
0
                        for (int iX = 0; iX < nXCheck; iX++)
8039
0
                        {
8040
0
                            const GPtrDiff_t iOffset =
8041
0
                                iX + 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 =
8047
0
                                GetPixelValue(eDataType, bSignedByte, pData,
8048
0
                                              iOffset, sNoDataValues, bValid);
8049
8050
0
                            if (!bValid)
8051
0
                                continue;
8052
8053
0
                            dfMin = std::min(dfMin, dfValue);
8054
0
                            dfMax = std::max(dfMax, dfValue);
8055
8056
0
                            nValidCount++;
8057
0
                            const double dfDelta = dfValue - dfMean;
8058
0
                            dfMean += dfDelta / nValidCount;
8059
0
                            dfM2 += dfDelta * (dfValue - dfMean);
8060
0
                        }
8061
0
                    }
8062
0
                    else
8063
0
                    {
8064
0
                        int iX = 0;
8065
0
                        if (nValidCount == 0)
8066
0
                        {
8067
0
                            for (; iX < nXCheck; iX++)
8068
0
                            {
8069
0
                                const GPtrDiff_t iOffset =
8070
0
                                    iX +
8071
0
                                    static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8072
0
                                if (pabyMaskData && pabyMaskData[iOffset] == 0)
8073
0
                                    continue;
8074
8075
0
                                bool bValid = true;
8076
0
                                double dfValue = GetPixelValue(
8077
0
                                    eDataType, bSignedByte, pData, iOffset,
8078
0
                                    sNoDataValues, bValid);
8079
8080
0
                                if (!bValid)
8081
0
                                    continue;
8082
8083
0
                                dfMin = dfValue;
8084
0
                                dfMax = dfValue;
8085
0
                                dfMean = dfValue;
8086
0
                                nValidCount = 1;
8087
0
                                iX++;
8088
0
                                break;
8089
0
                            }
8090
0
                        }
8091
0
                        for (; iX < nXCheck; iX++)
8092
0
                        {
8093
0
                            const GPtrDiff_t iOffset =
8094
0
                                iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8095
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8096
0
                                continue;
8097
8098
0
                            bool bValid = true;
8099
0
                            double dfValue =
8100
0
                                GetPixelValue(eDataType, bSignedByte, pData,
8101
0
                                              iOffset, sNoDataValues, bValid);
8102
8103
0
                            if (!bValid)
8104
0
                                continue;
8105
8106
0
                            dfMin = std::min(dfMin, dfValue);
8107
0
                            dfMax = std::max(dfMax, dfValue);
8108
8109
0
                            nValidCount++;
8110
0
                            if (dfMin != dfMax)
8111
0
                            {
8112
0
                                const double dfDelta = dfValue - dfMean;
8113
0
                                dfMean += dfDelta / nValidCount;
8114
0
                                dfM2 += dfDelta * (dfValue - dfMean);
8115
0
                            }
8116
0
                        }
8117
0
                    }
8118
0
                }
8119
0
            }
8120
8121
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8122
8123
0
            if (poBlock)
8124
0
                poBlock->DropLock();
8125
8126
0
            if (!pfnProgress(
8127
0
                    static_cast<double>(iSampleBlock) /
8128
0
                        (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8129
0
                    "Compute Statistics", pProgressData))
8130
0
            {
8131
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8132
0
                CPLFree(pabyMaskData);
8133
0
                return CE_Failure;
8134
0
            }
8135
0
        }
8136
8137
0
#undef nBlockXSize
8138
0
#undef nBlockYSize
8139
0
#undef nBlocksPerRow
8140
0
#undef nBlocksPerColumn
8141
8142
0
        if (bFloat32Optim)
8143
0
        {
8144
0
            dfMin = static_cast<double>(fMin);
8145
0
            dfMax = static_cast<double>(fMax);
8146
0
        }
8147
0
        CPLFree(pabyMaskData);
8148
0
    }
8149
8150
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8151
0
    {
8152
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8153
0
        return CE_Failure;
8154
0
    }
8155
8156
    /* -------------------------------------------------------------------- */
8157
    /*      Save computed information.                                      */
8158
    /* -------------------------------------------------------------------- */
8159
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8160
8161
0
    if (nValidCount > 0)
8162
0
    {
8163
0
        if (bSetStatistics)
8164
0
        {
8165
0
            if (bApproxOK)
8166
0
            {
8167
0
                SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8168
0
            }
8169
0
            else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8170
0
            {
8171
0
                SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8172
0
            }
8173
0
            SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8174
0
        }
8175
0
    }
8176
0
    else
8177
0
    {
8178
0
        dfMin = 0.0;
8179
0
        dfMax = 0.0;
8180
0
    }
8181
8182
0
    if (bSetStatistics)
8183
0
        SetValidPercent(nSampleCount, nValidCount);
8184
8185
    /* -------------------------------------------------------------------- */
8186
    /*      Record results.                                                 */
8187
    /* -------------------------------------------------------------------- */
8188
0
    if (pdfMin != nullptr)
8189
0
        *pdfMin = dfMin;
8190
0
    if (pdfMax != nullptr)
8191
0
        *pdfMax = dfMax;
8192
8193
0
    if (pdfMean != nullptr)
8194
0
        *pdfMean = dfMean;
8195
8196
0
    if (pdfStdDev != nullptr)
8197
0
        *pdfStdDev = dfStdDev;
8198
8199
0
    if (nValidCount > 0)
8200
0
        return CE_None;
8201
8202
0
    ReportError(
8203
0
        CE_Failure, CPLE_AppDefined,
8204
0
        "Failed to compute statistics, no valid pixels found in sampling.");
8205
0
    return CE_Failure;
8206
0
}
8207
8208
/************************************************************************/
8209
/*                    GDALComputeRasterStatistics()                     */
8210
/************************************************************************/
8211
8212
/**
8213
 * \brief Compute image statistics.
8214
 *
8215
 * @see GDALComputeRasterStatisticsEx()
8216
 * @see GDALRasterBand::ComputeStatistics()
8217
 */
8218
8219
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8220
                                               int bApproxOK, double *pdfMin,
8221
                                               double *pdfMax, double *pdfMean,
8222
                                               double *pdfStdDev,
8223
                                               GDALProgressFunc pfnProgress,
8224
                                               void *pProgressData)
8225
8226
0
{
8227
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8228
8229
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8230
8231
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8232
0
                                     pdfStdDev, pfnProgress, pProgressData,
8233
0
                                     nullptr);
8234
0
}
8235
8236
/************************************************************************/
8237
/*                   GDALComputeRasterStatisticsEx()                    */
8238
/************************************************************************/
8239
8240
/**
8241
 * \brief Compute image statistics.
8242
 *
8243
 * @see GDALRasterBand::ComputeStatistics()
8244
 *
8245
 * @since 3.14
8246
 */
8247
8248
CPLErr GDALComputeRasterStatisticsEx(GDALRasterBandH hBand, int bApproxOK,
8249
                                     double *pdfMin, double *pdfMax,
8250
                                     double *pdfMean, double *pdfStdDev,
8251
                                     GDALProgressFunc pfnProgress,
8252
                                     void *pProgressData,
8253
                                     CSLConstList papszOptions)
8254
8255
0
{
8256
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatisticsEx", CE_Failure);
8257
8258
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8259
8260
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8261
0
                                     pdfStdDev, pfnProgress, pProgressData,
8262
0
                                     papszOptions);
8263
0
}
8264
8265
/************************************************************************/
8266
/*                           SetStatistics()                            */
8267
/************************************************************************/
8268
8269
/**
8270
 * \brief Set statistics on band.
8271
 *
8272
 * This method can be used to store min/max/mean/standard deviation
8273
 * statistics on a raster band.
8274
 *
8275
 * The default implementation stores them as metadata, and will only work
8276
 * on formats that can save arbitrary metadata.  This method cannot detect
8277
 * whether metadata will be properly saved and so may return CE_None even
8278
 * if the statistics will never be saved.
8279
 *
8280
 * This method is the same as the C function GDALSetRasterStatistics().
8281
 *
8282
 * @param dfMin minimum pixel value.
8283
 *
8284
 * @param dfMax maximum pixel value.
8285
 *
8286
 * @param dfMean mean (average) of all pixel values.
8287
 *
8288
 * @param dfStdDev Standard deviation of all pixel values.
8289
 *
8290
 * @return CE_None on success or CE_Failure on failure.
8291
 */
8292
8293
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8294
                                     double dfStdDev)
8295
8296
0
{
8297
0
    char szValue[128] = {0};
8298
8299
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8300
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
8301
8302
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8303
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8304
8305
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8306
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
8307
8308
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8309
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
8310
8311
0
    return CE_None;
8312
0
}
8313
8314
/************************************************************************/
8315
/*                      GDALSetRasterStatistics()                       */
8316
/************************************************************************/
8317
8318
/**
8319
 * \brief Set statistics on band.
8320
 *
8321
 * @see GDALRasterBand::SetStatistics()
8322
 */
8323
8324
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8325
                                           double dfMax, double dfMean,
8326
                                           double dfStdDev)
8327
8328
0
{
8329
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8330
8331
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8332
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8333
0
}
8334
8335
/************************************************************************/
8336
/*                        ComputeRasterMinMax()                         */
8337
/************************************************************************/
8338
8339
template <class T, bool HAS_NODATA>
8340
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8341
                          T *pMax)
8342
0
{
8343
0
    T min0 = *pMin;
8344
0
    T max0 = *pMax;
8345
0
    T min1 = *pMin;
8346
0
    T max1 = *pMax;
8347
0
    size_t i;
8348
0
    for (i = 0; i + 1 < nElts; i += 2)
8349
0
    {
8350
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
8351
0
        {
8352
0
            min0 = std::min(min0, buffer[i]);
8353
0
            max0 = std::max(max0, buffer[i]);
8354
0
        }
8355
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8356
0
        {
8357
0
            min1 = std::min(min1, buffer[i + 1]);
8358
0
            max1 = std::max(max1, buffer[i + 1]);
8359
0
        }
8360
0
    }
8361
0
    T min = std::min(min0, min1);
8362
0
    T max = std::max(max0, max1);
8363
0
    if (i < nElts)
8364
0
    {
8365
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
8366
0
        {
8367
0
            min = std::min(min, buffer[i]);
8368
0
            max = std::max(max, buffer[i]);
8369
0
        }
8370
0
    }
8371
0
    *pMin = min;
8372
0
    *pMax = max;
8373
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*)
8374
8375
template <GDALDataType eDataType, bool bSignedByte>
8376
static void
8377
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8378
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8379
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
8380
0
{
8381
0
    double dfLocalMin = dfMin;
8382
0
    double dfLocalMax = dfMax;
8383
8384
0
    for (int iY = 0; iY < nYCheck; iY++)
8385
0
    {
8386
0
        for (int iX = 0; iX < nXCheck; iX++)
8387
0
        {
8388
0
            const GPtrDiff_t iOffset =
8389
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8390
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8391
0
                continue;
8392
0
            bool bValid = true;
8393
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8394
0
                                           iOffset, sNoDataValues, bValid);
8395
0
            if (!bValid)
8396
0
                continue;
8397
8398
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
8399
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
8400
0
        }
8401
0
    }
8402
8403
0
    dfMin = dfLocalMin;
8404
0
    dfMax = dfLocalMax;
8405
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&)
8406
8407
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8408
                                 bool bSignedByte, int nXCheck, int nYCheck,
8409
                                 int nBlockXSize,
8410
                                 const GDALNoDataValues &sNoDataValues,
8411
                                 const GByte *pabyMaskData, double &dfMin,
8412
                                 double &dfMax)
8413
0
{
8414
0
    switch (eDataType)
8415
0
    {
8416
0
        case GDT_Unknown:
8417
0
            CPLAssert(false);
8418
0
            break;
8419
0
        case GDT_UInt8:
8420
0
            if (bSignedByte)
8421
0
            {
8422
0
                ComputeMinMaxGeneric<GDT_UInt8, true>(
8423
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8424
0
                    pabyMaskData, dfMin, dfMax);
8425
0
            }
8426
0
            else
8427
0
            {
8428
0
                ComputeMinMaxGeneric<GDT_UInt8, false>(
8429
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8430
0
                    pabyMaskData, dfMin, dfMax);
8431
0
            }
8432
0
            break;
8433
0
        case GDT_Int8:
8434
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8435
0
                                                  nBlockXSize, sNoDataValues,
8436
0
                                                  pabyMaskData, dfMin, dfMax);
8437
0
            break;
8438
0
        case GDT_UInt16:
8439
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8440
0
                                                    nBlockXSize, sNoDataValues,
8441
0
                                                    pabyMaskData, dfMin, dfMax);
8442
0
            break;
8443
0
        case GDT_Int16:
8444
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8445
0
                                                   nBlockXSize, sNoDataValues,
8446
0
                                                   pabyMaskData, dfMin, dfMax);
8447
0
            break;
8448
0
        case GDT_UInt32:
8449
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8450
0
                                                    nBlockXSize, sNoDataValues,
8451
0
                                                    pabyMaskData, dfMin, dfMax);
8452
0
            break;
8453
0
        case GDT_Int32:
8454
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8455
0
                                                   nBlockXSize, sNoDataValues,
8456
0
                                                   pabyMaskData, dfMin, dfMax);
8457
0
            break;
8458
0
        case GDT_UInt64:
8459
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8460
0
                                                    nBlockXSize, sNoDataValues,
8461
0
                                                    pabyMaskData, dfMin, dfMax);
8462
0
            break;
8463
0
        case GDT_Int64:
8464
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8465
0
                                                   nBlockXSize, sNoDataValues,
8466
0
                                                   pabyMaskData, dfMin, dfMax);
8467
0
            break;
8468
0
        case GDT_Float16:
8469
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
8470
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8471
0
                pabyMaskData, dfMin, dfMax);
8472
0
            break;
8473
0
        case GDT_Float32:
8474
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
8475
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8476
0
                pabyMaskData, dfMin, dfMax);
8477
0
            break;
8478
0
        case GDT_Float64:
8479
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
8480
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8481
0
                pabyMaskData, dfMin, dfMax);
8482
0
            break;
8483
0
        case GDT_CInt16:
8484
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8485
0
                                                    nBlockXSize, sNoDataValues,
8486
0
                                                    pabyMaskData, dfMin, dfMax);
8487
0
            break;
8488
0
        case GDT_CInt32:
8489
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8490
0
                                                    nBlockXSize, sNoDataValues,
8491
0
                                                    pabyMaskData, dfMin, dfMax);
8492
0
            break;
8493
0
        case GDT_CFloat16:
8494
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
8495
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8496
0
                pabyMaskData, dfMin, dfMax);
8497
0
            break;
8498
0
        case GDT_CFloat32:
8499
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
8500
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8501
0
                pabyMaskData, dfMin, dfMax);
8502
0
            break;
8503
0
        case GDT_CFloat64:
8504
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
8505
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8506
0
                pabyMaskData, dfMin, dfMax);
8507
0
            break;
8508
0
        case GDT_TypeCount:
8509
0
            CPLAssert(false);
8510
0
            break;
8511
0
    }
8512
0
}
8513
8514
static bool ComputeMinMaxGenericIterBlocks(
8515
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8516
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8517
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8518
    double &dfMin, double &dfMax)
8519
8520
0
{
8521
0
    GByte *pabyMaskData = nullptr;
8522
0
    int nBlockXSize, nBlockYSize;
8523
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8524
8525
0
    if (poMaskBand)
8526
0
    {
8527
0
        pabyMaskData =
8528
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8529
0
        if (!pabyMaskData)
8530
0
        {
8531
0
            return false;
8532
0
        }
8533
0
    }
8534
8535
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8536
0
         iSampleBlock += nSampleRate)
8537
0
    {
8538
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8539
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8540
8541
0
        int nXCheck = 0, nYCheck = 0;
8542
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8543
8544
0
        if (poMaskBand &&
8545
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8546
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8547
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8548
0
                                 nBlockXSize, nullptr) != CE_None)
8549
0
        {
8550
0
            CPLFree(pabyMaskData);
8551
0
            return false;
8552
0
        }
8553
8554
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8555
0
        if (poBlock == nullptr)
8556
0
        {
8557
0
            CPLFree(pabyMaskData);
8558
0
            return false;
8559
0
        }
8560
8561
0
        void *const pData = poBlock->GetDataRef();
8562
8563
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8564
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8565
0
                             dfMax);
8566
8567
0
        poBlock->DropLock();
8568
0
    }
8569
8570
0
    CPLFree(pabyMaskData);
8571
0
    return true;
8572
0
}
8573
8574
/**
8575
 * \brief Compute the min/max values for a band.
8576
 *
8577
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8578
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
8579
 * get an approximate min/max.  If the band has a nodata value it will
8580
 * be excluded from the minimum and maximum.
8581
 *
8582
 * If bApprox is FALSE, then all pixels will be read and used to compute
8583
 * an exact range.
8584
 *
8585
 * This method is the same as the C function GDALComputeRasterMinMax().
8586
 *
8587
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8588
 * FALSE.
8589
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8590
 * maximum (adfMinMax[1]) are returned.
8591
 *
8592
 * @return CE_None on success or CE_Failure on failure.
8593
 */
8594
8595
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8596
0
{
8597
    /* -------------------------------------------------------------------- */
8598
    /*      Does the driver already know the min/max?                       */
8599
    /* -------------------------------------------------------------------- */
8600
0
    if (bApproxOK)
8601
0
    {
8602
0
        int bSuccessMin = FALSE;
8603
0
        int bSuccessMax = FALSE;
8604
8605
0
        double dfMin = GetMinimum(&bSuccessMin);
8606
0
        double dfMax = GetMaximum(&bSuccessMax);
8607
8608
0
        if (bSuccessMin && bSuccessMax)
8609
0
        {
8610
0
            adfMinMax[0] = dfMin;
8611
0
            adfMinMax[1] = dfMax;
8612
0
            return CE_None;
8613
0
        }
8614
0
    }
8615
8616
    /* -------------------------------------------------------------------- */
8617
    /*      If we have overview bands, use them for min/max.                */
8618
    /* -------------------------------------------------------------------- */
8619
    // cppcheck-suppress knownConditionTrueFalse
8620
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8621
0
    {
8622
0
        GDALRasterBand *poBand =
8623
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8624
8625
0
        if (poBand != this)
8626
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8627
0
    }
8628
8629
    /* -------------------------------------------------------------------- */
8630
    /*      Read actual data and compute minimum and maximum.               */
8631
    /* -------------------------------------------------------------------- */
8632
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8633
0
    GDALRasterBand *poMaskBand = nullptr;
8634
0
    if (!sNoDataValues.bGotNoDataValue)
8635
0
    {
8636
0
        const int l_nMaskFlags = GetMaskFlags();
8637
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8638
0
            GetColorInterpretation() != GCI_AlphaBand)
8639
0
        {
8640
0
            poMaskBand = GetMaskBand();
8641
0
        }
8642
0
    }
8643
8644
0
    if (!bApproxOK &&
8645
0
        (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8646
0
         eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8647
0
         eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8648
0
         eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8649
0
         eDataType == GDT_Float64) &&
8650
0
        !poMaskBand)
8651
0
    {
8652
0
        CPLErr eErr = ComputeRasterMinMaxLocation(
8653
0
            &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8654
0
        if (eErr == CE_Warning)
8655
0
        {
8656
0
            ReportError(CE_Failure, CPLE_AppDefined,
8657
0
                        "Failed to compute min/max, no valid pixels found in "
8658
0
                        "sampling.");
8659
0
            eErr = CE_Failure;
8660
0
        }
8661
0
        return eErr;
8662
0
    }
8663
8664
0
    bool bSignedByte = false;
8665
0
    if (eDataType == GDT_UInt8)
8666
0
    {
8667
0
        EnablePixelTypeSignedByteWarning(false);
8668
0
        const char *pszPixelType =
8669
0
            GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
8670
0
        EnablePixelTypeSignedByteWarning(true);
8671
0
        bSignedByte =
8672
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8673
0
    }
8674
8675
0
    GDALRasterIOExtraArg sExtraArg;
8676
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8677
8678
0
    GUInt32 nMin = (eDataType == GDT_UInt8)
8679
0
                       ? 255
8680
0
                       : 65535;  // used for GByte & GUInt16 cases
8681
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
8682
0
    GInt16 nMinInt16 =
8683
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
8684
0
    GInt16 nMaxInt16 =
8685
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
8686
0
    double dfMin =
8687
0
        std::numeric_limits<double>::infinity();  // used for generic code path
8688
0
    double dfMax =
8689
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
8690
0
    const bool bUseOptimizedPath =
8691
0
        !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8692
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8693
8694
0
    const auto ComputeMinMaxForBlock =
8695
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8696
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8697
0
                     int nYCheck)
8698
0
    {
8699
0
        if (eDataType == GDT_UInt8 && !bSignedByte)
8700
0
        {
8701
0
            const bool bHasNoData =
8702
0
                sNoDataValues.bGotNoDataValue &&
8703
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8704
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8705
0
                    sNoDataValues.dfNoDataValue;
8706
0
            const GUInt32 nNoDataValue =
8707
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8708
0
                           : 0;
8709
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8710
0
            ComputeStatisticsInternal<GByte,
8711
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8712
0
                f(nXCheck, nBufferWidth, nYCheck,
8713
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8714
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8715
0
        }
8716
0
        else if (eDataType == GDT_UInt16)
8717
0
        {
8718
0
            const bool bHasNoData =
8719
0
                sNoDataValues.bGotNoDataValue &&
8720
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8721
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8722
0
                    sNoDataValues.dfNoDataValue;
8723
0
            const GUInt32 nNoDataValue =
8724
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8725
0
                           : 0;
8726
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8727
0
            ComputeStatisticsInternal<GUInt16,
8728
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8729
0
                f(nXCheck, nBufferWidth, nYCheck,
8730
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8731
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8732
0
        }
8733
0
        else if (eDataType == GDT_Int16)
8734
0
        {
8735
0
            const bool bHasNoData =
8736
0
                sNoDataValues.bGotNoDataValue &&
8737
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8738
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8739
0
                    sNoDataValues.dfNoDataValue;
8740
0
            if (bHasNoData)
8741
0
            {
8742
0
                const int16_t nNoDataValue =
8743
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8744
0
                for (int iY = 0; iY < nYCheck; iY++)
8745
0
                {
8746
0
                    ComputeMinMax<int16_t, true>(
8747
0
                        static_cast<const int16_t *>(pData) +
8748
0
                            static_cast<size_t>(iY) * nBufferWidth,
8749
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8750
0
                }
8751
0
            }
8752
0
            else
8753
0
            {
8754
0
                for (int iY = 0; iY < nYCheck; iY++)
8755
0
                {
8756
0
                    ComputeMinMax<int16_t, false>(
8757
0
                        static_cast<const int16_t *>(pData) +
8758
0
                            static_cast<size_t>(iY) * nBufferWidth,
8759
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
8760
0
                }
8761
0
            }
8762
0
        }
8763
0
    };
8764
8765
0
    if (bApproxOK && HasArbitraryOverviews())
8766
0
    {
8767
        /* --------------------------------------------------------------------
8768
         */
8769
        /*      Figure out how much the image should be reduced to get an */
8770
        /*      approximate value. */
8771
        /* --------------------------------------------------------------------
8772
         */
8773
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8774
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8775
8776
0
        int nXReduced = nRasterXSize;
8777
0
        int nYReduced = nRasterYSize;
8778
0
        if (dfReduction > 1.0)
8779
0
        {
8780
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8781
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8782
8783
            // Catch the case of huge resizing ratios here
8784
0
            if (nXReduced == 0)
8785
0
                nXReduced = 1;
8786
0
            if (nYReduced == 0)
8787
0
                nYReduced = 1;
8788
0
        }
8789
8790
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
8791
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8792
8793
0
        const CPLErr eErr =
8794
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8795
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8796
0
        if (eErr != CE_None)
8797
0
        {
8798
0
            CPLFree(pData);
8799
0
            return eErr;
8800
0
        }
8801
8802
0
        GByte *pabyMaskData = nullptr;
8803
0
        if (poMaskBand)
8804
0
        {
8805
0
            pabyMaskData =
8806
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8807
0
            if (!pabyMaskData)
8808
0
            {
8809
0
                CPLFree(pData);
8810
0
                return CE_Failure;
8811
0
            }
8812
8813
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8814
0
                                     pabyMaskData, nXReduced, nYReduced,
8815
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
8816
0
            {
8817
0
                CPLFree(pData);
8818
0
                CPLFree(pabyMaskData);
8819
0
                return CE_Failure;
8820
0
            }
8821
0
        }
8822
8823
0
        if (bUseOptimizedPath)
8824
0
        {
8825
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8826
0
        }
8827
0
        else
8828
0
        {
8829
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8830
0
                                 nYReduced, nXReduced, sNoDataValues,
8831
0
                                 pabyMaskData, dfMin, dfMax);
8832
0
        }
8833
8834
0
        CPLFree(pData);
8835
0
        CPLFree(pabyMaskData);
8836
0
    }
8837
8838
0
    else  // No arbitrary overviews
8839
0
    {
8840
0
        if (!InitBlockInfo())
8841
0
            return CE_Failure;
8842
8843
        /* --------------------------------------------------------------------
8844
         */
8845
        /*      Figure out the ratio of blocks we will read to get an */
8846
        /*      approximate value. */
8847
        /* --------------------------------------------------------------------
8848
         */
8849
0
        int nSampleRate = 1;
8850
8851
0
        if (bApproxOK)
8852
0
        {
8853
0
            nSampleRate = static_cast<int>(std::max(
8854
0
                1.0,
8855
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8856
            // We want to avoid probing only the first column of blocks for
8857
            // a square shaped raster, because it is not unlikely that it may
8858
            // be padding only (#6378).
8859
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8860
0
                nSampleRate += 1;
8861
0
        }
8862
8863
0
        if (bUseOptimizedPath)
8864
0
        {
8865
0
            for (GIntBig iSampleBlock = 0;
8866
0
                 iSampleBlock <
8867
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8868
0
                 iSampleBlock += nSampleRate)
8869
0
            {
8870
0
                const int iYBlock =
8871
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
8872
0
                const int iXBlock =
8873
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
8874
8875
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8876
0
                if (poBlock == nullptr)
8877
0
                    return CE_Failure;
8878
8879
0
                void *const pData = poBlock->GetDataRef();
8880
8881
0
                int nXCheck = 0, nYCheck = 0;
8882
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8883
8884
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8885
8886
0
                poBlock->DropLock();
8887
8888
0
                if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8889
0
                    nMax == 255)
8890
0
                    break;
8891
0
            }
8892
0
        }
8893
0
        else
8894
0
        {
8895
0
            const GIntBig nTotalBlocks =
8896
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8897
0
            if (!ComputeMinMaxGenericIterBlocks(
8898
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8899
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8900
0
            {
8901
0
                return CE_Failure;
8902
0
            }
8903
0
        }
8904
0
    }
8905
8906
0
    if (bUseOptimizedPath)
8907
0
    {
8908
0
        if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8909
0
        {
8910
0
            dfMin = nMin;
8911
0
            dfMax = nMax;
8912
0
        }
8913
0
        else if (eDataType == GDT_Int16)
8914
0
        {
8915
0
            dfMin = nMinInt16;
8916
0
            dfMax = nMaxInt16;
8917
0
        }
8918
0
    }
8919
8920
0
    if (dfMin > dfMax)
8921
0
    {
8922
0
        adfMinMax[0] = 0;
8923
0
        adfMinMax[1] = 0;
8924
0
        ReportError(
8925
0
            CE_Failure, CPLE_AppDefined,
8926
0
            "Failed to compute min/max, no valid pixels found in sampling.");
8927
0
        return CE_Failure;
8928
0
    }
8929
8930
0
    adfMinMax[0] = dfMin;
8931
0
    adfMinMax[1] = dfMax;
8932
8933
0
    return CE_None;
8934
0
}
8935
8936
/************************************************************************/
8937
/*                      GDALComputeRasterMinMax()                       */
8938
/************************************************************************/
8939
8940
/**
8941
 * \brief Compute the min/max values for a band.
8942
 *
8943
 * @see GDALRasterBand::ComputeRasterMinMax()
8944
 *
8945
 * @note Prior to GDAL 3.6, this function returned void
8946
 */
8947
8948
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8949
                                           double adfMinMax[2])
8950
8951
0
{
8952
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8953
8954
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8955
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8956
0
}
8957
8958
/************************************************************************/
8959
/*                    ComputeRasterMinMaxLocation()                     */
8960
/************************************************************************/
8961
8962
/**
8963
 * \brief Compute the min/max values for a band, and their location.
8964
 *
8965
 * Pixels whose value matches the nodata value or are masked by the mask
8966
 * band are ignored.
8967
 *
8968
 * If the minimum or maximum value is hit in several locations, it is not
8969
 * specified which one will be returned.
8970
 *
8971
 * @param[out] pdfMin Pointer to the minimum value.
8972
 * @param[out] pdfMax Pointer to the maximum value.
8973
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8974
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8975
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8976
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8977
 *
8978
 * @return CE_None in case of success, CE_Warning if there are no valid values,
8979
 *         CE_Failure in case of error.
8980
 *
8981
 * @since GDAL 3.11
8982
 */
8983
8984
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8985
                                                   double *pdfMax, int *pnMinX,
8986
                                                   int *pnMinY, int *pnMaxX,
8987
                                                   int *pnMaxY)
8988
0
{
8989
0
    int nMinX = -1;
8990
0
    int nMinY = -1;
8991
0
    int nMaxX = -1;
8992
0
    int nMaxY = -1;
8993
0
    double dfMin = std::numeric_limits<double>::infinity();
8994
0
    double dfMax = -std::numeric_limits<double>::infinity();
8995
0
    if (pdfMin)
8996
0
        *pdfMin = dfMin;
8997
0
    if (pdfMax)
8998
0
        *pdfMax = dfMax;
8999
0
    if (pnMinX)
9000
0
        *pnMinX = nMinX;
9001
0
    if (pnMinY)
9002
0
        *pnMinY = nMinY;
9003
0
    if (pnMaxX)
9004
0
        *pnMaxX = nMaxX;
9005
0
    if (pnMaxY)
9006
0
        *pnMaxY = nMaxY;
9007
9008
0
    if (GDALDataTypeIsComplex(eDataType))
9009
0
    {
9010
0
        CPLError(CE_Failure, CPLE_NotSupported,
9011
0
                 "Complex data type not supported");
9012
0
        return CE_Failure;
9013
0
    }
9014
9015
0
    if (!InitBlockInfo())
9016
0
        return CE_Failure;
9017
9018
0
    GDALNoDataValues sNoDataValues(this, eDataType);
9019
0
    GDALRasterBand *poMaskBand = nullptr;
9020
0
    if (!sNoDataValues.bGotNoDataValue)
9021
0
    {
9022
0
        const int l_nMaskFlags = GetMaskFlags();
9023
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
9024
0
            GetColorInterpretation() != GCI_AlphaBand)
9025
0
        {
9026
0
            poMaskBand = GetMaskBand();
9027
0
        }
9028
0
    }
9029
9030
0
    bool bSignedByte = false;
9031
0
    if (eDataType == GDT_UInt8)
9032
0
    {
9033
0
        EnablePixelTypeSignedByteWarning(false);
9034
0
        const char *pszPixelType =
9035
0
            GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
9036
0
        EnablePixelTypeSignedByteWarning(true);
9037
0
        bSignedByte =
9038
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
9039
0
    }
9040
9041
0
    GByte *pabyMaskData = nullptr;
9042
0
    if (poMaskBand)
9043
0
    {
9044
0
        pabyMaskData =
9045
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
9046
0
        if (!pabyMaskData)
9047
0
        {
9048
0
            return CE_Failure;
9049
0
        }
9050
0
    }
9051
9052
0
    const GIntBig nTotalBlocks =
9053
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
9054
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
9055
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
9056
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
9057
0
    {
9058
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
9059
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
9060
9061
0
        int nXCheck = 0, nYCheck = 0;
9062
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
9063
9064
0
        if (poMaskBand &&
9065
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
9066
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
9067
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
9068
0
                                 nBlockXSize, nullptr) != CE_None)
9069
0
        {
9070
0
            CPLFree(pabyMaskData);
9071
0
            return CE_Failure;
9072
0
        }
9073
9074
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
9075
0
        if (poBlock == nullptr)
9076
0
        {
9077
0
            CPLFree(pabyMaskData);
9078
0
            return CE_Failure;
9079
0
        }
9080
9081
0
        void *const pData = poBlock->GetDataRef();
9082
9083
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
9084
0
        {
9085
0
            for (int iY = 0; iY < nYCheck; ++iY)
9086
0
            {
9087
0
                for (int iX = 0; iX < nXCheck; ++iX)
9088
0
                {
9089
0
                    const GPtrDiff_t iOffset =
9090
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9091
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
9092
0
                        continue;
9093
0
                    bool bValid = true;
9094
0
                    double dfValue =
9095
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
9096
0
                                      sNoDataValues, bValid);
9097
0
                    if (!bValid)
9098
0
                        continue;
9099
0
                    if (dfValue < dfMin)
9100
0
                    {
9101
0
                        dfMin = dfValue;
9102
0
                        nMinX = iXBlock * nBlockXSize + iX;
9103
0
                        nMinY = iYBlock * nBlockYSize + iY;
9104
0
                    }
9105
0
                    if (dfValue > dfMax)
9106
0
                    {
9107
0
                        dfMax = dfValue;
9108
0
                        nMaxX = iXBlock * nBlockXSize + iX;
9109
0
                        nMaxY = iYBlock * nBlockYSize + iY;
9110
0
                    }
9111
0
                }
9112
0
            }
9113
0
        }
9114
0
        else
9115
0
        {
9116
0
            size_t pos_min = 0;
9117
0
            size_t pos_max = 0;
9118
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
9119
0
            if (bNeedsMin && bNeedsMax)
9120
0
            {
9121
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
9122
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9123
0
                    eEffectiveDT, CPL_TO_BOOL(sNoDataValues.bGotNoDataValue),
9124
0
                    sNoDataValues.dfNoDataValue);
9125
0
            }
9126
0
            else if (bNeedsMin)
9127
0
            {
9128
0
                pos_min = gdal::min_element(
9129
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9130
0
                    eEffectiveDT, CPL_TO_BOOL(sNoDataValues.bGotNoDataValue),
9131
0
                    sNoDataValues.dfNoDataValue);
9132
0
            }
9133
0
            else if (bNeedsMax)
9134
0
            {
9135
0
                pos_max = gdal::max_element(
9136
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9137
0
                    eEffectiveDT, CPL_TO_BOOL(sNoDataValues.bGotNoDataValue),
9138
0
                    sNoDataValues.dfNoDataValue);
9139
0
            }
9140
9141
0
            if (bNeedsMin)
9142
0
            {
9143
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
9144
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
9145
0
                bool bValid = true;
9146
0
                const double dfMinValueBlock =
9147
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9148
0
                                  sNoDataValues, bValid);
9149
0
                if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9150
0
                {
9151
0
                    dfMin = dfMinValueBlock;
9152
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
9153
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
9154
0
                }
9155
0
            }
9156
9157
0
            if (bNeedsMax)
9158
0
            {
9159
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9160
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9161
0
                bool bValid = true;
9162
0
                const double dfMaxValueBlock =
9163
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9164
0
                                  sNoDataValues, bValid);
9165
0
                if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9166
0
                {
9167
0
                    dfMax = dfMaxValueBlock;
9168
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9169
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9170
0
                }
9171
0
            }
9172
0
        }
9173
9174
0
        poBlock->DropLock();
9175
9176
0
        if (eDataType == GDT_UInt8)
9177
0
        {
9178
0
            if (bNeedsMin && dfMin == 0)
9179
0
            {
9180
0
                bNeedsMin = false;
9181
0
            }
9182
0
            if (bNeedsMax && dfMax == 255)
9183
0
            {
9184
0
                bNeedsMax = false;
9185
0
            }
9186
0
            if (!bNeedsMin && !bNeedsMax)
9187
0
            {
9188
0
                break;
9189
0
            }
9190
0
        }
9191
0
    }
9192
9193
0
    CPLFree(pabyMaskData);
9194
9195
0
    if (pdfMin)
9196
0
        *pdfMin = dfMin;
9197
0
    if (pdfMax)
9198
0
        *pdfMax = dfMax;
9199
0
    if (pnMinX)
9200
0
        *pnMinX = nMinX;
9201
0
    if (pnMinY)
9202
0
        *pnMinY = nMinY;
9203
0
    if (pnMaxX)
9204
0
        *pnMaxX = nMaxX;
9205
0
    if (pnMaxY)
9206
0
        *pnMaxY = nMaxY;
9207
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9208
0
                                                                  : CE_None;
9209
0
}
9210
9211
/************************************************************************/
9212
/*                  GDALComputeRasterMinMaxLocation()                   */
9213
/************************************************************************/
9214
9215
/**
9216
 * \brief Compute the min/max values for a band, and their location.
9217
 *
9218
 * @see GDALRasterBand::ComputeRasterMinMax()
9219
 * @since GDAL 3.11
9220
 */
9221
9222
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9223
                                       double *pdfMax, int *pnMinX, int *pnMinY,
9224
                                       int *pnMaxX, int *pnMaxY)
9225
9226
0
{
9227
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9228
9229
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9230
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9231
0
                                               pnMaxX, pnMaxY);
9232
0
}
9233
9234
/************************************************************************/
9235
/*                        SetDefaultHistogram()                         */
9236
/************************************************************************/
9237
9238
/* FIXME : add proper documentation */
9239
/**
9240
 * \brief Set default histogram.
9241
 *
9242
 * This method is the same as the C function GDALSetDefaultHistogram() and
9243
 * GDALSetDefaultHistogramEx()
9244
 */
9245
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9246
                                           double /* dfMax */,
9247
                                           int /* nBuckets */,
9248
                                           GUIntBig * /* panHistogram */)
9249
9250
0
{
9251
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9252
0
        ReportError(CE_Failure, CPLE_NotSupported,
9253
0
                    "SetDefaultHistogram() not implemented for this format.");
9254
9255
0
    return CE_Failure;
9256
0
}
9257
9258
/************************************************************************/
9259
/*                      GDALSetDefaultHistogram()                       */
9260
/************************************************************************/
9261
9262
/**
9263
 * \brief Set default histogram.
9264
 *
9265
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9266
 * 2 billion.
9267
 *
9268
 * @see GDALRasterBand::SetDefaultHistogram()
9269
 * @see GDALSetRasterHistogramEx()
9270
 */
9271
9272
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9273
                                           double dfMax, int nBuckets,
9274
                                           int *panHistogram)
9275
9276
0
{
9277
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9278
9279
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9280
9281
0
    GUIntBig *panHistogramTemp =
9282
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9283
0
    if (panHistogramTemp == nullptr)
9284
0
    {
9285
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9286
0
                            "Out of memory in GDALSetDefaultHistogram().");
9287
0
        return CE_Failure;
9288
0
    }
9289
9290
0
    for (int i = 0; i < nBuckets; ++i)
9291
0
    {
9292
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9293
0
    }
9294
9295
0
    const CPLErr eErr =
9296
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9297
9298
0
    CPLFree(panHistogramTemp);
9299
9300
0
    return eErr;
9301
0
}
9302
9303
/************************************************************************/
9304
/*                     GDALSetDefaultHistogramEx()                      */
9305
/************************************************************************/
9306
9307
/**
9308
 * \brief Set default histogram.
9309
 *
9310
 * @see GDALRasterBand::SetDefaultHistogram()
9311
 *
9312
 */
9313
9314
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9315
                                             double dfMin, double dfMax,
9316
                                             int nBuckets,
9317
                                             GUIntBig *panHistogram)
9318
9319
0
{
9320
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9321
9322
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9323
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9324
0
}
9325
9326
/************************************************************************/
9327
/*                           GetDefaultRAT()                            */
9328
/************************************************************************/
9329
9330
/**
9331
 * \brief Fetch default Raster Attribute Table.
9332
 *
9333
 * A RAT will be returned if there is a default one associated with the
9334
 * band, otherwise NULL is returned.  The returned RAT is owned by the
9335
 * band and should not be deleted by the application.
9336
 *
9337
 * This method is the same as the C function GDALGetDefaultRAT().
9338
 *
9339
 * @return NULL, or a pointer to an internal RAT owned by the band.
9340
 */
9341
9342
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9343
9344
0
{
9345
0
    return nullptr;
9346
0
}
9347
9348
/************************************************************************/
9349
/*                         GDALGetDefaultRAT()                          */
9350
/************************************************************************/
9351
9352
/**
9353
 * \brief Fetch default Raster Attribute Table.
9354
 *
9355
 * @see GDALRasterBand::GetDefaultRAT()
9356
 */
9357
9358
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9359
9360
0
{
9361
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9362
9363
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9364
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9365
0
}
9366
9367
/************************************************************************/
9368
/*                           SetDefaultRAT()                            */
9369
/************************************************************************/
9370
9371
/**
9372
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9373
 * \brief Set default Raster Attribute Table.
9374
 *
9375
 * Associates a default RAT with the band.  If not implemented for the
9376
 * format a CPLE_NotSupported error will be issued.  If successful a copy
9377
 * of the RAT is made, the original remains owned by the caller.
9378
 *
9379
 * This method is the same as the C function GDALSetDefaultRAT().
9380
 *
9381
 * @param poRAT the RAT to assign to the band.
9382
 *
9383
 * @return CE_None on success or CE_Failure if unsupported or otherwise
9384
 * failing.
9385
 */
9386
9387
/**/
9388
/**/
9389
9390
CPLErr
9391
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9392
0
{
9393
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9394
0
    {
9395
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
9396
0
        ReportError(CE_Failure, CPLE_NotSupported,
9397
0
                    "SetDefaultRAT() not implemented for this format.");
9398
0
        CPLPopErrorHandler();
9399
0
    }
9400
0
    return CE_Failure;
9401
0
}
9402
9403
/************************************************************************/
9404
/*                         GDALSetDefaultRAT()                          */
9405
/************************************************************************/
9406
9407
/**
9408
 * \brief Set default Raster Attribute Table.
9409
 *
9410
 * @see GDALRasterBand::GDALSetDefaultRAT()
9411
 */
9412
9413
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9414
                                     GDALRasterAttributeTableH hRAT)
9415
9416
0
{
9417
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9418
9419
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9420
9421
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9422
0
}
9423
9424
/************************************************************************/
9425
/*                             HasNoData()                              */
9426
/************************************************************************/
9427
9428
bool GDALRasterBand::HasNoData() const
9429
0
{
9430
0
    int bHaveNoDataRaw = FALSE;
9431
0
    bool bHaveNoData = false;
9432
0
    GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9433
0
    if (eDataType == GDT_Int64)
9434
0
    {
9435
0
        CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9436
0
        bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9437
0
    }
9438
0
    else if (eDataType == GDT_UInt64)
9439
0
    {
9440
0
        CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9441
0
        bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9442
0
    }
9443
0
    else
9444
0
    {
9445
0
        const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9446
0
        if (bHaveNoDataRaw &&
9447
0
            GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9448
0
        {
9449
0
            bHaveNoData = true;
9450
0
        }
9451
0
    }
9452
0
    return bHaveNoData;
9453
0
}
9454
9455
/************************************************************************/
9456
/*                            GetMaskBand()                             */
9457
/************************************************************************/
9458
9459
/**
9460
 * \brief Return the mask band associated with the band.
9461
 *
9462
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9463
 * that returns one of four default implementations :
9464
 * <ul>
9465
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9466
 * </li>
9467
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9468
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9469
 * GMF_NODATA | GMF_PER_DATASET.
9470
 * </li>
9471
 * <li>If the band has a nodata value set, an instance of the new
9472
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9473
 * GMF_NODATA.
9474
 * </li>
9475
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
9476
 * to apply to this band (specific rules yet to be determined) and that is of
9477
 * type GDT_UInt8 then that alpha band will be returned, and the flags
9478
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9479
 * </li>
9480
 * <li>If neither of the above apply, an instance of the new
9481
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9482
 * pixels. The null flags will return GMF_ALL_VALID.
9483
 * </li>
9484
 * </ul>
9485
 *
9486
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9487
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9488
 *
9489
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9490
 * dataset, with the same name as the main dataset and suffixed with .msk,
9491
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9492
 * main dataset.
9493
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9494
 * level, where xx matches the band number of a band of the main dataset. The
9495
 * value of those items is a combination of the flags GMF_ALL_VALID,
9496
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9497
 * a band, then the other rules explained above will be used to generate a
9498
 * on-the-fly mask band.
9499
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9500
 *
9501
 * This method is the same as the C function GDALGetMaskBand().
9502
 *
9503
 * @return a valid mask band.
9504
 *
9505
 *
9506
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9507
 *
9508
 */
9509
GDALRasterBand *GDALRasterBand::GetMaskBand()
9510
9511
0
{
9512
0
    if (poMask != nullptr)
9513
0
    {
9514
0
        if (poMask.IsOwned())
9515
0
        {
9516
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9517
0
            {
9518
0
                if (HasNoData())
9519
0
                {
9520
0
                    InvalidateMaskBand();
9521
0
                }
9522
0
            }
9523
0
            else if (auto poNoDataMaskBand =
9524
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9525
0
            {
9526
0
                int bHaveNoDataRaw = FALSE;
9527
0
                bool bIsSame = false;
9528
0
                if (eDataType == GDT_Int64)
9529
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9530
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9531
0
                              bHaveNoDataRaw;
9532
0
                else if (eDataType == GDT_UInt64)
9533
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9534
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9535
0
                              bHaveNoDataRaw;
9536
0
                else
9537
0
                {
9538
0
                    const double dfNoDataValue =
9539
0
                        GetNoDataValue(&bHaveNoDataRaw);
9540
0
                    if (bHaveNoDataRaw)
9541
0
                    {
9542
0
                        bIsSame =
9543
0
                            std::isnan(dfNoDataValue)
9544
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9545
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
9546
0
                                      dfNoDataValue;
9547
0
                    }
9548
0
                }
9549
0
                if (!bIsSame)
9550
0
                    InvalidateMaskBand();
9551
0
            }
9552
0
        }
9553
9554
0
        if (poMask)
9555
0
            return poMask.get();
9556
0
    }
9557
9558
    /* -------------------------------------------------------------------- */
9559
    /*      Check for a mask in a .msk file.                                */
9560
    /* -------------------------------------------------------------------- */
9561
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9562
0
    {
9563
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9564
0
        if (poMask != nullptr)
9565
0
        {
9566
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9567
0
            return poMask.get();
9568
0
        }
9569
0
    }
9570
9571
    /* -------------------------------------------------------------------- */
9572
    /*      Check for NODATA_VALUES metadata.                               */
9573
    /* -------------------------------------------------------------------- */
9574
0
    if (poDS != nullptr)
9575
0
    {
9576
0
        const char *pszGDALNoDataValues =
9577
0
            poDS->GetMetadataItem("NODATA_VALUES");
9578
0
        if (pszGDALNoDataValues != nullptr)
9579
0
        {
9580
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9581
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
9582
9583
            // Make sure we have as many values as bands.
9584
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9585
0
                poDS->GetRasterCount() != 0)
9586
0
            {
9587
                // Make sure that all bands have the same data type
9588
                // This is clearly not a fundamental condition, just a
9589
                // condition to make implementation easier.
9590
0
                GDALDataType eDT = GDT_Unknown;
9591
0
                int i = 0;  // Used after for.
9592
0
                for (; i < poDS->GetRasterCount(); ++i)
9593
0
                {
9594
0
                    if (i == 0)
9595
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9596
0
                    else if (eDT !=
9597
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
9598
0
                    {
9599
0
                        break;
9600
0
                    }
9601
0
                }
9602
0
                if (i == poDS->GetRasterCount())
9603
0
                {
9604
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9605
0
                    try
9606
0
                    {
9607
0
                        poMask.reset(
9608
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9609
0
                    }
9610
0
                    catch (const std::bad_alloc &)
9611
0
                    {
9612
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9613
0
                        poMask.reset();
9614
0
                    }
9615
0
                    CSLDestroy(papszGDALNoDataValues);
9616
0
                    return poMask.get();
9617
0
                }
9618
0
                else
9619
0
                {
9620
0
                    ReportError(CE_Warning, CPLE_AppDefined,
9621
0
                                "All bands should have the same type in "
9622
0
                                "order the NODATA_VALUES metadata item "
9623
0
                                "to be used as a mask.");
9624
0
                }
9625
0
            }
9626
0
            else
9627
0
            {
9628
0
                ReportError(
9629
0
                    CE_Warning, CPLE_AppDefined,
9630
0
                    "NODATA_VALUES metadata item doesn't have the same number "
9631
0
                    "of values as the number of bands.  "
9632
0
                    "Ignoring it for mask.");
9633
0
            }
9634
9635
0
            CSLDestroy(papszGDALNoDataValues);
9636
0
        }
9637
0
    }
9638
9639
    /* -------------------------------------------------------------------- */
9640
    /*      Check for nodata case.                                          */
9641
    /* -------------------------------------------------------------------- */
9642
0
    if (HasNoData())
9643
0
    {
9644
0
        nMaskFlags = GMF_NODATA;
9645
0
        try
9646
0
        {
9647
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9648
0
        }
9649
0
        catch (const std::bad_alloc &)
9650
0
        {
9651
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9652
0
            poMask.reset();
9653
0
        }
9654
0
        return poMask.get();
9655
0
    }
9656
9657
    /* -------------------------------------------------------------------- */
9658
    /*      Check for alpha case.                                           */
9659
    /* -------------------------------------------------------------------- */
9660
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9661
0
        this == poDS->GetRasterBand(1) &&
9662
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9663
0
    {
9664
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9665
0
        {
9666
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9667
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
9668
0
            return poMask.get();
9669
0
        }
9670
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9671
0
        {
9672
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9673
0
            try
9674
0
            {
9675
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9676
0
                    poDS->GetRasterBand(2)));
9677
0
            }
9678
0
            catch (const std::bad_alloc &)
9679
0
            {
9680
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9681
0
                poMask.reset();
9682
0
            }
9683
0
            return poMask.get();
9684
0
        }
9685
0
    }
9686
9687
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9688
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9689
0
         this == poDS->GetRasterBand(3)) &&
9690
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9691
0
    {
9692
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9693
0
        {
9694
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9695
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
9696
0
            return poMask.get();
9697
0
        }
9698
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9699
0
        {
9700
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9701
0
            try
9702
0
            {
9703
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9704
0
                    poDS->GetRasterBand(4)));
9705
0
            }
9706
0
            catch (const std::bad_alloc &)
9707
0
            {
9708
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9709
0
                poMask.reset();
9710
0
            }
9711
0
            return poMask.get();
9712
0
        }
9713
0
    }
9714
9715
    /* -------------------------------------------------------------------- */
9716
    /*      Fallback to all valid case.                                     */
9717
    /* -------------------------------------------------------------------- */
9718
0
    nMaskFlags = GMF_ALL_VALID;
9719
0
    try
9720
0
    {
9721
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9722
0
    }
9723
0
    catch (const std::bad_alloc &)
9724
0
    {
9725
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9726
0
        poMask.reset();
9727
0
    }
9728
9729
0
    return poMask.get();
9730
0
}
9731
9732
/************************************************************************/
9733
/*                          GDALGetMaskBand()                           */
9734
/************************************************************************/
9735
9736
/**
9737
 * \brief Return the mask band associated with the band.
9738
 *
9739
 * @see GDALRasterBand::GetMaskBand()
9740
 */
9741
9742
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9743
9744
0
{
9745
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9746
9747
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9748
0
    return poBand->GetMaskBand();
9749
0
}
9750
9751
/************************************************************************/
9752
/*                            GetMaskFlags()                            */
9753
/************************************************************************/
9754
9755
/**
9756
 * \brief Return the status flags of the mask band associated with the band.
9757
 *
9758
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9759
 * the following available definitions that may be extended in the future:
9760
 * <ul>
9761
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9762
 * 255. When used this will normally be the only flag set.
9763
 * </li>
9764
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9765
 * dataset.
9766
 * </li>
9767
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9768
 * and may have values other than 0 and 255.
9769
 * </li>
9770
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9771
 * nodata values. (mutually exclusive of GMF_ALPHA)
9772
 * </li>
9773
 * </ul>
9774
 *
9775
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9776
 * that returns one of four default implementations:
9777
 * <ul>
9778
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9779
 * </li>
9780
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9781
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9782
 * GMF_NODATA | GMF_PER_DATASET.
9783
 * </li>
9784
 * <li>If the band has a nodata value set, an instance of the new
9785
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9786
 * GMF_NODATA.
9787
 * </li>
9788
 * <li>If there is no nodata value, but the dataset has an alpha band that
9789
 * seems to apply to this band (specific rules yet to be determined) and that is
9790
 * of type GDT_UInt8 then that alpha band will be returned, and the flags
9791
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9792
 * </li>
9793
 * <li>If neither of the above apply, an instance of the new
9794
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9795
 * pixels. The null flags will return GMF_ALL_VALID.
9796
 * </li>
9797
 * </ul>
9798
 *
9799
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9800
 * dataset, with the same name as the main dataset and suffixed with .msk,
9801
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9802
 * main dataset.
9803
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9804
 * level, where xx matches the band number of a band of the main dataset. The
9805
 * value of those items is a combination of the flags GMF_ALL_VALID,
9806
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9807
 * a band, then the other rules explained above will be used to generate a
9808
 * on-the-fly mask band.
9809
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9810
 *
9811
 * This method is the same as the C function GDALGetMaskFlags().
9812
 *
9813
 *
9814
 * @return a valid mask band.
9815
 *
9816
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9817
 *
9818
 */
9819
int GDALRasterBand::GetMaskFlags()
9820
9821
0
{
9822
    // If we don't have a band yet, force this now so that the masks value
9823
    // will be initialized.
9824
9825
0
    if (poMask == nullptr)
9826
0
        GetMaskBand();
9827
9828
0
    return nMaskFlags;
9829
0
}
9830
9831
/************************************************************************/
9832
/*                          GDALGetMaskFlags()                          */
9833
/************************************************************************/
9834
9835
/**
9836
 * \brief Return the status flags of the mask band associated with the band.
9837
 *
9838
 * @see GDALRasterBand::GetMaskFlags()
9839
 */
9840
9841
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9842
9843
0
{
9844
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9845
9846
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9847
0
    return poBand->GetMaskFlags();
9848
0
}
9849
9850
/************************************************************************/
9851
/*                         InvalidateMaskBand()                         */
9852
/************************************************************************/
9853
9854
//! @cond Doxygen_Suppress
9855
void GDALRasterBand::InvalidateMaskBand()
9856
0
{
9857
0
    poMask.reset();
9858
0
    nMaskFlags = 0;
9859
0
}
9860
9861
//! @endcond
9862
9863
/************************************************************************/
9864
/*                           CreateMaskBand()                           */
9865
/************************************************************************/
9866
9867
/**
9868
 * \brief Adds a mask band to the current band
9869
 *
9870
 * The default implementation of the CreateMaskBand() method is implemented
9871
 * based on similar rules to the .ovr handling implemented using the
9872
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9873
 * be created with the same basename as the original file, and it will have
9874
 * as many bands as the original image (or just one for GMF_PER_DATASET).
9875
 * The mask images will be deflate compressed tiled images with the same
9876
 * block size as the original image if possible.
9877
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9878
 * level, where xx matches the band number of a band of the main dataset. The
9879
 * value of those items will be the one of the nFlagsIn parameter.
9880
 *
9881
 * Note that if you got a mask band with a previous call to GetMaskBand(),
9882
 * it might be invalidated by CreateMaskBand(). So you have to call
9883
 * GetMaskBand() again.
9884
 *
9885
 * This method is the same as the C function GDALCreateMaskBand().
9886
 *
9887
 *
9888
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9889
 *
9890
 * @return CE_None on success or CE_Failure on an error.
9891
 *
9892
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9893
 * @see GDALDataset::CreateMaskBand()
9894
 *
9895
 */
9896
9897
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9898
9899
0
{
9900
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9901
0
    {
9902
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9903
0
        if (eErr != CE_None)
9904
0
            return eErr;
9905
9906
0
        InvalidateMaskBand();
9907
9908
0
        return CE_None;
9909
0
    }
9910
9911
0
    ReportError(CE_Failure, CPLE_NotSupported,
9912
0
                "CreateMaskBand() not supported for this band.");
9913
9914
0
    return CE_Failure;
9915
0
}
9916
9917
/************************************************************************/
9918
/*                         GDALCreateMaskBand()                         */
9919
/************************************************************************/
9920
9921
/**
9922
 * \brief Adds a mask band to the current band
9923
 *
9924
 * @see GDALRasterBand::CreateMaskBand()
9925
 */
9926
9927
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9928
9929
0
{
9930
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9931
9932
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9933
0
    return poBand->CreateMaskBand(nFlags);
9934
0
}
9935
9936
/************************************************************************/
9937
/*                             IsMaskBand()                             */
9938
/************************************************************************/
9939
9940
/**
9941
 * \brief Returns whether a band is a mask band.
9942
 *
9943
 * Mask band must be understood in the broad term: it can be a per-dataset
9944
 * mask band, an alpha band, or an implicit mask band.
9945
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9946
 *
9947
 * This method is the same as the C function GDALIsMaskBand().
9948
 *
9949
 * @return true if the band is a mask band.
9950
 *
9951
 * @see GDALDataset::CreateMaskBand()
9952
 *
9953
 * @since GDAL 3.5.0
9954
 *
9955
 */
9956
9957
bool GDALRasterBand::IsMaskBand() const
9958
0
{
9959
    // The GeoTIFF driver, among others, override this method to
9960
    // also handle external .msk bands.
9961
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9962
0
           GCI_AlphaBand;
9963
0
}
9964
9965
/************************************************************************/
9966
/*                           GDALIsMaskBand()                           */
9967
/************************************************************************/
9968
9969
/**
9970
 * \brief Returns whether a band is a mask band.
9971
 *
9972
 * Mask band must be understood in the broad term: it can be a per-dataset
9973
 * mask band, an alpha band, or an implicit mask band.
9974
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9975
 *
9976
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9977
 *
9978
 * @return true if the band is a mask band.
9979
 *
9980
 * @see GDALRasterBand::IsMaskBand()
9981
 *
9982
 * @since GDAL 3.5.0
9983
 *
9984
 */
9985
9986
bool GDALIsMaskBand(GDALRasterBandH hBand)
9987
9988
0
{
9989
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9990
9991
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9992
0
    return poBand->IsMaskBand();
9993
0
}
9994
9995
/************************************************************************/
9996
/*                         GetMaskValueRange()                          */
9997
/************************************************************************/
9998
9999
/**
10000
 * \brief Returns the range of values that a mask band can take.
10001
 *
10002
 * @return the range of values that a mask band can take.
10003
 *
10004
 * @since GDAL 3.5.0
10005
 *
10006
 */
10007
10008
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
10009
0
{
10010
0
    return GMVR_UNKNOWN;
10011
0
}
10012
10013
/************************************************************************/
10014
/*                     HasConflictingMaskSources()                      */
10015
/************************************************************************/
10016
10017
/**
10018
 * \brief Returns whether a raster band has conflicting mask sources.
10019
 *
10020
 * That is, if more than one of the following conditions is met:
10021
 * - it has a binary mask band (that is not an alpha band)
10022
 * - it has an external mask flags (.msk file)
10023
 * - it has a nodata value
10024
 * - it belongs to a dataset with the NODATA_VALUES metadata item set
10025
 * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
10026
 *
10027
 * @param[out] posDetailMessage Pointer to a string that will contain the
10028
 *                              details of the conflict.
10029
 * @param bMentionPrioritarySource Whether the mask source used should be
10030
 *                                 mentioned in *posDetailMessage.
10031
 * @since GDAL 3.13.0
10032
 */
10033
10034
bool GDALRasterBand::HasConflictingMaskSources(
10035
    std::string *posDetailMessage, bool bMentionPrioritarySource) const
10036
0
{
10037
0
    const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
10038
0
    const bool bHasBinaryMaskBand =
10039
0
        ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
10040
0
          (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
10041
0
        (!bHasExternalMask ||
10042
0
         (poDS && poDS->oOvManager.GetMaskBand(nBand) != this));
10043
0
    const bool bHasNoData = HasNoData();
10044
0
    const bool bHasNODATA_VALUES =
10045
0
        poDS && poDS->GetMetadataItem("NODATA_VALUES");
10046
0
    const bool bHasAlphaBand =
10047
0
        poDS &&
10048
0
        poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
10049
0
            GCI_AlphaBand;
10050
0
    const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
10051
0
                                  bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
10052
0
    const size_t nCount =
10053
0
        std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
10054
0
    if (nCount >= 2)
10055
0
    {
10056
0
        if (posDetailMessage)
10057
0
        {
10058
0
            *posDetailMessage = "Raster band ";
10059
0
            *posDetailMessage += std::to_string(nBand);
10060
0
            if (poDS && poDS->GetDescription()[0])
10061
0
            {
10062
0
                *posDetailMessage += " of dataset ";
10063
0
                *posDetailMessage += poDS->GetDescription();
10064
0
            }
10065
0
            *posDetailMessage += " has several conflicting mask sources:\n";
10066
0
            if (bHasBinaryMaskBand)
10067
0
                *posDetailMessage += "- internal binary mask band\n";
10068
0
            if (bHasExternalMask)
10069
0
                *posDetailMessage += "- external mask band (.msk)\n";
10070
0
            if (bHasNoData)
10071
0
                *posDetailMessage += "- nodata value\n";
10072
0
            if (bHasNODATA_VALUES)
10073
0
                *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
10074
0
            if (bHasAlphaBand)
10075
0
                *posDetailMessage +=
10076
0
                    "- related to a raster band that is an alpha band\n";
10077
0
            if (bMentionPrioritarySource)
10078
0
                *posDetailMessage +=
10079
0
                    "Only the first listed one will be taken into account.";
10080
0
        }
10081
0
        return true;
10082
0
    }
10083
0
    return false;
10084
0
}
10085
10086
/************************************************************************/
10087
/*                     GetIndexColorTranslationTo()                     */
10088
/************************************************************************/
10089
10090
/**
10091
 * \brief Compute translation table for color tables.
10092
 *
10093
 * When the raster band has a palette index, it may be useful to compute
10094
 * the "translation" of this palette to the palette of another band.
10095
 * The translation tries to do exact matching first, and then approximate
10096
 * matching if no exact matching is possible.
10097
 * This method returns a table such that table[i] = j where i is an index
10098
 * of the 'this' rasterband and j the corresponding index for the reference
10099
 * rasterband.
10100
 *
10101
 * This method is thought as internal to GDAL and is used for drivers
10102
 * like RPFTOC.
10103
 *
10104
 * The implementation only supports 1-byte palette rasterbands.
10105
 *
10106
 * @param poReferenceBand the raster band
10107
 * @param pTranslationTable an already allocated translation table (at least 256
10108
 * bytes), or NULL to let the method allocate it
10109
 * @param pApproximateMatching a pointer to a flag that is set if the matching
10110
 *                              is approximate. May be NULL.
10111
 *
10112
 * @return a translation table if the two bands are palette index and that they
10113
 * do not match or NULL in other cases. The table must be freed with CPLFree if
10114
 * NULL was passed for pTranslationTable.
10115
 */
10116
10117
unsigned char *
10118
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
10119
                                           unsigned char *pTranslationTable,
10120
                                           int *pApproximateMatching)
10121
0
{
10122
0
    if (poReferenceBand == nullptr)
10123
0
        return nullptr;
10124
10125
    // cppcheck-suppress knownConditionTrueFalse
10126
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
10127
        // cppcheck-suppress knownConditionTrueFalse
10128
0
        GetColorInterpretation() == GCI_PaletteIndex &&
10129
0
        poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
10130
0
        GetRasterDataType() == GDT_UInt8)
10131
0
    {
10132
0
        const GDALColorTable *srcColorTable = GetColorTable();
10133
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
10134
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
10135
0
        {
10136
0
            const int nEntries = srcColorTable->GetColorEntryCount();
10137
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
10138
10139
0
            int bHasNoDataValueSrc = FALSE;
10140
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
10141
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
10142
0
                  dfNoDataValueSrc <= 255 &&
10143
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
10144
0
                bHasNoDataValueSrc = FALSE;
10145
0
            const int noDataValueSrc =
10146
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10147
10148
0
            int bHasNoDataValueRef = FALSE;
10149
0
            const double dfNoDataValueRef =
10150
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10151
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10152
0
                  dfNoDataValueRef <= 255 &&
10153
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10154
0
                bHasNoDataValueRef = FALSE;
10155
0
            const int noDataValueRef =
10156
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10157
10158
0
            bool samePalette = false;
10159
10160
0
            if (pApproximateMatching)
10161
0
                *pApproximateMatching = FALSE;
10162
10163
0
            if (nEntries == nRefEntries &&
10164
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
10165
0
                (bHasNoDataValueSrc == FALSE ||
10166
0
                 noDataValueSrc == noDataValueRef))
10167
0
            {
10168
0
                samePalette = true;
10169
0
                for (int i = 0; i < nEntries; ++i)
10170
0
                {
10171
0
                    if (noDataValueSrc == i)
10172
0
                        continue;
10173
0
                    const GDALColorEntry *entry =
10174
0
                        srcColorTable->GetColorEntry(i);
10175
0
                    const GDALColorEntry *entryRef =
10176
0
                        destColorTable->GetColorEntry(i);
10177
0
                    if (entry->c1 != entryRef->c1 ||
10178
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10179
0
                    {
10180
0
                        samePalette = false;
10181
0
                    }
10182
0
                }
10183
0
            }
10184
10185
0
            if (!samePalette)
10186
0
            {
10187
0
                if (pTranslationTable == nullptr)
10188
0
                {
10189
0
                    pTranslationTable = static_cast<unsigned char *>(
10190
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10191
0
                    if (pTranslationTable == nullptr)
10192
0
                        return nullptr;
10193
0
                }
10194
10195
                // Trying to remap the product palette on the subdataset
10196
                // palette.
10197
0
                for (int i = 0; i < nEntries; ++i)
10198
0
                {
10199
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10200
0
                        noDataValueSrc == i)
10201
0
                        continue;
10202
0
                    const GDALColorEntry *entry =
10203
0
                        srcColorTable->GetColorEntry(i);
10204
0
                    bool bMatchFound = false;
10205
0
                    for (int j = 0; j < nRefEntries; ++j)
10206
0
                    {
10207
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
10208
0
                            continue;
10209
0
                        const GDALColorEntry *entryRef =
10210
0
                            destColorTable->GetColorEntry(j);
10211
0
                        if (entry->c1 == entryRef->c1 &&
10212
0
                            entry->c2 == entryRef->c2 &&
10213
0
                            entry->c3 == entryRef->c3)
10214
0
                        {
10215
0
                            pTranslationTable[i] =
10216
0
                                static_cast<unsigned char>(j);
10217
0
                            bMatchFound = true;
10218
0
                            break;
10219
0
                        }
10220
0
                    }
10221
0
                    if (!bMatchFound)
10222
0
                    {
10223
                        // No exact match. Looking for closest color now.
10224
0
                        int best_j = 0;
10225
0
                        int best_distance = 0;
10226
0
                        if (pApproximateMatching)
10227
0
                            *pApproximateMatching = TRUE;
10228
0
                        for (int j = 0; j < nRefEntries; ++j)
10229
0
                        {
10230
0
                            const GDALColorEntry *entryRef =
10231
0
                                destColorTable->GetColorEntry(j);
10232
0
                            int distance = (entry->c1 - entryRef->c1) *
10233
0
                                               (entry->c1 - entryRef->c1) +
10234
0
                                           (entry->c2 - entryRef->c2) *
10235
0
                                               (entry->c2 - entryRef->c2) +
10236
0
                                           (entry->c3 - entryRef->c3) *
10237
0
                                               (entry->c3 - entryRef->c3);
10238
0
                            if (j == 0 || distance < best_distance)
10239
0
                            {
10240
0
                                best_j = j;
10241
0
                                best_distance = distance;
10242
0
                            }
10243
0
                        }
10244
0
                        pTranslationTable[i] =
10245
0
                            static_cast<unsigned char>(best_j);
10246
0
                    }
10247
0
                }
10248
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
10249
0
                    pTranslationTable[noDataValueSrc] =
10250
0
                        static_cast<unsigned char>(noDataValueRef);
10251
10252
0
                return pTranslationTable;
10253
0
            }
10254
0
        }
10255
0
    }
10256
0
    return nullptr;
10257
0
}
10258
10259
/************************************************************************/
10260
/*                          SetFlushBlockErr()                          */
10261
/************************************************************************/
10262
10263
/**
10264
 * \brief Store that an error occurred while writing a dirty block.
10265
 *
10266
 * This function stores the fact that an error occurred while writing a dirty
10267
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10268
 * flushed when the block cache get full, it is not convenient/possible to
10269
 * report that a dirty block could not be written correctly. This function
10270
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10271
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10272
 * places where the user can easily match the error with the relevant dataset.
10273
 */
10274
10275
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10276
0
{
10277
0
    eFlushBlockErr = eErr;
10278
0
}
10279
10280
/************************************************************************/
10281
/*                           IncDirtyBlocks()                           */
10282
/************************************************************************/
10283
10284
/**
10285
 * \brief Increment/decrement the number of dirty blocks
10286
 */
10287
10288
void GDALRasterBand::IncDirtyBlocks(int nInc)
10289
0
{
10290
0
    if (poBandBlockCache)
10291
0
        poBandBlockCache->IncDirtyBlocks(nInc);
10292
0
}
10293
10294
/************************************************************************/
10295
/*                            ReportError()                             */
10296
/************************************************************************/
10297
10298
#ifndef DOXYGEN_XML
10299
/**
10300
 * \brief Emits an error related to a raster band.
10301
 *
10302
 * This function is a wrapper for regular CPLError(). The only difference
10303
 * with CPLError() is that it prepends the error message with the dataset
10304
 * name and the band number.
10305
 *
10306
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10307
 * @param err_no the error number (CPLE_*) from cpl_error.h.
10308
 * @param fmt a printf() style format string.  Any additional arguments
10309
 * will be treated as arguments to fill in this format in a manner
10310
 * similar to printf().
10311
 *
10312
 */
10313
10314
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10315
                                 const char *fmt, ...) const
10316
0
{
10317
0
    va_list args;
10318
10319
0
    va_start(args, fmt);
10320
10321
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
10322
0
    pszDSName = CPLGetFilename(pszDSName);
10323
0
    if (pszDSName[0] != '\0')
10324
0
    {
10325
0
        CPLError(eErrClass, err_no, "%s",
10326
0
                 CPLString()
10327
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
10328
0
                     .append(CPLString().vPrintf(fmt, args))
10329
0
                     .c_str());
10330
0
    }
10331
0
    else
10332
0
    {
10333
0
        CPLErrorV(eErrClass, err_no, fmt, args);
10334
0
    }
10335
10336
0
    va_end(args);
10337
0
}
10338
#endif
10339
10340
/************************************************************************/
10341
/*                         GetVirtualMemAuto()                          */
10342
/************************************************************************/
10343
10344
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10345
 *
10346
 * Only supported on Linux and Unix systems with mmap() for now.
10347
 *
10348
 * This method allows creating a virtual memory object for a GDALRasterBand,
10349
 * that exposes the whole image data as a virtual array.
10350
 *
10351
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10352
 * specialized implementation, such as for raw files, may also directly use
10353
 * mechanisms of the operating system to create a view of the underlying file
10354
 * into virtual memory ( CPLVirtualMemFileMapNew() )
10355
 *
10356
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10357
 * offer a specialized implementation with direct file mapping, provided that
10358
 * some requirements are met :
10359
 *   - for all drivers, the dataset must be backed by a "real" file in the file
10360
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10361
 *     must match the native ordering of the CPU.
10362
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10363
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10364
 * the file in sequential order, and be equally spaced (which is generally the
10365
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10366
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10367
 *
10368
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
10369
 * CPLVirtualMemFree() must be called before the raster band object is
10370
 * destroyed.
10371
 *
10372
 * If p is such a pointer and base_type the type matching
10373
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10374
 * accessed with
10375
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10376
 *
10377
 * This method is the same as the C GDALGetVirtualMemAuto() function.
10378
 *
10379
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10380
 * read/write the band.
10381
 *
10382
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
10383
 * one pixel value in the buffer to the start of the next pixel value within a
10384
 * scanline.
10385
 *
10386
 * @param pnLineSpace Output parameter giving the byte offset from the start of
10387
 * one scanline in the buffer to the start of the next.
10388
 *
10389
 * @param papszOptions NULL terminated list of options.
10390
 *                     If a specialized implementation exists, defining
10391
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10392
 * used. On the contrary, defining
10393
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10394
 * being used (thus only allowing efficient implementations to be used). When
10395
 * requiring or falling back to the default implementation, the following
10396
 *                     options are available : CACHE_SIZE (in bytes, defaults to
10397
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10398
 * to FALSE)
10399
 *
10400
 * @return a virtual memory object that must be unreferenced by
10401
 * CPLVirtualMemFree(), or NULL in case of failure.
10402
 *
10403
 */
10404
10405
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10406
                                                 int *pnPixelSpace,
10407
                                                 GIntBig *pnLineSpace,
10408
                                                 CSLConstList papszOptions)
10409
0
{
10410
0
    const char *pszImpl = CSLFetchNameValueDef(
10411
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10412
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10413
0
        EQUAL(pszImpl, "FALSE"))
10414
0
    {
10415
0
        return nullptr;
10416
0
    }
10417
10418
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10419
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10420
0
    if (pnPixelSpace)
10421
0
        *pnPixelSpace = nPixelSpace;
10422
0
    if (pnLineSpace)
10423
0
        *pnLineSpace = nLineSpace;
10424
0
    const size_t nCacheSize =
10425
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10426
0
    const size_t nPageSizeHint =
10427
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10428
0
    const bool bSingleThreadUsage = CPLTestBool(
10429
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10430
0
    return GDALRasterBandGetVirtualMem(
10431
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10432
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10433
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10434
0
        papszOptions);
10435
0
}
10436
10437
/************************************************************************/
10438
/*                       GDALGetVirtualMemAuto()                        */
10439
/************************************************************************/
10440
10441
/**
10442
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10443
 *
10444
 * @see GDALRasterBand::GetVirtualMemAuto()
10445
 */
10446
10447
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10448
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
10449
                                     CSLConstList papszOptions)
10450
0
{
10451
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10452
10453
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10454
10455
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10456
0
                                     const_cast<char **>(papszOptions));
10457
0
}
10458
10459
/************************************************************************/
10460
/*                     GDALGetDataCoverageStatus()                      */
10461
/************************************************************************/
10462
10463
/**
10464
 * \brief Get the coverage status of a sub-window of the raster.
10465
 *
10466
 * Returns whether a sub-window of the raster contains only data, only empty
10467
 * blocks or a mix of both. This function can be used to determine quickly
10468
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10469
 * be sparse.
10470
 *
10471
 * Empty blocks are blocks that are generally not physically present in the
10472
 * file, and when read through GDAL, contain only pixels whose value is the
10473
 * nodata value when it is set, or whose value is 0 when the nodata value is
10474
 * not set.
10475
 *
10476
 * The query is done in an efficient way without reading the actual pixel
10477
 * values. If not possible, or not implemented at all by the driver,
10478
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10479
 * be returned.
10480
 *
10481
 * The values that can be returned by the function are the following,
10482
 * potentially combined with the binary or operator :
10483
 * <ul>
10484
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10485
 * GetDataCoverageStatus(). This flag should be returned together with
10486
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10487
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10488
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10489
 * the queried window. This is typically identified by the concept of missing
10490
 * block in formats that supports it.
10491
 * </li>
10492
 * </ul>
10493
 *
10494
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10495
 * should be interpreted more as hint of potential presence of data. For example
10496
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10497
 * nodata value), instead of using the missing block mechanism,
10498
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10499
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10500
 *
10501
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10502
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10503
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10504
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10505
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10506
 * the function will exit, so that you can potentially refine the requested area
10507
 * to find which particular region(s) have missing blocks.
10508
 *
10509
 * @see GDALRasterBand::GetDataCoverageStatus()
10510
 *
10511
 * @param hBand raster band
10512
 *
10513
 * @param nXOff The pixel offset to the top left corner of the region
10514
 * of the band to be queried. This would be zero to start from the left side.
10515
 *
10516
 * @param nYOff The line offset to the top left corner of the region
10517
 * of the band to be queried. This would be zero to start from the top.
10518
 *
10519
 * @param nXSize The width of the region of the band to be queried in pixels.
10520
 *
10521
 * @param nYSize The height of the region of the band to be queried in lines.
10522
 *
10523
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10524
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10525
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10526
 * as the computation of the coverage matches the mask, the computation will be
10527
 * stopped. *pdfDataPct will not be valid in that case.
10528
 *
10529
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10530
 * to the (approximate) percentage in [0,100] of pixels in the queried
10531
 * sub-window that have valid values. The implementation might not always be
10532
 * able to compute it, in which case it will be set to a negative value.
10533
 *
10534
 * @return a binary-or'ed combination of possible values
10535
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10536
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10537
 */
10538
10539
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10540
                                          int nYOff, int nXSize, int nYSize,
10541
                                          int nMaskFlagStop, double *pdfDataPct)
10542
0
{
10543
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10544
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10545
10546
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10547
10548
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10549
0
                                         nMaskFlagStop, pdfDataPct);
10550
0
}
10551
10552
/************************************************************************/
10553
/*                       GetDataCoverageStatus()                        */
10554
/************************************************************************/
10555
10556
/**
10557
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10558
 *                                           int nYOff,
10559
 *                                           int nXSize,
10560
 *                                           int nYSize,
10561
 *                                           int nMaskFlagStop,
10562
 *                                           double* pdfDataPct)
10563
 * \brief Get the coverage status of a sub-window of the raster.
10564
 *
10565
 * Returns whether a sub-window of the raster contains only data, only empty
10566
 * blocks or a mix of both. This function can be used to determine quickly
10567
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10568
 * be sparse.
10569
 *
10570
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10571
 * value when it is set, or whose value is 0 when the nodata value is not set.
10572
 *
10573
 * The query is done in an efficient way without reading the actual pixel
10574
 * values. If not possible, or not implemented at all by the driver,
10575
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10576
 * be returned.
10577
 *
10578
 * The values that can be returned by the function are the following,
10579
 * potentially combined with the binary or operator :
10580
 * <ul>
10581
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10582
 * GetDataCoverageStatus(). This flag should be returned together with
10583
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10584
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10585
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10586
 * the queried window. This is typically identified by the concept of missing
10587
 * block in formats that supports it.
10588
 * </li>
10589
 * </ul>
10590
 *
10591
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10592
 * should be interpreted more as hint of potential presence of data. For example
10593
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10594
 * nodata value), instead of using the missing block mechanism,
10595
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10596
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10597
 *
10598
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10599
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10600
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10601
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10602
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10603
 * the function will exit, so that you can potentially refine the requested area
10604
 * to find which particular region(s) have missing blocks.
10605
 *
10606
 * @see GDALGetDataCoverageStatus()
10607
 *
10608
 * @param nXOff The pixel offset to the top left corner of the region
10609
 * of the band to be queried. This would be zero to start from the left side.
10610
 *
10611
 * @param nYOff The line offset to the top left corner of the region
10612
 * of the band to be queried. This would be zero to start from the top.
10613
 *
10614
 * @param nXSize The width of the region of the band to be queried in pixels.
10615
 *
10616
 * @param nYSize The height of the region of the band to be queried in lines.
10617
 *
10618
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10619
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10620
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10621
 * as the computation of the coverage matches the mask, the computation will be
10622
 * stopped. *pdfDataPct will not be valid in that case.
10623
 *
10624
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10625
 * to the (approximate) percentage in [0,100] of pixels in the queried
10626
 * sub-window that have valid values. The implementation might not always be
10627
 * able to compute it, in which case it will be set to a negative value.
10628
 *
10629
 * @return a binary-or'ed combination of possible values
10630
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10631
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10632
 */
10633
10634
/**
10635
 * \brief Get the coverage status of a sub-window of the raster.
10636
 *
10637
 * Returns whether a sub-window of the raster contains only data, only empty
10638
 * blocks or a mix of both. This function can be used to determine quickly
10639
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10640
 * be sparse.
10641
 *
10642
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10643
 * value when it is set, or whose value is 0 when the nodata value is not set.
10644
 *
10645
 * The query is done in an efficient way without reading the actual pixel
10646
 * values. If not possible, or not implemented at all by the driver,
10647
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10648
 * be returned.
10649
 *
10650
 * The values that can be returned by the function are the following,
10651
 * potentially combined with the binary or operator :
10652
 * <ul>
10653
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10654
 * GetDataCoverageStatus(). This flag should be returned together with
10655
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10656
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10657
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10658
 * the queried window. This is typically identified by the concept of missing
10659
 * block in formats that supports it.
10660
 * </li>
10661
 * </ul>
10662
 *
10663
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10664
 * should be interpreted more as hint of potential presence of data. For example
10665
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10666
 * nodata value), instead of using the missing block mechanism,
10667
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10668
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10669
 *
10670
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10671
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10672
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10673
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10674
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10675
 * the function will exit, so that you can potentially refine the requested area
10676
 * to find which particular region(s) have missing blocks.
10677
 *
10678
 * @see GDALGetDataCoverageStatus()
10679
 *
10680
 * @param nXOff The pixel offset to the top left corner of the region
10681
 * of the band to be queried. This would be zero to start from the left side.
10682
 *
10683
 * @param nYOff The line offset to the top left corner of the region
10684
 * of the band to be queried. This would be zero to start from the top.
10685
 *
10686
 * @param nXSize The width of the region of the band to be queried in pixels.
10687
 *
10688
 * @param nYSize The height of the region of the band to be queried in lines.
10689
 *
10690
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10691
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10692
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10693
 * as the computation of the coverage matches the mask, the computation will be
10694
 * stopped. *pdfDataPct will not be valid in that case.
10695
 *
10696
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10697
 * to the (approximate) percentage in [0,100] of pixels in the queried
10698
 * sub-window that have valid values. The implementation might not always be
10699
 * able to compute it, in which case it will be set to a negative value.
10700
 *
10701
 * @return a binary-or'ed combination of possible values
10702
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10703
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10704
 */
10705
10706
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10707
                                          int nYSize, int nMaskFlagStop,
10708
                                          double *pdfDataPct)
10709
0
{
10710
0
    if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10711
0
        nYSize > nRasterYSize - nYOff)
10712
0
    {
10713
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10714
0
        if (pdfDataPct)
10715
0
            *pdfDataPct = 0.0;
10716
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10717
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
10718
0
    }
10719
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10720
0
                                  pdfDataPct);
10721
0
}
10722
10723
/************************************************************************/
10724
/*                       IGetDataCoverageStatus()                       */
10725
/************************************************************************/
10726
10727
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10728
                                           int /*nXSize*/, int /*nYSize*/,
10729
                                           int /*nMaskFlagStop*/,
10730
                                           double *pdfDataPct)
10731
0
{
10732
0
    if (pdfDataPct != nullptr)
10733
0
        *pdfDataPct = 100.0;
10734
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10735
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
10736
0
}
10737
10738
//! @cond Doxygen_Suppress
10739
/************************************************************************/
10740
/*                           EnterReadWrite()                           */
10741
/************************************************************************/
10742
10743
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10744
0
{
10745
0
    if (poDS != nullptr)
10746
0
        return poDS->EnterReadWrite(eRWFlag);
10747
0
    return FALSE;
10748
0
}
10749
10750
/************************************************************************/
10751
/*                           LeaveReadWrite()                           */
10752
/************************************************************************/
10753
10754
void GDALRasterBand::LeaveReadWrite()
10755
0
{
10756
0
    if (poDS != nullptr)
10757
0
        poDS->LeaveReadWrite();
10758
0
}
10759
10760
/************************************************************************/
10761
/*                             InitRWLock()                             */
10762
/************************************************************************/
10763
10764
void GDALRasterBand::InitRWLock()
10765
0
{
10766
0
    if (poDS != nullptr)
10767
0
        poDS->InitRWLock();
10768
0
}
10769
10770
//! @endcond
10771
10772
// clang-format off
10773
10774
/**
10775
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10776
 * \brief Set metadata.
10777
 *
10778
 * CAUTION: depending on the format, older values of the updated information
10779
 * might still be found in the file in a "ghost" state, even if no longer
10780
 * accessible through the GDAL API. This is for example the case of the GTiff
10781
 * format (this is not a exhaustive list)
10782
 *
10783
 * The C function GDALSetMetadata() does the same thing as this method.
10784
 *
10785
 * @param papszMetadata the metadata in name=value string list format to
10786
 * apply.
10787
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
10788
 * domain.
10789
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10790
 * metadata has been accepted, but is likely not maintained persistently
10791
 * by the underlying object between sessions.
10792
 */
10793
10794
/**
10795
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10796
 * \brief Set single metadata item.
10797
 *
10798
 * CAUTION: depending on the format, older values of the updated information
10799
 * might still be found in the file in a "ghost" state, even if no longer
10800
 * accessible through the GDAL API. This is for example the case of the GTiff
10801
 * format (this is not a exhaustive list)
10802
 *
10803
 * The C function GDALSetMetadataItem() does the same thing as this method.
10804
 *
10805
 * @param pszName the key for the metadata item to fetch.
10806
 * @param pszValue the value to assign to the key.
10807
 * @param pszDomain the domain to set within, use NULL for the default domain.
10808
 *
10809
 * @return CE_None on success, or an error code on failure.
10810
 */
10811
10812
// clang-format on
10813
10814
//! @cond Doxygen_Suppress
10815
/************************************************************************/
10816
/*                  EnablePixelTypeSignedByteWarning()                  */
10817
/************************************************************************/
10818
10819
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10820
0
{
10821
0
    m_bEnablePixelTypeSignedByteWarning = b;
10822
0
}
10823
10824
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10825
0
{
10826
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10827
0
}
10828
10829
//! @endcond
10830
10831
/************************************************************************/
10832
/*                          GetMetadataItem()                           */
10833
/************************************************************************/
10834
10835
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10836
                                            const char *pszDomain)
10837
0
{
10838
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10839
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10840
0
        pszDomain != nullptr && EQUAL(pszDomain, GDAL_MDD_IMAGE_STRUCTURE) &&
10841
0
        EQUAL(pszName, "PIXELTYPE"))
10842
0
    {
10843
0
        CPLError(CE_Warning, CPLE_AppDefined,
10844
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10845
0
                 "used to signal signed 8-bit raster. Change your code to "
10846
0
                 "test for the new GDT_Int8 data type instead.");
10847
0
    }
10848
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10849
0
}
10850
10851
/************************************************************************/
10852
/*                      GDALRasterBandAsMDArray()                       */
10853
/************************************************************************/
10854
10855
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10856
 *
10857
 * The band must be linked to a GDALDataset. If this dataset is not already
10858
 * marked as shared, it will be, so that the returned array holds a reference
10859
 * to it.
10860
 *
10861
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10862
 * returned array will have an associated indexing variable.
10863
 *
10864
 * The returned pointer must be released with GDALMDArrayRelease().
10865
 *
10866
 * This is the same as the C++ method GDALRasterBand::AsMDArray().
10867
 *
10868
 * @return a new array, or NULL.
10869
 *
10870
 * @since GDAL 3.1
10871
 */
10872
GDALMDArrayH GDALRasterBandAsMDArray(GDALRasterBandH hBand)
10873
0
{
10874
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10875
0
    auto poArray(GDALRasterBand::FromHandle(hBand)->AsMDArray());
10876
0
    if (!poArray)
10877
0
        return nullptr;
10878
0
    return new GDALMDArrayHS(poArray);
10879
0
}
10880
10881
/************************************************************************/
10882
/*                            WindowIterator                            */
10883
/************************************************************************/
10884
10885
//! @cond Doxygen_Suppress
10886
10887
GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10888
                                               int nRasterYSize,
10889
                                               int nBlockXSize, int nBlockYSize,
10890
                                               int nRow, int nCol)
10891
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10892
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10893
0
      m_col(nCol)
10894
0
{
10895
0
}
10896
10897
bool GDALRasterBand::WindowIterator::operator==(
10898
    const WindowIterator &other) const
10899
0
{
10900
0
    return m_row == other.m_row && m_col == other.m_col &&
10901
0
           m_nRasterXSize == other.m_nRasterXSize &&
10902
0
           m_nRasterYSize == other.m_nRasterYSize &&
10903
0
           m_nBlockXSize == other.m_nBlockXSize &&
10904
0
           m_nBlockYSize == other.m_nBlockYSize;
10905
0
}
10906
10907
bool GDALRasterBand::WindowIterator::operator!=(
10908
    const WindowIterator &other) const
10909
0
{
10910
0
    return !(*this == other);
10911
0
}
10912
10913
GDALRasterBand::WindowIterator::value_type
10914
GDALRasterBand::WindowIterator::operator*() const
10915
0
{
10916
0
    GDALRasterWindow ret;
10917
0
    ret.nXOff = m_col * m_nBlockXSize;
10918
0
    ret.nYOff = m_row * m_nBlockYSize;
10919
0
    ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10920
0
    ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10921
10922
0
    return ret;
10923
0
}
10924
10925
GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10926
0
{
10927
0
    m_col++;
10928
0
    if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10929
0
    {
10930
0
        m_col = 0;
10931
0
        m_row++;
10932
0
    }
10933
0
    return *this;
10934
0
}
10935
10936
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10937
    const GDALRasterBand &band, size_t maxSize)
10938
0
    : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10939
0
                            band.nBlockYSize, maxSize)
10940
0
{
10941
0
}
10942
10943
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10944
    const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10945
0
    : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10946
0
                            std::min(band1.GetYSize(), band2.GetYSize()),
10947
0
                            std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10948
0
                            std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10949
0
                            maxSize)
10950
0
{
10951
0
    if (band1.GetXSize() != band2.GetXSize() ||
10952
0
        band1.GetYSize() != band2.GetYSize())
10953
0
    {
10954
0
        CPLError(CE_Warning, CPLE_AppDefined,
10955
0
                 "WindowIteratorWrapper called on bands of different "
10956
0
                 "dimensions. Selecting smallest one");
10957
0
    }
10958
0
}
10959
10960
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10961
                                                             int nRasterYSize,
10962
                                                             int nBlockXSize,
10963
                                                             int nBlockYSize,
10964
                                                             size_t maxSize)
10965
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10966
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10967
0
{
10968
#ifdef CSA_BUILD
10969
    assert(this);
10970
#endif
10971
0
    int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10972
0
    int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10973
10974
0
    if (nXSize < 1 || nYSize < 1)
10975
0
    {
10976
        // If invalid block size is reported, assume scanlines
10977
0
        nXSize = m_nRasterXSize;
10978
0
        nYSize = 1;
10979
0
    }
10980
10981
0
    if (maxSize == 0)
10982
0
    {
10983
0
        m_nBlockXSize = nXSize;
10984
0
        m_nBlockYSize = nYSize;
10985
0
        return;
10986
0
    }
10987
10988
0
    const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10989
0
    const double dfBlocksPerChunk =
10990
0
        static_cast<double>(maxSize) /
10991
0
        (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10992
10993
0
    if (dfBlocksPerChunk < dfBlocksPerRow)
10994
0
    {
10995
0
        m_nBlockXSize = static_cast<int>(std::min<double>(
10996
0
            m_nRasterXSize,
10997
0
            nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10998
0
        m_nBlockYSize = nYSize;
10999
0
    }
11000
0
    else
11001
0
    {
11002
0
        m_nBlockXSize = m_nRasterXSize;
11003
0
        m_nBlockYSize = static_cast<int>(std::min<double>(
11004
0
            m_nRasterYSize,
11005
0
            nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
11006
0
    }
11007
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
11008
    {
11009
        if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
11010
        {
11011
            m_nBlockXSize = m_nRasterXSize;
11012
            m_nBlockYSize = 1;
11013
        }
11014
    }
11015
0
}
11016
11017
GDALRasterBand::WindowIterator
11018
GDALRasterBand::WindowIteratorWrapper::begin() const
11019
0
{
11020
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
11021
0
                          m_nBlockYSize, 0, 0);
11022
0
}
11023
11024
GDALRasterBand::WindowIterator
11025
GDALRasterBand::WindowIteratorWrapper::end() const
11026
0
{
11027
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
11028
0
                          m_nBlockYSize,
11029
0
                          DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
11030
0
}
11031
11032
uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
11033
0
{
11034
0
    return static_cast<uint64_t>(
11035
0
               cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
11036
0
           static_cast<uint64_t>(
11037
0
               cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
11038
0
}
11039
11040
//! @endcond
11041
11042
/** Return an object whose begin() and end() methods can be used to iterate
11043
 *  over GDALRasterWindow objects that are aligned with blocks in this raster
11044
 *  band. The iteration order is from left to right, then from top to bottom.
11045
 *
11046
\code{.cpp}
11047
    std::vector<double> pixelValues;
11048
    for (const auto& window : poBand->IterateWindows()) {
11049
        CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
11050
                                         window.nXSize, window.nYSize);
11051
        // check eErr
11052
    }
11053
\endcode
11054
 *
11055
 *
11056
 *  @param maxSize The maximum number of pixels in each window. If set to
11057
 *         zero (the default), or a number smaller than the block size,
11058
 *         the window size will be the same as the block size.
11059
 *  @since GDAL 3.12
11060
 */
11061
GDALRasterBand::WindowIteratorWrapper
11062
GDALRasterBand::IterateWindows(size_t maxSize) const
11063
0
{
11064
0
    return WindowIteratorWrapper(*this, maxSize);
11065
0
}
11066
11067
/************************************************************************/
11068
/*                MayMultiBlockReadingBeMultiThreaded()                 */
11069
/************************************************************************/
11070
11071
/** Return whether a RasterIO(GF_Read) request spanning over multiple
11072
 * blocks may be accelerated internally using multi-threading.
11073
 *
11074
 * This can be used to determine the best chunk size to read a raster band.
11075
 *
11076
 * Note that such optimizations may require that the window is perfectly aligned
11077
 * on block boundaries and does not involve resampling or data type translation
11078
 * occurs, etc.
11079
 *
11080
 * @since GDAL 3.13
11081
 */
11082
bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
11083
0
{
11084
0
    return false;
11085
0
}
11086
11087
/************************************************************************/
11088
/*                      GDALMDArrayFromRasterBand                       */
11089
/************************************************************************/
11090
11091
class GDALMDArrayFromRasterBand final : public GDALMDArray
11092
{
11093
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
11094
11095
    GDALDataset *m_poDS;
11096
    GDALRasterBand *m_poBand;
11097
    GDALExtendedDataType m_dt;
11098
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11099
    std::string m_osUnit;
11100
    std::vector<GByte> m_pabyNoData{};
11101
    std::shared_ptr<GDALMDArray> m_varX{};
11102
    std::shared_ptr<GDALMDArray> m_varY{};
11103
    std::string m_osFilename{};
11104
    mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11105
11106
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11107
                   const size_t *count, const GInt64 *arrayStep,
11108
                   const GPtrDiff_t *bufferStride,
11109
                   const GDALExtendedDataType &bufferDataType,
11110
                   void *pBuffer) const;
11111
11112
  protected:
11113
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
11114
0
        : GDALAbstractMDArray(std::string(),
11115
0
                              std::string(poDS->GetDescription()) +
11116
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
11117
0
          GDALMDArray(std::string(),
11118
0
                      std::string(poDS->GetDescription()) +
11119
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
11120
0
          m_poDS(poDS), m_poBand(poBand),
11121
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
11122
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
11123
0
    {
11124
0
        m_poDS->Reference();
11125
11126
0
        int bHasNoData = false;
11127
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
11128
0
        {
11129
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
11130
0
            if (bHasNoData)
11131
0
            {
11132
0
                m_pabyNoData.resize(m_dt.GetSize());
11133
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
11134
0
                                m_dt.GetNumericDataType(), 0, 1);
11135
0
            }
11136
0
        }
11137
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
11138
0
        {
11139
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
11140
0
            if (bHasNoData)
11141
0
            {
11142
0
                m_pabyNoData.resize(m_dt.GetSize());
11143
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
11144
0
                                m_dt.GetNumericDataType(), 0, 1);
11145
0
            }
11146
0
        }
11147
0
        else
11148
0
        {
11149
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
11150
0
            if (bHasNoData)
11151
0
            {
11152
0
                m_pabyNoData.resize(m_dt.GetSize());
11153
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
11154
0
                                m_dt.GetNumericDataType(), 0, 1);
11155
0
            }
11156
0
        }
11157
11158
0
        const int nXSize = poBand->GetXSize();
11159
0
        const int nYSize = poBand->GetYSize();
11160
11161
0
        auto poSRS = m_poDS->GetSpatialRef();
11162
0
        std::string osTypeY;
11163
0
        std::string osTypeX;
11164
0
        std::string osDirectionY;
11165
0
        std::string osDirectionX;
11166
0
        if (poSRS && poSRS->GetAxesCount() == 2)
11167
0
        {
11168
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11169
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
11170
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
11171
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
11172
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
11173
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11174
0
            {
11175
0
                if (mapping == std::vector<int>{1, 2})
11176
0
                {
11177
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11178
0
                    osDirectionY = "NORTH";
11179
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11180
0
                    osDirectionX = "EAST";
11181
0
                }
11182
0
            }
11183
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11184
0
            {
11185
0
                if (mapping == std::vector<int>{2, 1})
11186
0
                {
11187
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11188
0
                    osDirectionY = "NORTH";
11189
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11190
0
                    osDirectionX = "EAST";
11191
0
                }
11192
0
            }
11193
0
        }
11194
11195
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11196
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
11197
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
11198
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
11199
11200
0
        GDALGeoTransform gt;
11201
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
11202
0
        {
11203
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
11204
0
                "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
11205
0
            m_dims[1]->SetIndexingVariable(m_varX);
11206
11207
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
11208
0
                "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
11209
0
            m_dims[0]->SetIndexingVariable(m_varY);
11210
0
        }
11211
0
    }
11212
11213
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11214
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11215
               const GDALExtendedDataType &bufferDataType,
11216
               void *pDstBuffer) const override;
11217
11218
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11219
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11220
                const GDALExtendedDataType &bufferDataType,
11221
                const void *pSrcBuffer) override
11222
0
    {
11223
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11224
0
                         bufferStride, bufferDataType,
11225
0
                         const_cast<void *>(pSrcBuffer));
11226
0
    }
11227
11228
  public:
11229
    ~GDALMDArrayFromRasterBand() override
11230
0
    {
11231
0
        m_poDS->ReleaseRef();
11232
0
    }
11233
11234
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11235
                                               GDALRasterBand *poBand)
11236
0
    {
11237
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11238
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
11239
0
        array->SetSelf(array);
11240
0
        return array;
11241
0
    }
11242
11243
    bool IsWritable() const override
11244
0
    {
11245
0
        return m_poDS->GetAccess() == GA_Update;
11246
0
    }
11247
11248
    const std::string &GetFilename() const override
11249
0
    {
11250
0
        return m_osFilename;
11251
0
    }
11252
11253
    const std::vector<std::shared_ptr<GDALDimension>> &
11254
    GetDimensions() const override
11255
0
    {
11256
0
        return m_dims;
11257
0
    }
11258
11259
    const GDALExtendedDataType &GetDataType() const override
11260
0
    {
11261
0
        return m_dt;
11262
0
    }
11263
11264
    const std::string &GetUnit() const override
11265
0
    {
11266
0
        return m_osUnit;
11267
0
    }
11268
11269
    const void *GetRawNoDataValue() const override
11270
0
    {
11271
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11272
0
    }
11273
11274
    double GetOffset(bool *pbHasOffset,
11275
                     GDALDataType *peStorageType) const override
11276
0
    {
11277
0
        int bHasOffset = false;
11278
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
11279
0
        if (pbHasOffset)
11280
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11281
0
        if (peStorageType)
11282
0
            *peStorageType = GDT_Unknown;
11283
0
        return dfRes;
11284
0
    }
11285
11286
    double GetScale(bool *pbHasScale,
11287
                    GDALDataType *peStorageType) const override
11288
0
    {
11289
0
        int bHasScale = false;
11290
0
        double dfRes = m_poBand->GetScale(&bHasScale);
11291
0
        if (pbHasScale)
11292
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
11293
0
        if (peStorageType)
11294
0
            *peStorageType = GDT_Unknown;
11295
0
        return dfRes;
11296
0
    }
11297
11298
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11299
0
    {
11300
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
11301
0
        if (!poSrcSRS)
11302
0
            return nullptr;
11303
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11304
11305
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11306
0
        constexpr int iYDim = 0;
11307
0
        constexpr int iXDim = 1;
11308
0
        for (auto &m : axisMapping)
11309
0
        {
11310
0
            if (m == 1)
11311
0
                m = iXDim + 1;
11312
0
            else if (m == 2)
11313
0
                m = iYDim + 1;
11314
0
            else
11315
0
                m = 0;
11316
0
        }
11317
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11318
0
        return poSRS;
11319
0
    }
11320
11321
    std::vector<GUInt64> GetBlockSize() const override
11322
0
    {
11323
0
        int nBlockXSize = 0;
11324
0
        int nBlockYSize = 0;
11325
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11326
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11327
0
                                    static_cast<GUInt64>(nBlockXSize)};
11328
0
    }
11329
11330
    std::vector<std::shared_ptr<GDALAttribute>>
11331
    GetAttributes(CSLConstList) const override
11332
0
    {
11333
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
11334
0
        auto papszMD = m_poBand->GetMetadata();
11335
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
11336
0
        {
11337
0
            char *pszKey = nullptr;
11338
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11339
0
            if (pszKey && pszValue)
11340
0
            {
11341
0
                res.emplace_back(
11342
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11343
0
            }
11344
0
            CPLFree(pszKey);
11345
0
        }
11346
0
        return res;
11347
0
    }
11348
11349
    int GetOverviewCount() const override
11350
0
    {
11351
0
        return m_poBand->GetOverviewCount();
11352
0
    }
11353
11354
    std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11355
0
    {
11356
0
        const int nOverviews = GetOverviewCount();
11357
0
        if (idx < 0 || idx >= nOverviews)
11358
0
            return nullptr;
11359
0
        m_apoOverviews.resize(nOverviews);
11360
0
        if (!m_apoOverviews[idx])
11361
0
        {
11362
0
            if (auto poOvrBand = m_poBand->GetOverview(idx))
11363
0
            {
11364
0
                if (auto poOvrDS = poOvrBand->GetDataset())
11365
0
                {
11366
0
                    m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11367
0
                }
11368
0
            }
11369
0
        }
11370
0
        return m_apoOverviews[idx];
11371
0
    }
11372
};
11373
11374
bool GDALMDArrayFromRasterBand::IRead(
11375
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11376
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11377
    void *pDstBuffer) const
11378
0
{
11379
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11380
0
                     bufferDataType, pDstBuffer);
11381
0
}
11382
11383
/************************************************************************/
11384
/*                             ReadWrite()                              */
11385
/************************************************************************/
11386
11387
bool GDALMDArrayFromRasterBand::ReadWrite(
11388
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11389
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11390
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11391
0
{
11392
0
    constexpr size_t iDimX = 1;
11393
0
    constexpr size_t iDimY = 0;
11394
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11395
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
11396
0
                                  bufferDataType, pBuffer);
11397
0
}
11398
11399
/************************************************************************/
11400
/*                       GDALMDRasterIOFromBand()                       */
11401
/************************************************************************/
11402
11403
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11404
                            size_t iDimX, size_t iDimY,
11405
                            const GUInt64 *arrayStartIdx, const size_t *count,
11406
                            const GInt64 *arrayStep,
11407
                            const GPtrDiff_t *bufferStride,
11408
                            const GDALExtendedDataType &bufferDataType,
11409
                            void *pBuffer)
11410
0
{
11411
0
    const auto eDT(bufferDataType.GetNumericDataType());
11412
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11413
0
    const int nX =
11414
0
        arrayStep[iDimX] > 0
11415
0
            ? static_cast<int>(arrayStartIdx[iDimX])
11416
0
            : static_cast<int>(arrayStartIdx[iDimX] -
11417
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
11418
0
    const int nY =
11419
0
        arrayStep[iDimY] > 0
11420
0
            ? static_cast<int>(arrayStartIdx[iDimY])
11421
0
            : static_cast<int>(arrayStartIdx[iDimY] -
11422
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
11423
0
    const int nSizeX =
11424
0
        static_cast<int>(count[iDimX] * std::abs(arrayStep[iDimX]));
11425
0
    const int nSizeY =
11426
0
        static_cast<int>(count[iDimY] * std::abs(arrayStep[iDimY]));
11427
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11428
0
    int nStrideXSign = 1;
11429
0
    if (arrayStep[iDimX] < 0)
11430
0
    {
11431
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11432
0
        nStrideXSign = -1;
11433
0
    }
11434
0
    int nStrideYSign = 1;
11435
0
    if (arrayStep[iDimY] < 0)
11436
0
    {
11437
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11438
0
        nStrideYSign = -1;
11439
0
    }
11440
11441
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11442
0
                            static_cast<int>(count[iDimX]),
11443
0
                            static_cast<int>(count[iDimY]), eDT,
11444
0
                            static_cast<GSpacing>(
11445
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
11446
0
                            static_cast<GSpacing>(
11447
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
11448
0
                            nullptr) == CE_None;
11449
0
}
11450
11451
/************************************************************************/
11452
/*                             AsMDArray()                              */
11453
/************************************************************************/
11454
11455
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11456
 *
11457
 * The band must be linked to a GDALDataset. If this dataset is not already
11458
 * marked as shared, it will be, so that the returned array holds a reference
11459
 * to it.
11460
 *
11461
 * If the dataset has a geotransform attached, the X and Y dimensions of the
11462
 * returned array will have an associated indexing variable.
11463
 *
11464
 * This is the same as the C function GDALRasterBandAsMDArray().
11465
 *
11466
 * The "reverse" method is GDALMDArray::AsClassicDataset().
11467
 *
11468
 * @return a new array, or nullptr.
11469
 *
11470
 * @since GDAL 3.1
11471
 */
11472
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11473
0
{
11474
0
    if (!poDS)
11475
0
    {
11476
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11477
0
        return nullptr;
11478
0
    }
11479
0
    if (!poDS->GetShared())
11480
0
    {
11481
0
        poDS->MarkAsShared();
11482
0
    }
11483
0
    return GDALMDArrayFromRasterBand::Create(
11484
0
        poDS, const_cast<GDALRasterBand *>(this));
11485
0
}
11486
11487
/************************************************************************/
11488
/*                         InterpolateAtPoint()                         */
11489
/************************************************************************/
11490
11491
/**
11492
 * \brief Interpolates the value between pixels using a resampling algorithm,
11493
 * taking pixel/line coordinates as input.
11494
 *
11495
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11496
 * @param dfLine line coordinate as a double, where interpolation should be done.
11497
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11498
 * @param pdfRealValue pointer to real part of interpolated value
11499
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11500
 *
11501
 * @return CE_None on success, or an error code on failure.
11502
 * @since GDAL 3.10
11503
 */
11504
11505
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11506
                                          GDALRIOResampleAlg eInterpolation,
11507
                                          double *pdfRealValue,
11508
                                          double *pdfImagValue) const
11509
0
{
11510
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
11511
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11512
0
        eInterpolation != GRIORA_CubicSpline)
11513
0
    {
11514
0
        CPLError(CE_Failure, CPLE_AppDefined,
11515
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
11516
0
                 "methods "
11517
0
                 "allowed");
11518
11519
0
        return CE_Failure;
11520
0
    }
11521
11522
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11523
0
    if (!m_poPointsCache)
11524
0
        m_poPointsCache = new GDALDoublePointsCache();
11525
11526
0
    const bool res =
11527
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11528
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
11529
11530
0
    return res ? CE_None : CE_Failure;
11531
0
}
11532
11533
/************************************************************************/
11534
/*                    GDALRasterInterpolateAtPoint()                    */
11535
/************************************************************************/
11536
11537
/**
11538
 * \brief Interpolates the value between pixels using
11539
 * a resampling algorithm
11540
 *
11541
 * @see GDALRasterBand::InterpolateAtPoint()
11542
 * @since GDAL 3.10
11543
 */
11544
11545
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11546
                                    double dfLine,
11547
                                    GDALRIOResampleAlg eInterpolation,
11548
                                    double *pdfRealValue, double *pdfImagValue)
11549
0
{
11550
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11551
11552
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11553
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11554
0
                                      pdfRealValue, pdfImagValue);
11555
0
}
11556
11557
/************************************************************************/
11558
/*                      InterpolateAtGeolocation()                      */
11559
/************************************************************************/
11560
11561
/**
11562
 * \brief Interpolates the value between pixels using a resampling algorithm,
11563
 * taking georeferenced coordinates as input.
11564
 *
11565
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11566
 * must be in the "natural" SRS of the dataset, that is the one returned by
11567
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11568
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11569
 * array (generally WGS 84) if there is a geolocation array.
11570
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11571
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11572
 * be a easting, and dfGeolocY a northing.
11573
 *
11574
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11575
 * expressed in that CRS, and that tuple must be conformant with the
11576
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11577
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11578
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11579
 * before calling this method, and in that case, dfGeolocX must be a longitude
11580
 * or an easting value, and dfGeolocX a latitude or a northing value.
11581
 *
11582
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11583
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11584
 * it for details on how that transformation is done.
11585
 *
11586
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11587
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11588
 * where interpolation should be done.
11589
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11590
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11591
 * where interpolation should be done.
11592
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11593
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11594
 * @param pdfRealValue pointer to real part of interpolated value
11595
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11596
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11597
 *
11598
 * @return CE_None on success, or an error code on failure.
11599
 * @since GDAL 3.11
11600
 */
11601
11602
CPLErr GDALRasterBand::InterpolateAtGeolocation(
11603
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11604
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11605
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
11606
0
{
11607
0
    double dfPixel;
11608
0
    double dfLine;
11609
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11610
0
                                     &dfLine,
11611
0
                                     papszTransformerOptions) != CE_None)
11612
0
    {
11613
0
        return CE_Failure;
11614
0
    }
11615
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11616
0
                              pdfImagValue);
11617
0
}
11618
11619
/************************************************************************/
11620
/*                 GDALRasterInterpolateAtGeolocation()                 */
11621
/************************************************************************/
11622
11623
/**
11624
 * \brief Interpolates the value between pixels using a resampling algorithm,
11625
 * taking georeferenced coordinates as input.
11626
 *
11627
 * @see GDALRasterBand::InterpolateAtGeolocation()
11628
 * @since GDAL 3.11
11629
 */
11630
11631
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11632
                                          double dfGeolocX, double dfGeolocY,
11633
                                          OGRSpatialReferenceH hSRS,
11634
                                          GDALRIOResampleAlg eInterpolation,
11635
                                          double *pdfRealValue,
11636
                                          double *pdfImagValue,
11637
                                          CSLConstList papszTransformerOptions)
11638
0
{
11639
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11640
11641
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11642
0
    return poBand->InterpolateAtGeolocation(
11643
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11644
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11645
0
}
11646
11647
/************************************************************************/
11648
/*                   GDALRasterBand::SplitRasterIO()                    */
11649
/************************************************************************/
11650
11651
//! @cond Doxygen_Suppress
11652
11653
/** Implements IRasterIO() by dividing the request in 2.
11654
 *
11655
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11656
 *
11657
 * Return CE_Warning if the split could not be done, CE_None in case of
11658
 * success and CE_Failure in case of error.
11659
 *
11660
 * @since 3.12
11661
 */
11662
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11663
                                     [[maybe_unused]] int nXSize,
11664
                                     [[maybe_unused]] int nYSize, void *pData,
11665
                                     int nBufXSize, int nBufYSize,
11666
                                     GDALDataType eBufType,
11667
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
11668
                                     GDALRasterIOExtraArg *psExtraArg)
11669
0
{
11670
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11671
11672
0
    GByte *pabyData = static_cast<GByte *>(pData);
11673
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11674
0
    {
11675
0
        GDALRasterIOExtraArg sArg;
11676
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11677
0
        const int nHalfHeight = nBufYSize / 2;
11678
11679
0
        sArg.pfnProgress = GDALScaledProgress;
11680
0
        sArg.pProgressData = GDALCreateScaledProgress(
11681
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11682
0
        if (sArg.pProgressData == nullptr)
11683
0
            sArg.pfnProgress = nullptr;
11684
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11685
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
11686
0
                                nPixelSpace, nLineSpace, &sArg);
11687
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11688
11689
0
        if (eErr == CE_None)
11690
0
        {
11691
0
            sArg.pfnProgress = GDALScaledProgress;
11692
0
            sArg.pProgressData = GDALCreateScaledProgress(
11693
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11694
0
            if (sArg.pProgressData == nullptr)
11695
0
                sArg.pfnProgress = nullptr;
11696
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11697
0
                             nBufYSize - nHalfHeight,
11698
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
11699
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11700
0
                             nLineSpace, &sArg);
11701
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11702
0
        }
11703
0
        return eErr;
11704
0
    }
11705
0
    else if (nBufXSize >= 2)
11706
0
    {
11707
0
        GDALRasterIOExtraArg sArg;
11708
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11709
0
        const int nHalfWidth = nBufXSize / 2;
11710
11711
0
        sArg.pfnProgress = GDALScaledProgress;
11712
0
        sArg.pProgressData = GDALCreateScaledProgress(
11713
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11714
0
        if (sArg.pProgressData == nullptr)
11715
0
            sArg.pfnProgress = nullptr;
11716
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11717
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
11718
0
                                nPixelSpace, nLineSpace, &sArg);
11719
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11720
11721
0
        if (eErr == CE_None)
11722
0
        {
11723
0
            sArg.pfnProgress = GDALScaledProgress;
11724
0
            sArg.pProgressData = GDALCreateScaledProgress(
11725
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11726
0
            if (sArg.pProgressData == nullptr)
11727
0
                sArg.pfnProgress = nullptr;
11728
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11729
0
                             nBufXSize - nHalfWidth, nBufYSize,
11730
0
                             pabyData + nHalfWidth * nPixelSpace,
11731
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
11732
0
                             nPixelSpace, nLineSpace, &sArg);
11733
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11734
0
        }
11735
0
        return eErr;
11736
0
    }
11737
11738
0
    return CE_Warning;
11739
0
}
11740
11741
//! @endcond
11742
11743
/************************************************************************/
11744
/*                      ThrowIfNotSameDimensions()                      */
11745
/************************************************************************/
11746
11747
//! @cond Doxygen_Suppress
11748
/* static */
11749
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11750
                                              const GDALRasterBand &second)
11751
0
{
11752
0
    if (first.GetXSize() != second.GetXSize() ||
11753
0
        first.GetYSize() != second.GetYSize())
11754
0
    {
11755
0
        throw std::runtime_error("Bands do not have the same dimensions");
11756
0
    }
11757
0
}
11758
11759
//! @endcond
11760
11761
/************************************************************************/
11762
/*                       GDALRasterBandUnaryOp()                        */
11763
/************************************************************************/
11764
11765
/** Apply a unary operation on this band.
11766
 *
11767
 * The resulting band is lazy evaluated. A reference is taken on the input
11768
 * dataset.
11769
 *
11770
 * @since 3.12
11771
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11772
 */
11773
GDALComputedRasterBandH
11774
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11775
                      GDALRasterAlgebraUnaryOperation eOp)
11776
0
{
11777
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11778
0
    GDALComputedRasterBand::Operation cppOp{};
11779
0
    switch (eOp)
11780
0
    {
11781
0
        case GRAUO_LOGICAL_NOT:
11782
0
            return new GDALComputedRasterBand(
11783
0
                GDALComputedRasterBand::Operation::OP_NE,
11784
0
                *(GDALRasterBand::FromHandle(hBand)), true);
11785
0
        case GRAUO_ABS:
11786
0
            cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11787
0
            break;
11788
0
        case GRAUO_SQRT:
11789
0
            cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11790
0
            break;
11791
0
        case GRAUO_LOG:
11792
0
#ifndef HAVE_MUPARSER
11793
0
            CPLError(
11794
0
                CE_Failure, CPLE_NotSupported,
11795
0
                "log(band) not available on a GDAL build without muparser");
11796
0
            return nullptr;
11797
#else
11798
            cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11799
            break;
11800
#endif
11801
0
        case GRAUO_LOG10:
11802
0
            cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11803
0
            break;
11804
0
    }
11805
0
    return new GDALComputedRasterBand(cppOp,
11806
0
                                      *(GDALRasterBand::FromHandle(hBand)));
11807
0
}
11808
11809
/************************************************************************/
11810
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
11811
/************************************************************************/
11812
11813
static GDALComputedRasterBand::Operation
11814
ConvertGDALRasterAlgebraBinaryOperationToCpp(
11815
    GDALRasterAlgebraBinaryOperation eOp)
11816
0
{
11817
0
    switch (eOp)
11818
0
    {
11819
0
        case GRABO_ADD:
11820
0
            return GDALComputedRasterBand::Operation::OP_ADD;
11821
0
        case GRABO_SUB:
11822
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11823
0
        case GRABO_MUL:
11824
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11825
0
        case GRABO_DIV:
11826
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
11827
0
        case GRABO_GT:
11828
0
            return GDALComputedRasterBand::Operation::OP_GT;
11829
0
        case GRABO_GE:
11830
0
            return GDALComputedRasterBand::Operation::OP_GE;
11831
0
        case GRABO_LT:
11832
0
            return GDALComputedRasterBand::Operation::OP_LT;
11833
0
        case GRABO_LE:
11834
0
            return GDALComputedRasterBand::Operation::OP_LE;
11835
0
        case GRABO_EQ:
11836
0
            return GDALComputedRasterBand::Operation::OP_EQ;
11837
0
        case GRABO_NE:
11838
0
            break;
11839
0
        case GRABO_LOGICAL_AND:
11840
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11841
0
        case GRABO_LOGICAL_OR:
11842
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11843
0
        case GRABO_POW:
11844
0
            return GDALComputedRasterBand::Operation::OP_POW;
11845
0
    }
11846
0
    return GDALComputedRasterBand::Operation::OP_NE;
11847
0
}
11848
11849
/************************************************************************/
11850
/*                     GDALRasterBandBinaryOpBand()                     */
11851
/************************************************************************/
11852
11853
/** Apply a binary operation on this band with another one.
11854
 *
11855
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11856
 * "hBand1 - hBand2".
11857
 *
11858
 * The resulting band is lazy evaluated. A reference is taken on both input
11859
 * datasets.
11860
 *
11861
 * @since 3.12
11862
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11863
 */
11864
GDALComputedRasterBandH
11865
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11866
                           GDALRasterAlgebraBinaryOperation eOp,
11867
                           GDALRasterBandH hOtherBand)
11868
0
{
11869
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11870
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11871
0
#ifndef HAVE_MUPARSER
11872
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11873
0
    {
11874
0
        CPLError(
11875
0
            CE_Failure, CPLE_NotSupported,
11876
0
            "Band comparison operators not available on a GDAL build without "
11877
0
            "muparser");
11878
0
        return nullptr;
11879
0
    }
11880
0
    else if (eOp == GRABO_POW)
11881
0
    {
11882
0
        CPLError(
11883
0
            CE_Failure, CPLE_NotSupported,
11884
0
            "pow(band, band) not available on a GDAL build without muparser");
11885
0
        return nullptr;
11886
0
    }
11887
0
#endif
11888
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11889
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11890
0
    try
11891
0
    {
11892
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11893
0
    }
11894
0
    catch (const std::exception &e)
11895
0
    {
11896
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11897
0
        return nullptr;
11898
0
    }
11899
0
    return new GDALComputedRasterBand(
11900
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11901
0
        secondBand);
11902
0
}
11903
11904
/************************************************************************/
11905
/*                    GDALRasterBandBinaryOpDouble()                    */
11906
/************************************************************************/
11907
11908
/** Apply a binary operation on this band with a constant
11909
 *
11910
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11911
 * "hBand - constant".
11912
 *
11913
 * The resulting band is lazy evaluated. A reference is taken on the input
11914
 * dataset.
11915
 *
11916
 * @since 3.12
11917
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11918
 */
11919
GDALComputedRasterBandH
11920
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11921
                             GDALRasterAlgebraBinaryOperation eOp,
11922
                             double constant)
11923
0
{
11924
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11925
0
#ifndef HAVE_MUPARSER
11926
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11927
0
    {
11928
0
        CPLError(
11929
0
            CE_Failure, CPLE_NotSupported,
11930
0
            "Band comparison operators not available on a GDAL build without "
11931
0
            "muparser");
11932
0
        return nullptr;
11933
0
    }
11934
0
#endif
11935
0
    return new GDALComputedRasterBand(
11936
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11937
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
11938
0
}
11939
11940
/************************************************************************/
11941
/*                 GDALRasterBandBinaryOpDoubleToBand()                 */
11942
/************************************************************************/
11943
11944
/** Apply a binary operation on the constant with this band
11945
 *
11946
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11947
 * "constant - hBand".
11948
 *
11949
 * The resulting band is lazy evaluated. A reference is taken on the input
11950
 * dataset.
11951
 *
11952
 * @since 3.12
11953
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11954
 */
11955
GDALComputedRasterBandH
11956
GDALRasterBandBinaryOpDoubleToBand(double constant,
11957
                                   GDALRasterAlgebraBinaryOperation eOp,
11958
                                   GDALRasterBandH hBand)
11959
0
{
11960
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11961
0
#ifndef HAVE_MUPARSER
11962
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11963
0
    {
11964
0
        CPLError(
11965
0
            CE_Failure, CPLE_NotSupported,
11966
0
            "Band comparison operators not available on a GDAL build without "
11967
0
            "muparser");
11968
0
        return nullptr;
11969
0
    }
11970
0
#endif
11971
0
    switch (eOp)
11972
0
    {
11973
0
        case GRABO_ADD:
11974
0
        case GRABO_MUL:
11975
0
        {
11976
0
            return new GDALComputedRasterBand(
11977
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11978
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
11979
0
        }
11980
11981
0
        case GRABO_DIV:
11982
0
        case GRABO_GT:
11983
0
        case GRABO_GE:
11984
0
        case GRABO_LT:
11985
0
        case GRABO_LE:
11986
0
        case GRABO_EQ:
11987
0
        case GRABO_NE:
11988
0
        case GRABO_LOGICAL_AND:
11989
0
        case GRABO_LOGICAL_OR:
11990
0
        case GRABO_POW:
11991
0
        {
11992
0
            return new GDALComputedRasterBand(
11993
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11994
0
                *(GDALRasterBand::FromHandle(hBand)));
11995
0
        }
11996
11997
0
        case GRABO_SUB:
11998
0
        {
11999
0
            break;
12000
0
        }
12001
0
    }
12002
12003
0
    return new GDALComputedRasterBand(
12004
0
        GDALComputedRasterBand::Operation::OP_ADD,
12005
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
12006
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
12007
0
        constant);
12008
0
}
12009
12010
/************************************************************************/
12011
/*                             operator+()                              */
12012
/************************************************************************/
12013
12014
/** Add this band with another one.
12015
 *
12016
 * The resulting band is lazy evaluated. A reference is taken on both input
12017
 * datasets.
12018
 *
12019
 * @since 3.12
12020
 * @throw std::runtime_error if both bands do not have the same dimensions.
12021
 */
12022
GDALComputedRasterBand
12023
GDALRasterBand::operator+(const GDALRasterBand &other) const
12024
0
{
12025
0
    ThrowIfNotSameDimensions(*this, other);
12026
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
12027
0
                                  *this, other);
12028
0
}
12029
12030
/************************************************************************/
12031
/*                             operator+()                              */
12032
/************************************************************************/
12033
12034
/** Add this band with a constant.
12035
 *
12036
 * The resulting band is lazy evaluated. A reference is taken on the input
12037
 * dataset.
12038
 *
12039
 * @since 3.12
12040
 */
12041
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
12042
0
{
12043
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
12044
0
                                  *this, constant);
12045
0
}
12046
12047
/************************************************************************/
12048
/*                             operator+()                              */
12049
/************************************************************************/
12050
12051
/** Add a band with a constant.
12052
 *
12053
 * The resulting band is lazy evaluated. A reference is taken on the input
12054
 * dataset.
12055
 *
12056
 * @since 3.12
12057
 */
12058
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
12059
0
{
12060
0
    return other + constant;
12061
0
}
12062
12063
/************************************************************************/
12064
/*                             operator-()                              */
12065
/************************************************************************/
12066
12067
/** Return a band whose value is the opposite value of the band for each
12068
 * pixel.
12069
 *
12070
 * The resulting band is lazy evaluated. A reference is taken on the input
12071
 * dataset.
12072
 *
12073
 * @since 3.12
12074
 */
12075
GDALComputedRasterBand GDALRasterBand::operator-() const
12076
0
{
12077
0
    return 0 - *this;
12078
0
}
12079
12080
/************************************************************************/
12081
/*                             operator-()                              */
12082
/************************************************************************/
12083
12084
/** Subtract this band with another one.
12085
 *
12086
 * The resulting band is lazy evaluated. A reference is taken on both input
12087
 * datasets.
12088
 *
12089
 * @since 3.12
12090
 * @throw std::runtime_error if both bands do not have the same dimensions.
12091
 */
12092
GDALComputedRasterBand
12093
GDALRasterBand::operator-(const GDALRasterBand &other) const
12094
0
{
12095
0
    ThrowIfNotSameDimensions(*this, other);
12096
0
    return GDALComputedRasterBand(
12097
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
12098
0
}
12099
12100
/************************************************************************/
12101
/*                             operator-()                              */
12102
/************************************************************************/
12103
12104
/** Subtract this band with a constant.
12105
 *
12106
 * The resulting band is lazy evaluated. A reference is taken on the input
12107
 * dataset.
12108
 *
12109
 * @since 3.12
12110
 */
12111
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
12112
0
{
12113
0
    return GDALComputedRasterBand(
12114
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
12115
0
}
12116
12117
/************************************************************************/
12118
/*                             operator-()                              */
12119
/************************************************************************/
12120
12121
/** Subtract a constant with a band.
12122
 *
12123
 * The resulting band is lazy evaluated. A reference is taken on the input
12124
 * dataset.
12125
 *
12126
 * @since 3.12
12127
 */
12128
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
12129
0
{
12130
0
    return other * (-1.0) + constant;
12131
0
}
12132
12133
/************************************************************************/
12134
/*                             operator*()                              */
12135
/************************************************************************/
12136
12137
/** Multiply this band with another one.
12138
 *
12139
 * The resulting band is lazy evaluated. A reference is taken on both input
12140
 * datasets.
12141
 *
12142
 * @since 3.12
12143
 * @throw std::runtime_error if both bands do not have the same dimensions.
12144
 */
12145
GDALComputedRasterBand
12146
GDALRasterBand::operator*(const GDALRasterBand &other) const
12147
0
{
12148
0
    ThrowIfNotSameDimensions(*this, other);
12149
0
    return GDALComputedRasterBand(
12150
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
12151
0
}
12152
12153
/************************************************************************/
12154
/*                             operator*()                              */
12155
/************************************************************************/
12156
12157
/** Multiply this band by a constant.
12158
 *
12159
 * The resulting band is lazy evaluated. A reference is taken on the input
12160
 * dataset.
12161
 *
12162
 * @since 3.12
12163
 */
12164
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
12165
0
{
12166
0
    return GDALComputedRasterBand(
12167
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
12168
0
}
12169
12170
/************************************************************************/
12171
/*                             operator*()                              */
12172
/************************************************************************/
12173
12174
/** Multiply a band with a constant.
12175
 *
12176
 * The resulting band is lazy evaluated. A reference is taken on the input
12177
 * dataset.
12178
 *
12179
 * @since 3.12
12180
 */
12181
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12182
0
{
12183
0
    return other * constant;
12184
0
}
12185
12186
/************************************************************************/
12187
/*                             operator/()                              */
12188
/************************************************************************/
12189
12190
/** Divide this band with another one.
12191
 *
12192
 * The resulting band is lazy evaluated. A reference is taken on both input
12193
 * datasets.
12194
 *
12195
 * @since 3.12
12196
 * @throw std::runtime_error if both bands do not have the same dimensions.
12197
 */
12198
GDALComputedRasterBand
12199
GDALRasterBand::operator/(const GDALRasterBand &other) const
12200
0
{
12201
0
    ThrowIfNotSameDimensions(*this, other);
12202
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12203
0
                                  *this, other);
12204
0
}
12205
12206
/************************************************************************/
12207
/*                             operator/()                              */
12208
/************************************************************************/
12209
12210
/** Divide this band by a constant.
12211
 *
12212
 * The resulting band is lazy evaluated. A reference is taken on the input
12213
 * dataset.
12214
 *
12215
 * @since 3.12
12216
 */
12217
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12218
0
{
12219
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12220
0
                                  *this, constant);
12221
0
}
12222
12223
/************************************************************************/
12224
/*                             operator/()                              */
12225
/************************************************************************/
12226
12227
/** Divide a constant by a band.
12228
 *
12229
 * The resulting band is lazy evaluated. A reference is taken on the input
12230
 * dataset.
12231
 *
12232
 * @since 3.12
12233
 */
12234
GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12235
0
{
12236
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12237
0
                                  constant, other);
12238
0
}
12239
12240
/************************************************************************/
12241
/*                         ThrowIfNotMuparser()                         */
12242
/************************************************************************/
12243
12244
#ifndef HAVE_MUPARSER
12245
static GDALComputedRasterBand ThrowIfNotMuparser()
12246
0
{
12247
0
    throw std::runtime_error("Operator not available on a "
12248
0
                             "GDAL build without muparser");
12249
0
}
12250
#endif
12251
12252
/************************************************************************/
12253
/*                         CreateComputedBand()                         */
12254
/************************************************************************/
12255
12256
static GDALComputedRasterBand
12257
CreateComputedBand(GDALComputedRasterBand::Operation op,
12258
                   const GDALRasterBand &bandA, const GDALRasterBand &bandB)
12259
0
{
12260
0
#ifndef HAVE_MUPARSER
12261
0
    (void)op;
12262
0
    (void)bandA;
12263
0
    (void)bandB;
12264
0
    return ThrowIfNotMuparser();
12265
#else
12266
    GDALRasterBand::ThrowIfNotSameDimensions(bandA, bandB);
12267
    return GDALComputedRasterBand(op, bandA, bandB);
12268
#endif
12269
0
}
12270
12271
static GDALComputedRasterBand
12272
CreateComputedBand(GDALComputedRasterBand::Operation op,
12273
                   const GDALRasterBand &band, double constant)
12274
0
{
12275
0
#ifndef HAVE_MUPARSER
12276
0
    (void)op;
12277
0
    (void)band;
12278
0
    (void)constant;
12279
0
    return ThrowIfNotMuparser();
12280
#else
12281
    return GDALComputedRasterBand(op, band, constant);
12282
#endif
12283
0
}
12284
12285
static GDALComputedRasterBand
12286
CreateComputedBand(GDALComputedRasterBand::Operation op, double constant,
12287
                   const GDALRasterBand &band)
12288
0
{
12289
0
#ifndef HAVE_MUPARSER
12290
0
    (void)op;
12291
0
    (void)constant;
12292
0
    (void)band;
12293
0
    return ThrowIfNotMuparser();
12294
#else
12295
    return GDALComputedRasterBand(op, constant, band);
12296
#endif
12297
0
}
12298
12299
/************************************************************************/
12300
/*                             operator>()                              */
12301
/************************************************************************/
12302
12303
/** Return a band whose value is 1 if the pixel value of the left operand
12304
 * is greater than the pixel value of the right operand.
12305
 *
12306
 * The resulting band is lazy evaluated. A reference is taken on the input
12307
 * dataset.
12308
 *
12309
 * @since 3.12
12310
 */
12311
GDALComputedRasterBand
12312
GDALRasterBand::operator>(const GDALRasterBand &other) const
12313
0
{
12314
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GT, *this,
12315
0
                              other);
12316
0
}
12317
12318
/************************************************************************/
12319
/*                             operator>()                              */
12320
/************************************************************************/
12321
12322
/** Return a band whose value is 1 if the pixel value of the left operand
12323
 * is greater than the constant.
12324
 *
12325
 * The resulting band is lazy evaluated. A reference is taken on the input
12326
 * dataset.
12327
 *
12328
 * @since 3.12
12329
 */
12330
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12331
0
{
12332
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GT, *this,
12333
0
                              constant);
12334
0
}
12335
12336
/************************************************************************/
12337
/*                             operator>()                              */
12338
/************************************************************************/
12339
12340
/** Return a band whose value is 1 if the constant is greater than the pixel
12341
 * value of the right operand.
12342
 *
12343
 * The resulting band is lazy evaluated. A reference is taken on the input
12344
 * dataset.
12345
 *
12346
 * @since 3.12
12347
 */
12348
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12349
0
{
12350
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GT,
12351
0
                              constant, other);
12352
0
}
12353
12354
/************************************************************************/
12355
/*                             operator>=()                             */
12356
/************************************************************************/
12357
12358
/** Return a band whose value is 1 if the pixel value of the left operand
12359
 * is greater or equal to the pixel value of the right operand.
12360
 *
12361
 * The resulting band is lazy evaluated. A reference is taken on the input
12362
 * dataset.
12363
 *
12364
 * @since 3.12
12365
 */
12366
GDALComputedRasterBand
12367
GDALRasterBand::operator>=(const GDALRasterBand &other) const
12368
0
{
12369
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GE, *this,
12370
0
                              other);
12371
0
}
12372
12373
/************************************************************************/
12374
/*                             operator>=()                             */
12375
/************************************************************************/
12376
12377
/** Return a band whose value is 1 if the pixel value of the left operand
12378
 * is greater or equal to the constant.
12379
 *
12380
 * The resulting band is lazy evaluated. A reference is taken on the input
12381
 * dataset.
12382
 *
12383
 * @since 3.12
12384
 */
12385
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12386
0
{
12387
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GE, *this,
12388
0
                              constant);
12389
0
}
12390
12391
/************************************************************************/
12392
/*                             operator>=()                             */
12393
/************************************************************************/
12394
12395
/** Return a band whose value is 1 if the constant is greater or equal to
12396
 * the pixel value of the right operand.
12397
 *
12398
 * The resulting band is lazy evaluated. A reference is taken on the input
12399
 * dataset.
12400
 *
12401
 * @since 3.12
12402
 */
12403
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12404
0
{
12405
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GE,
12406
0
                              constant, other);
12407
0
}
12408
12409
/************************************************************************/
12410
/*                             operator<()                              */
12411
/************************************************************************/
12412
12413
/** Return a band whose value is 1 if the pixel value of the left operand
12414
 * is lesser than the pixel value of the right operand.
12415
 *
12416
 * The resulting band is lazy evaluated. A reference is taken on the input
12417
 * dataset.
12418
 *
12419
 * @since 3.12
12420
 */
12421
GDALComputedRasterBand
12422
GDALRasterBand::operator<(const GDALRasterBand &other) const
12423
0
{
12424
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LT, *this,
12425
0
                              other);
12426
0
}
12427
12428
/************************************************************************/
12429
/*                             operator<()                              */
12430
/************************************************************************/
12431
12432
/** Return a band whose value is 1 if the pixel value of the left operand
12433
 * is lesser than the constant.
12434
 *
12435
 * The resulting band is lazy evaluated. A reference is taken on the input
12436
 * dataset.
12437
 *
12438
 * @since 3.12
12439
 */
12440
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12441
0
{
12442
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LT, *this,
12443
0
                              constant);
12444
0
}
12445
12446
/************************************************************************/
12447
/*                             operator<()                              */
12448
/************************************************************************/
12449
12450
/** Return a band whose value is 1 if the constant is lesser than the pixel
12451
 * value of the right operand.
12452
 *
12453
 * The resulting band is lazy evaluated. A reference is taken on the input
12454
 * dataset.
12455
 *
12456
 * @since 3.12
12457
 */
12458
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12459
0
{
12460
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LT,
12461
0
                              constant, other);
12462
0
}
12463
12464
/************************************************************************/
12465
/*                             operator<=()                             */
12466
/************************************************************************/
12467
12468
/** Return a band whose value is 1 if the pixel value of the left operand
12469
 * is lesser or equal to the pixel value of the right operand.
12470
 *
12471
 * The resulting band is lazy evaluated. A reference is taken on the input
12472
 * dataset.
12473
 *
12474
 * @since 3.12
12475
 */
12476
GDALComputedRasterBand
12477
GDALRasterBand::operator<=(const GDALRasterBand &other) const
12478
0
{
12479
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LE, *this,
12480
0
                              other);
12481
0
}
12482
12483
/************************************************************************/
12484
/*                             operator<=()                             */
12485
/************************************************************************/
12486
12487
/** Return a band whose value is 1 if the pixel value of the left operand
12488
 * is lesser or equal to the constant.
12489
 *
12490
 * The resulting band is lazy evaluated. A reference is taken on the input
12491
 * dataset.
12492
 *
12493
 * @since 3.12
12494
 */
12495
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12496
0
{
12497
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LE, *this,
12498
0
                              constant);
12499
0
}
12500
12501
/************************************************************************/
12502
/*                             operator<=()                             */
12503
/************************************************************************/
12504
12505
/** Return a band whose value is 1 if the constant is lesser or equal to
12506
 * the pixel value of the right operand.
12507
 *
12508
 * The resulting band is lazy evaluated. A reference is taken on the input
12509
 * dataset.
12510
 *
12511
 * @since 3.12
12512
 */
12513
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12514
0
{
12515
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LE,
12516
0
                              constant, other);
12517
0
}
12518
12519
/************************************************************************/
12520
/*                             operator==()                             */
12521
/************************************************************************/
12522
12523
/** Return a band whose value is 1 if the pixel value of the left operand
12524
 * is equal to the pixel value of the right operand.
12525
 *
12526
 * The resulting band is lazy evaluated. A reference is taken on the input
12527
 * dataset.
12528
 *
12529
 * @since 3.12
12530
 */
12531
GDALComputedRasterBand
12532
GDALRasterBand::operator==(const GDALRasterBand &other) const
12533
0
{
12534
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_EQ, *this,
12535
0
                              other);
12536
0
}
12537
12538
/************************************************************************/
12539
/*                             operator==()                             */
12540
/************************************************************************/
12541
12542
/** Return a band whose value is 1 if the pixel value of the left operand
12543
 * is equal to the constant.
12544
 *
12545
 * The resulting band is lazy evaluated. A reference is taken on the input
12546
 * dataset.
12547
 *
12548
 * @since 3.12
12549
 */
12550
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12551
0
{
12552
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_EQ, *this,
12553
0
                              constant);
12554
0
}
12555
12556
/************************************************************************/
12557
/*                             operator==()                             */
12558
/************************************************************************/
12559
12560
/** Return a band whose value is 1 if the constant is equal to
12561
 * the pixel value of the right operand.
12562
 *
12563
 * The resulting band is lazy evaluated. A reference is taken on the input
12564
 * dataset.
12565
 *
12566
 * @since 3.12
12567
 */
12568
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12569
0
{
12570
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_EQ,
12571
0
                              constant, other);
12572
0
}
12573
12574
/************************************************************************/
12575
/*                             operator!=()                             */
12576
/************************************************************************/
12577
12578
/** Return a band whose value is 1 if the pixel value of the left operand
12579
 * is different from the pixel value of the right operand.
12580
 *
12581
 * The resulting band is lazy evaluated. A reference is taken on the input
12582
 * dataset.
12583
 *
12584
 * @since 3.12
12585
 */
12586
GDALComputedRasterBand
12587
GDALRasterBand::operator!=(const GDALRasterBand &other) const
12588
0
{
12589
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_NE, *this,
12590
0
                              other);
12591
0
}
12592
12593
/************************************************************************/
12594
/*                             operator!=()                             */
12595
/************************************************************************/
12596
12597
/** Return a band whose value is 1 if the pixel value of the left operand
12598
 * is different from the constant.
12599
 *
12600
 * The resulting band is lazy evaluated. A reference is taken on the input
12601
 * dataset.
12602
 *
12603
 * @since 3.12
12604
 */
12605
GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12606
0
{
12607
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_NE, *this,
12608
0
                              constant);
12609
0
}
12610
12611
/************************************************************************/
12612
/*                             operator!=()                             */
12613
/************************************************************************/
12614
12615
/** Return a band whose value is 1 if the constant is different from
12616
 * the pixel value of the right operand.
12617
 *
12618
 * The resulting band is lazy evaluated. A reference is taken on the input
12619
 * dataset.
12620
 *
12621
 * @since 3.12
12622
 */
12623
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12624
0
{
12625
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_NE,
12626
0
                              constant, other);
12627
0
}
12628
12629
#if defined(__GNUC__)
12630
#pragma GCC diagnostic push
12631
#pragma GCC diagnostic ignored "-Weffc++"
12632
#endif
12633
12634
/************************************************************************/
12635
/*                             operator&&()                             */
12636
/************************************************************************/
12637
12638
/** Return a band whose value is 1 if the pixel value of the left and right
12639
 * operands is true.
12640
 *
12641
 * The resulting band is lazy evaluated. A reference is taken on the input
12642
 * dataset.
12643
 *
12644
 * @since 3.12
12645
 */
12646
GDALComputedRasterBand
12647
GDALRasterBand::operator&&(const GDALRasterBand &other) const
12648
0
{
12649
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_AND,
12650
0
                              *this, other);
12651
0
}
12652
12653
/************************************************************************/
12654
/*                             operator&&()                             */
12655
/************************************************************************/
12656
12657
/** Return a band whose value is 1 if the pixel value of the left operand
12658
 * is true, as well as the constant
12659
 *
12660
 * The resulting band is lazy evaluated. A reference is taken on the input
12661
 * dataset.
12662
 *
12663
 * @since 3.12
12664
 */
12665
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12666
0
{
12667
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_AND,
12668
0
                              *this, constant);
12669
0
}
12670
12671
/************************************************************************/
12672
/*                             operator&&()                             */
12673
/************************************************************************/
12674
12675
/** Return a band whose value is 1 if the constant is true, as well as
12676
 * the pixel value of the right operand.
12677
 *
12678
 * The resulting band is lazy evaluated. A reference is taken on the input
12679
 * dataset.
12680
 *
12681
 * @since 3.12
12682
 */
12683
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12684
0
{
12685
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_AND,
12686
0
                              constant, other);
12687
0
}
12688
12689
/************************************************************************/
12690
/*                             operator||()                             */
12691
/************************************************************************/
12692
12693
/** Return a band whose value is 1 if the pixel value of the left or right
12694
 * operands is true.
12695
 *
12696
 * The resulting band is lazy evaluated. A reference is taken on the input
12697
 * dataset.
12698
 *
12699
 * @since 3.12
12700
 */
12701
GDALComputedRasterBand
12702
GDALRasterBand::operator||(const GDALRasterBand &other) const
12703
0
{
12704
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_OR,
12705
0
                              *this, other);
12706
0
}
12707
12708
/************************************************************************/
12709
/*                             operator||()                             */
12710
/************************************************************************/
12711
12712
/** Return a band whose value is 1 if the pixel value of the left operand
12713
 * is true, or if the constant is true
12714
 *
12715
 * The resulting band is lazy evaluated. A reference is taken on the input
12716
 * dataset.
12717
 *
12718
 * @since 3.12
12719
 */
12720
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12721
0
{
12722
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_OR,
12723
0
                              *this, constant);
12724
0
}
12725
12726
/************************************************************************/
12727
/*                             operator||()                             */
12728
/************************************************************************/
12729
12730
/** Return a band whose value is 1 if the constant is true, or
12731
 * the pixel value of the right operand is true
12732
 *
12733
 * The resulting band is lazy evaluated. A reference is taken on the input
12734
 * dataset.
12735
 *
12736
 * @since 3.12
12737
 */
12738
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12739
0
{
12740
0
    return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_OR,
12741
0
                              constant, other);
12742
0
}
12743
12744
#if defined(__GNUC__)
12745
#pragma GCC diagnostic pop
12746
#endif
12747
12748
/************************************************************************/
12749
/*                             operator!()                              */
12750
/************************************************************************/
12751
12752
/** Return a band whose value is the logical negation of the pixel value
12753
 *
12754
 * The resulting band is lazy evaluated. A reference is taken on the input
12755
 * dataset.
12756
 *
12757
 * @since 3.12
12758
 */
12759
GDALComputedRasterBand GDALRasterBand::operator!() const
12760
0
{
12761
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12762
0
                                  *this, true);
12763
0
}
12764
12765
namespace gdal
12766
{
12767
12768
/************************************************************************/
12769
/*                             IfThenElse()                             */
12770
/************************************************************************/
12771
12772
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12773
 * is not zero, or the one from elseBand otherwise.
12774
 *
12775
 * Variants of this method exits where thenBand and/or elseBand can be double
12776
 * values.
12777
 *
12778
 * The resulting band is lazy evaluated. A reference is taken on the input
12779
 * datasets.
12780
 *
12781
 * This method is the same as the C function GDALRasterBandIfThenElse()
12782
 *
12783
 * @since 3.12
12784
 */
12785
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12786
                                  const GDALRasterBand &thenBand,
12787
                                  const GDALRasterBand &elseBand)
12788
0
{
12789
0
#ifndef HAVE_MUPARSER
12790
0
    (void)condBand;
12791
0
    (void)thenBand;
12792
0
    (void)elseBand;
12793
0
    return ThrowIfNotMuparser();
12794
#else
12795
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12796
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12797
    return GDALComputedRasterBand(
12798
        GDALComputedRasterBand::Operation::OP_TERNARY,
12799
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12800
#endif
12801
0
}
12802
12803
//! @cond Doxygen_Suppress
12804
12805
/************************************************************************/
12806
/*                             IfThenElse()                             */
12807
/************************************************************************/
12808
12809
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12810
 * is not zero, or the one from elseBand otherwise.
12811
 *
12812
 * The resulting band is lazy evaluated. A reference is taken on the input
12813
 * datasets.
12814
 *
12815
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12816
 * with thenBand = (condBand * 0) + thenValue
12817
 *
12818
 * @since 3.12
12819
 */
12820
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12821
                                  double thenValue,
12822
                                  const GDALRasterBand &elseBand)
12823
0
{
12824
0
#ifndef HAVE_MUPARSER
12825
0
    (void)condBand;
12826
0
    (void)thenValue;
12827
0
    (void)elseBand;
12828
0
    return ThrowIfNotMuparser();
12829
#else
12830
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12831
    auto thenBand =
12832
        (condBand * 0)
12833
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12834
        thenValue;
12835
    return GDALComputedRasterBand(
12836
        GDALComputedRasterBand::Operation::OP_TERNARY,
12837
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12838
#endif
12839
0
}
12840
12841
/************************************************************************/
12842
/*                             IfThenElse()                             */
12843
/************************************************************************/
12844
12845
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12846
 * is not zero, or the one from elseValue otherwise.
12847
 *
12848
 * The resulting band is lazy evaluated. A reference is taken on the input
12849
 * datasets.
12850
 *
12851
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12852
 * with elseBand = (condBand * 0) + elseValue
12853
12854
 * @since 3.12
12855
 */
12856
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12857
                                  const GDALRasterBand &thenBand,
12858
                                  double elseValue)
12859
0
{
12860
0
#ifndef HAVE_MUPARSER
12861
0
    (void)condBand;
12862
0
    (void)thenBand;
12863
0
    (void)elseValue;
12864
0
    return ThrowIfNotMuparser();
12865
#else
12866
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12867
    auto elseBand =
12868
        (condBand * 0)
12869
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12870
        elseValue;
12871
    return GDALComputedRasterBand(
12872
        GDALComputedRasterBand::Operation::OP_TERNARY,
12873
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12874
#endif
12875
0
}
12876
12877
/************************************************************************/
12878
/*                             IfThenElse()                             */
12879
/************************************************************************/
12880
12881
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12882
 * is not zero, or the one from elseValue otherwise.
12883
 *
12884
 * The resulting band is lazy evaluated. A reference is taken on the input
12885
 * datasets.
12886
 *
12887
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12888
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12889
 *
12890
 * @since 3.12
12891
 */
12892
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12893
                                  double thenValue, double elseValue)
12894
0
{
12895
0
#ifndef HAVE_MUPARSER
12896
0
    (void)condBand;
12897
0
    (void)thenValue;
12898
0
    (void)elseValue;
12899
0
    return ThrowIfNotMuparser();
12900
#else
12901
    auto thenBand =
12902
        (condBand * 0)
12903
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12904
        thenValue;
12905
    auto elseBand =
12906
        (condBand * 0)
12907
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12908
        elseValue;
12909
    return GDALComputedRasterBand(
12910
        GDALComputedRasterBand::Operation::OP_TERNARY,
12911
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12912
#endif
12913
0
}
12914
12915
//! @endcond
12916
12917
}  // namespace gdal
12918
12919
/************************************************************************/
12920
/*                      GDALRasterBandIfThenElse()                      */
12921
/************************************************************************/
12922
12923
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12924
 * is not zero, or the one from hElseBand otherwise.
12925
 *
12926
 * The resulting band is lazy evaluated. A reference is taken on the input
12927
 * datasets.
12928
 *
12929
 * This function is the same as the C++ method gdal::IfThenElse()
12930
 *
12931
 * @since 3.12
12932
 */
12933
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12934
                                                 GDALRasterBandH hThenBand,
12935
                                                 GDALRasterBandH hElseBand)
12936
0
{
12937
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12938
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12939
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12940
0
#ifndef HAVE_MUPARSER
12941
0
    CPLError(CE_Failure, CPLE_NotSupported,
12942
0
             "Band comparison operators not available on a GDAL build without "
12943
0
             "muparser");
12944
0
    return nullptr;
12945
#else
12946
12947
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12948
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12949
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12950
    try
12951
    {
12952
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12953
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12954
    }
12955
    catch (const std::exception &e)
12956
    {
12957
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12958
        return nullptr;
12959
    }
12960
    return new GDALComputedRasterBand(
12961
        GDALComputedRasterBand::Operation::OP_TERNARY,
12962
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12963
#endif
12964
0
}
12965
12966
/************************************************************************/
12967
/*                       GDALRasterBand::AsType()                       */
12968
/************************************************************************/
12969
12970
/** Cast this band to another type.
12971
 *
12972
 * The resulting band is lazy evaluated. A reference is taken on the input
12973
 * dataset.
12974
 *
12975
 * This method is the same as the C function GDALRasterBandAsDataType()
12976
 *
12977
 * @since 3.12
12978
 */
12979
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12980
0
{
12981
0
    if (dt == GDT_Unknown)
12982
0
    {
12983
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12984
0
    }
12985
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12986
0
                                  *this, dt);
12987
0
}
12988
12989
/************************************************************************/
12990
/*                      GDALRasterBandAsDataType()                      */
12991
/************************************************************************/
12992
12993
/** Cast this band to another type.
12994
 *
12995
 * The resulting band is lazy evaluated. A reference is taken on the input
12996
 * dataset.
12997
 *
12998
 * This function is the same as the C++ method GDALRasterBand::AsType()
12999
 *
13000
 * @since 3.12
13001
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13002
 */
13003
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
13004
                                                 GDALDataType eDT)
13005
0
{
13006
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
13007
0
    if (eDT == GDT_Unknown)
13008
0
    {
13009
0
        CPLError(CE_Failure, CPLE_NotSupported,
13010
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
13011
0
        return nullptr;
13012
0
    }
13013
0
    return new GDALComputedRasterBand(
13014
0
        GDALComputedRasterBand::Operation::OP_CAST,
13015
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
13016
0
}
13017
13018
/************************************************************************/
13019
/*                           GetBandVector()                            */
13020
/************************************************************************/
13021
13022
static std::vector<const GDALRasterBand *>
13023
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
13024
0
{
13025
0
    std::vector<const GDALRasterBand *> bands;
13026
0
    for (size_t i = 0; i < nBandCount; ++i)
13027
0
    {
13028
0
        if (i > 0)
13029
0
        {
13030
0
            GDALRasterBand::ThrowIfNotSameDimensions(
13031
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
13032
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
13033
0
        }
13034
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
13035
0
    }
13036
0
    return bands;
13037
0
}
13038
13039
/************************************************************************/
13040
/*                       GDALOperationOnNBands()                        */
13041
/************************************************************************/
13042
13043
static GDALComputedRasterBandH
13044
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
13045
                      GDALRasterBandH *pahBands)
13046
0
{
13047
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
13048
0
    if (nBandCount == 0)
13049
0
    {
13050
0
        CPLError(CE_Failure, CPLE_AppDefined,
13051
0
                 "At least one band should be passed");
13052
0
        return nullptr;
13053
0
    }
13054
13055
0
    std::vector<const GDALRasterBand *> bands;
13056
0
    try
13057
0
    {
13058
0
        bands = GetBandVector(nBandCount, pahBands);
13059
0
    }
13060
0
    catch (const std::exception &e)
13061
0
    {
13062
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
13063
0
        return nullptr;
13064
0
    }
13065
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
13066
0
}
13067
13068
/************************************************************************/
13069
/*                        GDALMaximumOfNBands()                         */
13070
/************************************************************************/
13071
13072
/** Return a band whose each pixel value is the maximum of the corresponding
13073
 * pixel values in the input bands.
13074
 *
13075
 * The resulting band is lazy evaluated. A reference is taken on input
13076
 * datasets.
13077
 *
13078
 * This function is the same as the C ++ method gdal::max()
13079
 *
13080
 * @since 3.12
13081
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13082
 */
13083
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
13084
                                            GDALRasterBandH *pahBands)
13085
0
{
13086
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
13087
0
                                 nBandCount, pahBands);
13088
0
}
13089
13090
/************************************************************************/
13091
/*                             gdal::max()                              */
13092
/************************************************************************/
13093
13094
namespace gdal
13095
{
13096
/** Return a band whose each pixel value is the maximum of the corresponding
13097
 * pixel values in the inputs (bands or constants)
13098
 *
13099
 * The resulting band is lazy evaluated. A reference is taken on input
13100
 * datasets.
13101
 *
13102
 * Two or more bands can be passed.
13103
 *
13104
 * This method is the same as the C function GDALMaximumOfNBands()
13105
 *
13106
 * @since 3.12
13107
 * @throw std::runtime_error if bands do not have the same dimensions.
13108
 */
13109
GDALComputedRasterBand max(const GDALRasterBand &first,
13110
                           const GDALRasterBand &second)
13111
0
{
13112
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13113
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13114
0
                                  first, second);
13115
0
}
13116
}  // namespace gdal
13117
13118
/************************************************************************/
13119
/*                     GDALRasterBandMaxConstant()                      */
13120
/************************************************************************/
13121
13122
/** Return a band whose each pixel value is the maximum of the corresponding
13123
 * pixel values in the input band and the constant.
13124
 *
13125
 * The resulting band is lazy evaluated. A reference is taken on the input
13126
 * dataset.
13127
 *
13128
 * This function is the same as the C ++ method gdal::max()
13129
 *
13130
 * @since 3.12
13131
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13132
 */
13133
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13134
                                                  double dfConstant)
13135
0
{
13136
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13137
0
        GDALComputedRasterBand::Operation::OP_MAX,
13138
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13139
0
        dfConstant));
13140
0
}
13141
13142
/************************************************************************/
13143
/*                        GDALMinimumOfNBands()                         */
13144
/************************************************************************/
13145
13146
/** Return a band whose each pixel value is the minimum of the corresponding
13147
 * pixel values in the input bands.
13148
 *
13149
 * The resulting band is lazy evaluated. A reference is taken on input
13150
 * datasets.
13151
 *
13152
 * This function is the same as the C ++ method gdal::min()
13153
 *
13154
 * @since 3.12
13155
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13156
 */
13157
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13158
                                            GDALRasterBandH *pahBands)
13159
0
{
13160
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13161
0
                                 nBandCount, pahBands);
13162
0
}
13163
13164
/************************************************************************/
13165
/*                             gdal::min()                              */
13166
/************************************************************************/
13167
13168
namespace gdal
13169
{
13170
/** Return a band whose each pixel value is the minimum of the corresponding
13171
 * pixel values in the inputs (bands or constants)
13172
 *
13173
 * The resulting band is lazy evaluated. A reference is taken on input
13174
 * datasets.
13175
 *
13176
 * Two or more bands can be passed.
13177
 *
13178
 * This method is the same as the C function GDALMinimumOfNBands()
13179
 *
13180
 * @since 3.12
13181
 * @throw std::runtime_error if bands do not have the same dimensions.
13182
 */
13183
GDALComputedRasterBand min(const GDALRasterBand &first,
13184
                           const GDALRasterBand &second)
13185
0
{
13186
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13187
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13188
0
                                  first, second);
13189
0
}
13190
}  // namespace gdal
13191
13192
/************************************************************************/
13193
/*                     GDALRasterBandMinConstant()                      */
13194
/************************************************************************/
13195
13196
/** Return a band whose each pixel value is the minimum of the corresponding
13197
 * pixel values in the input band and the constant.
13198
 *
13199
 * The resulting band is lazy evaluated. A reference is taken on the input
13200
 * dataset.
13201
 *
13202
 * This function is the same as the C ++ method gdal::min()
13203
 *
13204
 * @since 3.12
13205
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13206
 */
13207
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13208
                                                  double dfConstant)
13209
0
{
13210
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13211
0
        GDALComputedRasterBand::Operation::OP_MIN,
13212
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13213
0
        dfConstant));
13214
0
}
13215
13216
/************************************************************************/
13217
/*                          GDALMeanOfNBands()                          */
13218
/************************************************************************/
13219
13220
/** Return a band whose each pixel value is the arithmetic mean of the
13221
 * corresponding pixel values in the input bands.
13222
 *
13223
 * The resulting band is lazy evaluated. A reference is taken on input
13224
 * datasets.
13225
 *
13226
 * This function is the same as the C ++ method gdal::mean()
13227
 *
13228
 * @since 3.12
13229
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13230
 */
13231
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13232
                                         GDALRasterBandH *pahBands)
13233
0
{
13234
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13235
0
                                 nBandCount, pahBands);
13236
0
}
13237
13238
/************************************************************************/
13239
/*                             gdal::mean()                             */
13240
/************************************************************************/
13241
13242
namespace gdal
13243
{
13244
13245
/** Return a band whose each pixel value is the arithmetic mean of the
13246
 * corresponding pixel values in the input bands.
13247
 *
13248
 * The resulting band is lazy evaluated. A reference is taken on input
13249
 * datasets.
13250
 *
13251
 * Two or more bands can be passed.
13252
 *
13253
 * This method is the same as the C function GDALMeanOfNBands()
13254
 *
13255
 * @since 3.12
13256
 * @throw std::runtime_error if bands do not have the same dimensions.
13257
 */
13258
GDALComputedRasterBand mean(const GDALRasterBand &first,
13259
                            const GDALRasterBand &second)
13260
0
{
13261
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13262
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13263
0
                                  first, second);
13264
0
}
13265
}  // namespace gdal
13266
13267
/************************************************************************/
13268
/*                             gdal::abs()                              */
13269
/************************************************************************/
13270
13271
namespace gdal
13272
{
13273
13274
/** Return a band whose each pixel value is the absolute value (or module
13275
 * for complex data type) of the corresponding pixel value in the input band.
13276
 *
13277
 * The resulting band is lazy evaluated. A reference is taken on input
13278
 * datasets.
13279
 *
13280
 * @since 3.12
13281
 */
13282
GDALComputedRasterBand abs(const GDALRasterBand &band)
13283
0
{
13284
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13285
0
                                  band);
13286
0
}
13287
}  // namespace gdal
13288
13289
/************************************************************************/
13290
/*                             gdal::fabs()                             */
13291
/************************************************************************/
13292
13293
namespace gdal
13294
{
13295
13296
/** Return a band whose each pixel value is the absolute value (or module
13297
 * for complex data type) of the corresponding pixel value in the input band.
13298
 *
13299
 * The resulting band is lazy evaluated. A reference is taken on input
13300
 * datasets.
13301
 *
13302
 * @since 3.12
13303
 */
13304
GDALComputedRasterBand fabs(const GDALRasterBand &band)
13305
0
{
13306
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13307
0
                                  band);
13308
0
}
13309
}  // namespace gdal
13310
13311
/************************************************************************/
13312
/*                             gdal::sqrt()                             */
13313
/************************************************************************/
13314
13315
namespace gdal
13316
{
13317
13318
/** Return a band whose each pixel value is the square root of the
13319
 * corresponding pixel value in the input band.
13320
 *
13321
 * The resulting band is lazy evaluated. A reference is taken on input
13322
 * datasets.
13323
 *
13324
 * @since 3.12
13325
 */
13326
GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13327
0
{
13328
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13329
0
                                  band);
13330
0
}
13331
}  // namespace gdal
13332
13333
/************************************************************************/
13334
/*                             gdal::log()                              */
13335
/************************************************************************/
13336
13337
namespace gdal
13338
{
13339
13340
/** Return a band whose each pixel value is the natural logarithm of the
13341
 * corresponding pixel value in the input band.
13342
 *
13343
 * The resulting band is lazy evaluated. A reference is taken on input
13344
 * datasets.
13345
 *
13346
 * @since 3.12
13347
 */
13348
GDALComputedRasterBand log(const GDALRasterBand &band)
13349
0
{
13350
0
#ifndef HAVE_MUPARSER
13351
0
    (void)band;
13352
0
    return ThrowIfNotMuparser();
13353
#else
13354
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13355
                                  band);
13356
#endif
13357
0
}
13358
}  // namespace gdal
13359
13360
/************************************************************************/
13361
/*                            gdal::log10()                             */
13362
/************************************************************************/
13363
13364
namespace gdal
13365
{
13366
13367
/** Return a band whose each pixel value is the logarithm base 10 of the
13368
 * corresponding pixel value in the input band.
13369
 *
13370
 * The resulting band is lazy evaluated. A reference is taken on input
13371
 * datasets.
13372
 *
13373
 * @since 3.12
13374
 */
13375
GDALComputedRasterBand log10(const GDALRasterBand &band)
13376
0
{
13377
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13378
0
                                  band);
13379
0
}
13380
}  // namespace gdal
13381
13382
/************************************************************************/
13383
/*                             gdal::pow()                              */
13384
/************************************************************************/
13385
13386
namespace gdal
13387
{
13388
13389
#ifndef DOXYGEN_SKIP
13390
/** Return a band whose each pixel value is the constant raised to the power of
13391
 * the corresponding pixel value in the input band.
13392
 *
13393
 * The resulting band is lazy evaluated. A reference is taken on input
13394
 * datasets.
13395
 *
13396
 * @since 3.12
13397
 */
13398
GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13399
0
{
13400
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13401
0
                                  constant, band);
13402
0
}
13403
#endif
13404
13405
}  // namespace gdal
13406
13407
/************************************************************************/
13408
/*                             gdal::pow()                              */
13409
/************************************************************************/
13410
13411
namespace gdal
13412
{
13413
13414
/** Return a band whose each pixel value is the the corresponding pixel value
13415
 * in the input band raised to the power of the constant.
13416
 *
13417
 * The resulting band is lazy evaluated. A reference is taken on input
13418
 * datasets.
13419
 *
13420
 * @since 3.12
13421
 */
13422
GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13423
0
{
13424
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13425
0
                                  band, constant);
13426
0
}
13427
}  // namespace gdal
13428
13429
/************************************************************************/
13430
/*                             gdal::pow()                              */
13431
/************************************************************************/
13432
13433
namespace gdal
13434
{
13435
13436
#ifndef DOXYGEN_SKIP
13437
/** Return a band whose each pixel value is the the corresponding pixel value
13438
 * in the input band1 raised to the power of the corresponding pixel value
13439
 * in the input band2
13440
 *
13441
 * The resulting band is lazy evaluated. A reference is taken on input
13442
 * datasets.
13443
 *
13444
 * @since 3.12
13445
 * @throw std::runtime_error if bands do not have the same dimensions.
13446
 */
13447
GDALComputedRasterBand pow(const GDALRasterBand &band1,
13448
                           const GDALRasterBand &band2)
13449
0
{
13450
0
#ifndef HAVE_MUPARSER
13451
0
    (void)band1;
13452
0
    (void)band2;
13453
0
    return ThrowIfNotMuparser();
13454
#else
13455
    GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13456
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13457
                                  band1, band2);
13458
#endif
13459
0
}
13460
#endif
13461
}  // namespace gdal