Coverage Report

Created: 2026-04-01 06:20

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", "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", "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", "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
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4506
0
                    continue;
4507
4508
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4509
                // finite, the result of the multiplication cannot be NaN
4510
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4511
4512
0
                if (dfIndex < 0)
4513
0
                {
4514
0
                    if (bIncludeOutOfRange)
4515
0
                        panHistogram[0]++;
4516
0
                }
4517
0
                else if (dfIndex >= nBuckets)
4518
0
                {
4519
0
                    if (bIncludeOutOfRange)
4520
0
                        ++panHistogram[nBuckets - 1];
4521
0
                }
4522
0
                else
4523
0
                {
4524
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4525
0
                }
4526
0
            }
4527
0
        }
4528
4529
0
        CPLFree(pData);
4530
0
        CPLFree(pabyMaskData);
4531
0
    }
4532
0
    else  // No arbitrary overviews.
4533
0
    {
4534
0
        if (!InitBlockInfo())
4535
0
            return CE_Failure;
4536
4537
        /* --------------------------------------------------------------------
4538
         */
4539
        /*      Figure out the ratio of blocks we will read to get an */
4540
        /*      approximate value. */
4541
        /* --------------------------------------------------------------------
4542
         */
4543
4544
0
        int nSampleRate = 1;
4545
0
        if (bApproxOK)
4546
0
        {
4547
0
            nSampleRate = static_cast<int>(std::max(
4548
0
                1.0,
4549
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4550
            // We want to avoid probing only the first column of blocks for
4551
            // a square shaped raster, because it is not unlikely that it may
4552
            // be padding only (#6378).
4553
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4554
0
                nSampleRate += 1;
4555
0
        }
4556
4557
0
        GByte *pabyMaskData = nullptr;
4558
0
        if (poMaskBand)
4559
0
        {
4560
0
            pabyMaskData = static_cast<GByte *>(
4561
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4562
0
            if (!pabyMaskData)
4563
0
            {
4564
0
                return CE_Failure;
4565
0
            }
4566
0
        }
4567
4568
        /* --------------------------------------------------------------------
4569
         */
4570
        /*      Read the blocks, and add to histogram. */
4571
        /* --------------------------------------------------------------------
4572
         */
4573
0
        for (GIntBig iSampleBlock = 0;
4574
0
             iSampleBlock <
4575
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4576
0
             iSampleBlock += nSampleRate)
4577
0
        {
4578
0
            if (!pfnProgress(
4579
0
                    static_cast<double>(iSampleBlock) /
4580
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4581
0
                    "Compute Histogram", pProgressData))
4582
0
            {
4583
0
                CPLFree(pabyMaskData);
4584
0
                return CE_Failure;
4585
0
            }
4586
4587
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4588
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4589
4590
0
            int nXCheck = 0, nYCheck = 0;
4591
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4592
4593
0
            if (poMaskBand &&
4594
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4595
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4596
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4597
0
                                     0, nBlockXSize, nullptr) != CE_None)
4598
0
            {
4599
0
                CPLFree(pabyMaskData);
4600
0
                return CE_Failure;
4601
0
            }
4602
4603
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4604
0
            if (poBlock == nullptr)
4605
0
            {
4606
0
                CPLFree(pabyMaskData);
4607
0
                return CE_Failure;
4608
0
            }
4609
4610
0
            void *pData = poBlock->GetDataRef();
4611
4612
            // this is a special case for a common situation.
4613
0
            if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4614
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4615
0
                nXCheck == nBlockXSize && nBuckets == 256)
4616
0
            {
4617
0
                const GPtrDiff_t nPixels =
4618
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4619
0
                GByte *pabyData = static_cast<GByte *>(pData);
4620
4621
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4622
0
                {
4623
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4624
0
                        continue;
4625
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4626
0
                          (pabyData[i] ==
4627
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4628
0
                    {
4629
0
                        panHistogram[pabyData[i]]++;
4630
0
                    }
4631
0
                }
4632
4633
0
                poBlock->DropLock();
4634
0
                continue;  // To next sample block.
4635
0
            }
4636
4637
            // This isn't the fastest way to do this, but is easier for now.
4638
0
            for (int iY = 0; iY < nYCheck; iY++)
4639
0
            {
4640
0
                for (int iX = 0; iX < nXCheck; iX++)
4641
0
                {
4642
0
                    const GPtrDiff_t iOffset =
4643
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4644
4645
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4646
0
                        continue;
4647
4648
0
                    double dfValue = 0.0;
4649
4650
0
                    switch (eDataType)
4651
0
                    {
4652
0
                        case GDT_UInt8:
4653
0
                        {
4654
0
                            if (bSignedByte)
4655
0
                                dfValue =
4656
0
                                    static_cast<signed char *>(pData)[iOffset];
4657
0
                            else
4658
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4659
0
                            break;
4660
0
                        }
4661
0
                        case GDT_Int8:
4662
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4663
0
                            break;
4664
0
                        case GDT_UInt16:
4665
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4666
0
                            break;
4667
0
                        case GDT_Int16:
4668
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4669
0
                            break;
4670
0
                        case GDT_UInt32:
4671
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4672
0
                            break;
4673
0
                        case GDT_Int32:
4674
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4675
0
                            break;
4676
0
                        case GDT_UInt64:
4677
0
                            dfValue = static_cast<double>(
4678
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4679
0
                            break;
4680
0
                        case GDT_Int64:
4681
0
                            dfValue = static_cast<double>(
4682
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4683
0
                            break;
4684
0
                        case GDT_Float16:
4685
0
                        {
4686
0
                            using namespace std;
4687
0
                            const GFloat16 hfValue =
4688
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4689
0
                            if (isnan(hfValue) ||
4690
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4691
0
                                 ARE_REAL_EQUAL(hfValue,
4692
0
                                                sNoDataValues.hfNoDataValue)))
4693
0
                                continue;
4694
0
                            dfValue = hfValue;
4695
0
                            break;
4696
0
                        }
4697
0
                        case GDT_Float32:
4698
0
                        {
4699
0
                            const float fValue =
4700
0
                                static_cast<float *>(pData)[iOffset];
4701
0
                            if (std::isnan(fValue) ||
4702
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4703
0
                                 ARE_REAL_EQUAL(fValue,
4704
0
                                                sNoDataValues.fNoDataValue)))
4705
0
                                continue;
4706
0
                            dfValue = double(fValue);
4707
0
                            break;
4708
0
                        }
4709
0
                        case GDT_Float64:
4710
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4711
0
                            if (std::isnan(dfValue))
4712
0
                                continue;
4713
0
                            break;
4714
0
                        case GDT_CInt16:
4715
0
                        {
4716
0
                            double dfReal =
4717
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4718
0
                            double dfImag =
4719
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4720
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4721
0
                            break;
4722
0
                        }
4723
0
                        case GDT_CInt32:
4724
0
                        {
4725
0
                            double dfReal =
4726
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4727
0
                            double dfImag =
4728
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4729
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4730
0
                            break;
4731
0
                        }
4732
0
                        case GDT_CFloat16:
4733
0
                        {
4734
0
                            double dfReal =
4735
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4736
0
                            double dfImag =
4737
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4738
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4739
0
                                continue;
4740
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4741
0
                            break;
4742
0
                        }
4743
0
                        case GDT_CFloat32:
4744
0
                        {
4745
0
                            double dfReal = double(
4746
0
                                static_cast<float *>(pData)[iOffset * 2]);
4747
0
                            double dfImag = double(
4748
0
                                static_cast<float *>(pData)[iOffset * 2 + 1]);
4749
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4750
0
                                continue;
4751
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4752
0
                            break;
4753
0
                        }
4754
0
                        case GDT_CFloat64:
4755
0
                        {
4756
0
                            double dfReal =
4757
0
                                static_cast<double *>(pData)[iOffset * 2];
4758
0
                            double dfImag =
4759
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4760
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4761
0
                                continue;
4762
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4763
0
                            break;
4764
0
                        }
4765
0
                        case GDT_Unknown:
4766
0
                        case GDT_TypeCount:
4767
0
                            CPLAssert(false);
4768
0
                            CPLFree(pabyMaskData);
4769
0
                            return CE_Failure;
4770
0
                    }
4771
4772
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4773
0
                        sNoDataValues.bGotNoDataValue &&
4774
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4775
0
                        continue;
4776
4777
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4778
                    // and finite, the result of the multiplication cannot be
4779
                    // NaN
4780
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4781
4782
0
                    if (dfIndex < 0)
4783
0
                    {
4784
0
                        if (bIncludeOutOfRange)
4785
0
                            panHistogram[0]++;
4786
0
                    }
4787
0
                    else if (dfIndex >= nBuckets)
4788
0
                    {
4789
0
                        if (bIncludeOutOfRange)
4790
0
                            ++panHistogram[nBuckets - 1];
4791
0
                    }
4792
0
                    else
4793
0
                    {
4794
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4795
0
                    }
4796
0
                }
4797
0
            }
4798
4799
0
            poBlock->DropLock();
4800
0
        }
4801
4802
0
        CPLFree(pabyMaskData);
4803
0
    }
4804
4805
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4806
4807
0
    return CE_None;
4808
0
}
4809
4810
/************************************************************************/
4811
/*                       GDALGetRasterHistogram()                       */
4812
/************************************************************************/
4813
4814
/**
4815
 * \brief Compute raster histogram.
4816
 *
4817
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4818
 * exceeding 2 billion.
4819
 *
4820
 * @see GDALRasterBand::GetHistogram()
4821
 * @see GDALGetRasterHistogramEx()
4822
 */
4823
4824
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4825
                                          double dfMax, int nBuckets,
4826
                                          int *panHistogram,
4827
                                          int bIncludeOutOfRange, int bApproxOK,
4828
                                          GDALProgressFunc pfnProgress,
4829
                                          void *pProgressData)
4830
4831
0
{
4832
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4833
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4834
4835
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4836
4837
0
    GUIntBig *panHistogramTemp =
4838
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4839
0
    if (panHistogramTemp == nullptr)
4840
0
    {
4841
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4842
0
                            "Out of memory in GDALGetRasterHistogram().");
4843
0
        return CE_Failure;
4844
0
    }
4845
4846
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4847
0
                                       bIncludeOutOfRange, bApproxOK,
4848
0
                                       pfnProgress, pProgressData);
4849
4850
0
    if (eErr == CE_None)
4851
0
    {
4852
0
        for (int i = 0; i < nBuckets; i++)
4853
0
        {
4854
0
            if (panHistogramTemp[i] > INT_MAX)
4855
0
            {
4856
0
                CPLError(CE_Warning, CPLE_AppDefined,
4857
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4858
0
                         " exceeds maximum 32 bit value",
4859
0
                         i, panHistogramTemp[i]);
4860
0
                panHistogram[i] = INT_MAX;
4861
0
            }
4862
0
            else
4863
0
            {
4864
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4865
0
            }
4866
0
        }
4867
0
    }
4868
4869
0
    CPLFree(panHistogramTemp);
4870
4871
0
    return eErr;
4872
0
}
4873
4874
/************************************************************************/
4875
/*                      GDALGetRasterHistogramEx()                      */
4876
/************************************************************************/
4877
4878
/**
4879
 * \brief Compute raster histogram.
4880
 *
4881
 * @see GDALRasterBand::GetHistogram()
4882
 *
4883
 */
4884
4885
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4886
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4887
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4888
    GDALProgressFunc pfnProgress, void *pProgressData)
4889
4890
0
{
4891
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4892
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4893
4894
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4895
4896
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4897
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4898
0
                                pProgressData);
4899
0
}
4900
4901
/************************************************************************/
4902
/*                        GetDefaultHistogram()                         */
4903
/************************************************************************/
4904
4905
/**
4906
 * \brief Fetch default raster histogram.
4907
 *
4908
 * The default method in GDALRasterBand will compute a default histogram. This
4909
 * method is overridden by derived classes (such as GDALPamRasterBand,
4910
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4911
 * stored histogram.
4912
 *
4913
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4914
 * GDALGetDefaultHistogramEx().
4915
 *
4916
 * @param pdfMin pointer to double value that will contain the lower bound of
4917
 * the histogram.
4918
 * @param pdfMax pointer to double value that will contain the upper bound of
4919
 * the histogram.
4920
 * @param pnBuckets pointer to int value that will contain the number of buckets
4921
 * in *ppanHistogram.
4922
 * @param ppanHistogram pointer to array into which the histogram totals are
4923
 * placed. To be freed with VSIFree
4924
 * @param bForce TRUE to force the computation. If FALSE and no default
4925
 * histogram is available, the method will return CE_Warning
4926
 * @param pfnProgress function to report progress to completion.
4927
 * @param pProgressData application data to pass to pfnProgress.
4928
 *
4929
 * @return CE_None on success, CE_Failure if something goes wrong, or
4930
 * CE_Warning if no default histogram is available.
4931
 */
4932
4933
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4934
                                           int *pnBuckets,
4935
                                           GUIntBig **ppanHistogram, int bForce,
4936
                                           GDALProgressFunc pfnProgress,
4937
                                           void *pProgressData)
4938
4939
0
{
4940
0
    CPLAssert(nullptr != pnBuckets);
4941
0
    CPLAssert(nullptr != ppanHistogram);
4942
0
    CPLAssert(nullptr != pdfMin);
4943
0
    CPLAssert(nullptr != pdfMax);
4944
4945
0
    *pnBuckets = 0;
4946
0
    *ppanHistogram = nullptr;
4947
4948
0
    if (!bForce)
4949
0
        return CE_Warning;
4950
4951
0
    int nBuckets = 256;
4952
4953
0
    bool bSignedByte = false;
4954
0
    if (eDataType == GDT_UInt8)
4955
0
    {
4956
0
        EnablePixelTypeSignedByteWarning(false);
4957
0
        const char *pszPixelType =
4958
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4959
0
        EnablePixelTypeSignedByteWarning(true);
4960
0
        bSignedByte =
4961
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4962
0
    }
4963
4964
0
    if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4965
0
    {
4966
0
        *pdfMin = -0.5;
4967
0
        *pdfMax = 255.5;
4968
0
    }
4969
0
    else if (GetRasterDataType() == GDT_Int8)
4970
0
    {
4971
0
        *pdfMin = -128 - 0.5;
4972
0
        *pdfMax = 127 + 0.5;
4973
0
    }
4974
0
    else
4975
0
    {
4976
4977
0
        const CPLErr eErr =
4978
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4979
0
        if (eErr != CE_None)
4980
0
            return eErr;
4981
0
        if (*pdfMin == *pdfMax)
4982
0
        {
4983
0
            nBuckets = 1;
4984
0
            *pdfMin -= 0.5;
4985
0
            *pdfMax += 0.5;
4986
0
        }
4987
0
        else
4988
0
        {
4989
0
            const double dfHalfBucket =
4990
0
                (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4991
0
            *pdfMin -= dfHalfBucket;
4992
0
            *pdfMax += dfHalfBucket;
4993
0
        }
4994
0
    }
4995
4996
0
    *ppanHistogram =
4997
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4998
0
    if (*ppanHistogram == nullptr)
4999
0
    {
5000
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
5001
0
                    "Out of memory in GetDefaultHistogram().");
5002
0
        return CE_Failure;
5003
0
    }
5004
5005
0
    *pnBuckets = nBuckets;
5006
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
5007
0
                               TRUE, FALSE, pfnProgress, pProgressData);
5008
0
    if (eErr != CE_None)
5009
0
    {
5010
0
        *pnBuckets = 0;
5011
0
    }
5012
0
    return eErr;
5013
0
}
5014
5015
/************************************************************************/
5016
/*                      GDALGetDefaultHistogram()                       */
5017
/************************************************************************/
5018
5019
/**
5020
 * \brief Fetch default raster histogram.
5021
 *
5022
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5023
 * exceeding 2 billion.
5024
 *
5025
 * @see GDALRasterBand::GDALGetDefaultHistogram()
5026
 * @see GDALGetRasterHistogramEx()
5027
 */
5028
5029
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5030
                                           double *pdfMin, double *pdfMax,
5031
                                           int *pnBuckets, int **ppanHistogram,
5032
                                           int bForce,
5033
                                           GDALProgressFunc pfnProgress,
5034
                                           void *pProgressData)
5035
5036
0
{
5037
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5038
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5039
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5040
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5041
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5042
5043
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5044
0
    GUIntBig *panHistogramTemp = nullptr;
5045
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5046
0
                                              &panHistogramTemp, bForce,
5047
0
                                              pfnProgress, pProgressData);
5048
0
    if (eErr == CE_None)
5049
0
    {
5050
0
        const int nBuckets = *pnBuckets;
5051
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5052
0
        if (*ppanHistogram == nullptr)
5053
0
        {
5054
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5055
0
                                "Out of memory in GDALGetDefaultHistogram().");
5056
0
            VSIFree(panHistogramTemp);
5057
0
            return CE_Failure;
5058
0
        }
5059
5060
0
        for (int i = 0; i < nBuckets; ++i)
5061
0
        {
5062
0
            if (panHistogramTemp[i] > INT_MAX)
5063
0
            {
5064
0
                CPLError(CE_Warning, CPLE_AppDefined,
5065
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
5066
0
                         " exceeds maximum 32 bit value",
5067
0
                         i, panHistogramTemp[i]);
5068
0
                (*ppanHistogram)[i] = INT_MAX;
5069
0
            }
5070
0
            else
5071
0
            {
5072
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5073
0
            }
5074
0
        }
5075
5076
0
        CPLFree(panHistogramTemp);
5077
0
    }
5078
0
    else
5079
0
    {
5080
0
        *ppanHistogram = nullptr;
5081
0
    }
5082
5083
0
    return eErr;
5084
0
}
5085
5086
/************************************************************************/
5087
/*                     GDALGetDefaultHistogramEx()                      */
5088
/************************************************************************/
5089
5090
/**
5091
 * \brief Fetch default raster histogram.
5092
 *
5093
 * @see GDALRasterBand::GetDefaultHistogram()
5094
 *
5095
 */
5096
5097
CPLErr CPL_STDCALL
5098
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5099
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5100
                          GDALProgressFunc pfnProgress, void *pProgressData)
5101
5102
0
{
5103
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5104
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5105
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5106
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5107
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5108
5109
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5110
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5111
0
                                       bForce, pfnProgress, pProgressData);
5112
0
}
5113
5114
/************************************************************************/
5115
/*                             AdviseRead()                             */
5116
/************************************************************************/
5117
5118
/**
5119
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5120
 * \brief Advise driver of upcoming read requests.
5121
 *
5122
 * Some GDAL drivers operate more efficiently if they know in advance what
5123
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5124
 * an application to notify the driver of the region of interest,
5125
 * and at what resolution the region will be read.
5126
 *
5127
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5128
 * accelerate access via some drivers.
5129
 *
5130
 * Depending on call paths, drivers might receive several calls to
5131
 * AdviseRead() with the same parameters.
5132
 *
5133
 * @param nXOff The pixel offset to the top left corner of the region
5134
 * of the band to be accessed.  This would be zero to start from the left side.
5135
 *
5136
 * @param nYOff The line offset to the top left corner of the region
5137
 * of the band to be accessed.  This would be zero to start from the top.
5138
 *
5139
 * @param nXSize The width of the region of the band to be accessed in pixels.
5140
 *
5141
 * @param nYSize The height of the region of the band to be accessed in lines.
5142
 *
5143
 * @param nBufXSize the width of the buffer image into which the desired region
5144
 * is to be read, or from which it is to be written.
5145
 *
5146
 * @param nBufYSize the height of the buffer image into which the desired
5147
 * region is to be read, or from which it is to be written.
5148
 *
5149
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5150
 * pixel values will automatically be translated to/from the GDALRasterBand
5151
 * data type as needed.
5152
 *
5153
 * @param papszOptions a list of name=value strings with special control
5154
 * options.  Normally this is NULL.
5155
 *
5156
 * @return CE_Failure if the request is invalid and CE_None if it works or
5157
 * is ignored.
5158
 */
5159
5160
/**/
5161
/**/
5162
5163
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5164
                                  int /*nYSize*/, int /*nBufXSize*/,
5165
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5166
                                  CSLConstList /*papszOptions*/)
5167
0
{
5168
0
    return CE_None;
5169
0
}
5170
5171
/************************************************************************/
5172
/*                        GDALRasterAdviseRead()                        */
5173
/************************************************************************/
5174
5175
/**
5176
 * \brief Advise driver of upcoming read requests.
5177
 *
5178
 * @see GDALRasterBand::AdviseRead()
5179
 */
5180
5181
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5182
                                        int nYOff, int nXSize, int nYSize,
5183
                                        int nBufXSize, int nBufYSize,
5184
                                        GDALDataType eDT,
5185
                                        CSLConstList papszOptions)
5186
5187
0
{
5188
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5189
5190
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5191
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5192
0
                              nBufYSize, eDT,
5193
0
                              const_cast<char **>(papszOptions));
5194
0
}
5195
5196
/************************************************************************/
5197
/*                           GetStatistics()                            */
5198
/************************************************************************/
5199
5200
/**
5201
 * \brief Fetch image statistics.
5202
 *
5203
 * Returns the minimum, maximum, mean and standard deviation of all
5204
 * pixel values in this band.  If approximate statistics are sufficient,
5205
 * the bApproxOK flag can be set to true in which case overviews, or a
5206
 * subset of image tiles may be used in computing the statistics.
5207
 *
5208
 * If bForce is FALSE results will only be returned if it can be done
5209
 * quickly (i.e. without scanning the image, typically by using pre-existing
5210
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5211
 * returned efficiently, the method will return CE_Warning but no warning will
5212
 * be issued. This is a non-standard use of the CE_Warning return value
5213
 * to indicate "nothing done".
5214
 *
5215
 * If bForce is TRUE, and results are quickly available without scanning the
5216
 * image, they will be used. If bForce is TRUE and results are not quickly
5217
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5218
 * which will scan the image.
5219
 *
5220
 * To always force recomputation of statistics, use ComputeStatistics() instead
5221
 * of this method.
5222
 *
5223
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5224
 * will generally cache statistics in the .pam file allowing fast fetch
5225
 * after the first request.
5226
 *
5227
 * This method is the same as the C function GDALGetRasterStatistics().
5228
 *
5229
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5230
 * or a subset of all tiles.
5231
 *
5232
 * @param bForce If FALSE statistics will only be returned if it can
5233
 * be done without rescanning the image. If TRUE, statistics computation will
5234
 * be forced if pre-existing values are not quickly available.
5235
 *
5236
 * @param pdfMin Location into which to load image minimum (may be NULL).
5237
 *
5238
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5239
 *
5240
 * @param pdfMean Location into which to load image mean (may be NULL).
5241
 *
5242
 * @param pdfStdDev Location into which to load image standard deviation
5243
 * (may be NULL).
5244
 *
5245
 * @return CE_None on success, CE_Warning if no values returned,
5246
 * CE_Failure if an error occurs.
5247
 */
5248
5249
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5250
                                     double *pdfMax, double *pdfMean,
5251
                                     double *pdfStdDev)
5252
5253
0
{
5254
    /* -------------------------------------------------------------------- */
5255
    /*      Do we already have metadata items for the requested values?     */
5256
    /* -------------------------------------------------------------------- */
5257
0
    if ((pdfMin == nullptr ||
5258
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5259
0
        (pdfMax == nullptr ||
5260
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5261
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5262
0
        (pdfStdDev == nullptr ||
5263
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5264
0
    {
5265
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5266
0
        {
5267
0
            if (pdfMin != nullptr)
5268
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5269
0
            if (pdfMax != nullptr)
5270
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5271
0
            if (pdfMean != nullptr)
5272
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5273
0
            if (pdfStdDev != nullptr)
5274
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5275
5276
0
            return CE_None;
5277
0
        }
5278
0
    }
5279
5280
    /* -------------------------------------------------------------------- */
5281
    /*      Does the driver already know the min/max?                       */
5282
    /* -------------------------------------------------------------------- */
5283
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5284
0
    {
5285
0
        int bSuccessMin = FALSE;
5286
0
        int bSuccessMax = FALSE;
5287
5288
0
        const double dfMin = GetMinimum(&bSuccessMin);
5289
0
        const double dfMax = GetMaximum(&bSuccessMax);
5290
5291
0
        if (bSuccessMin && bSuccessMax)
5292
0
        {
5293
0
            if (pdfMin != nullptr)
5294
0
                *pdfMin = dfMin;
5295
0
            if (pdfMax != nullptr)
5296
0
                *pdfMax = dfMax;
5297
0
            return CE_None;
5298
0
        }
5299
0
    }
5300
5301
    /* -------------------------------------------------------------------- */
5302
    /*      Either return without results, or force computation.            */
5303
    /* -------------------------------------------------------------------- */
5304
0
    if (!bForce)
5305
0
        return CE_Warning;
5306
0
    else
5307
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5308
0
                                 GDALDummyProgress, nullptr);
5309
0
}
5310
5311
/************************************************************************/
5312
/*                      GDALGetRasterStatistics()                       */
5313
/************************************************************************/
5314
5315
/**
5316
 * \brief Fetch image statistics.
5317
 *
5318
 * @see GDALRasterBand::GetStatistics()
5319
 */
5320
5321
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5322
                                           int bForce, double *pdfMin,
5323
                                           double *pdfMax, double *pdfMean,
5324
                                           double *pdfStdDev)
5325
5326
0
{
5327
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5328
5329
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5330
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5331
0
                                 pdfStdDev);
5332
0
}
5333
5334
/************************************************************************/
5335
/*                             GDALUInt128                              */
5336
/************************************************************************/
5337
5338
#ifdef HAVE_UINT128_T
5339
class GDALUInt128
5340
{
5341
    __uint128_t val;
5342
5343
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5344
0
    {
5345
0
    }
5346
5347
  public:
5348
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5349
0
    {
5350
        // Evaluates to just a single mul on x86_64
5351
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5352
0
    }
5353
5354
    GDALUInt128 operator-(const GDALUInt128 &other) const
5355
0
    {
5356
0
        return GDALUInt128(val - other.val);
5357
0
    }
5358
5359
    operator double() const
5360
0
    {
5361
0
        return static_cast<double>(val);
5362
0
    }
5363
};
5364
#else
5365
5366
#if defined(_MSC_VER) && defined(_M_X64)
5367
#include <intrin.h>
5368
#endif
5369
5370
class GDALUInt128
5371
{
5372
    GUIntBig low, high;
5373
5374
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5375
    {
5376
    }
5377
5378
  public:
5379
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5380
    {
5381
#if defined(_MSC_VER) && defined(_M_X64)
5382
        GUIntBig highRes;
5383
        GUIntBig lowRes = _umul128(first, second, &highRes);
5384
        return GDALUInt128(lowRes, highRes);
5385
#else
5386
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5387
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5388
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5389
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5390
        GUIntBig highRes = 0;
5391
        const GUIntBig firstLowSecondHigh =
5392
            static_cast<GUIntBig>(firstLow) * secondHigh;
5393
        const GUIntBig firstHighSecondLow =
5394
            static_cast<GUIntBig>(firstHigh) * secondLow;
5395
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5396
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5397
            highRes += static_cast<GUIntBig>(1) << 32;
5398
        const GUIntBig firstLowSecondLow =
5399
            static_cast<GUIntBig>(firstLow) * secondLow;
5400
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5401
        if (lowRes < firstLowSecondLow)  // check for overflow
5402
            highRes++;
5403
        highRes +=
5404
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5405
        return GDALUInt128(lowRes, highRes);
5406
#endif
5407
    }
5408
5409
    GDALUInt128 operator-(const GDALUInt128 &other) const
5410
    {
5411
        GUIntBig highRes = high - other.high;
5412
        GUIntBig lowRes = low - other.low;
5413
        if (lowRes > low)  // check for underflow
5414
            --highRes;
5415
        return GDALUInt128(lowRes, highRes);
5416
    }
5417
5418
    operator double() const
5419
    {
5420
        const double twoPow64 = 18446744073709551616.0;
5421
        return high * twoPow64 + low;
5422
    }
5423
};
5424
#endif
5425
5426
/************************************************************************/
5427
/*                     ComputeStatisticsInternal()                      */
5428
/************************************************************************/
5429
5430
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5431
// not needed.
5432
0
#define static_cast_for_coverity_scan static_cast
5433
5434
// The rationale for below optimizations is detailed in statistics.txt
5435
5436
// Use with T = GByte or GUInt16 only !
5437
template <class T, bool COMPUTE_OTHER_STATS>
5438
struct ComputeStatisticsInternalGeneric
5439
{
5440
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5441
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5442
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5443
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5444
0
    {
5445
0
        static_assert(std::is_same<T, GByte>::value ||
5446
0
                          std::is_same<T, GUInt16>::value,
5447
0
                      "bad type for T");
5448
0
        if (bHasNoData)
5449
0
        {
5450
            // General case
5451
0
            for (int iY = 0; iY < nYCheck; iY++)
5452
0
            {
5453
0
                for (int iX = 0; iX < nXCheck; iX++)
5454
0
                {
5455
0
                    const GPtrDiff_t iOffset =
5456
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5457
0
                    const GUInt32 nValue = pData[iOffset];
5458
0
                    if (nValue == nNoDataValue)
5459
0
                        continue;
5460
0
                    if (nValue < nMin)
5461
0
                        nMin = nValue;
5462
0
                    if (nValue > nMax)
5463
0
                        nMax = nValue;
5464
                    if constexpr (COMPUTE_OTHER_STATS)
5465
0
                    {
5466
0
                        nValidCount++;
5467
0
                        nSum += nValue;
5468
0
                        nSumSquare +=
5469
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5470
0
                            nValue;
5471
0
                    }
5472
0
                }
5473
0
            }
5474
            if constexpr (COMPUTE_OTHER_STATS)
5475
0
            {
5476
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5477
0
            }
5478
0
        }
5479
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5480
0
                 nMax == std::numeric_limits<T>::max())
5481
0
        {
5482
            if constexpr (COMPUTE_OTHER_STATS)
5483
0
            {
5484
                // Optimization when there is no nodata and we know we have already
5485
                // reached the min and max
5486
0
                for (int iY = 0; iY < nYCheck; iY++)
5487
0
                {
5488
0
                    int iX;
5489
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5490
0
                    {
5491
0
                        const GPtrDiff_t iOffset =
5492
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493
0
                        const GUIntBig nValue = pData[iOffset];
5494
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5495
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5496
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5497
0
                        nSum += nValue;
5498
0
                        nSumSquare += nValue * nValue;
5499
0
                        nSum += nValue2;
5500
0
                        nSumSquare += nValue2 * nValue2;
5501
0
                        nSum += nValue3;
5502
0
                        nSumSquare += nValue3 * nValue3;
5503
0
                        nSum += nValue4;
5504
0
                        nSumSquare += nValue4 * nValue4;
5505
0
                    }
5506
0
                    for (; iX < nXCheck; ++iX)
5507
0
                    {
5508
0
                        const GPtrDiff_t iOffset =
5509
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5510
0
                        const GUIntBig nValue = pData[iOffset];
5511
0
                        nSum += nValue;
5512
0
                        nSumSquare += nValue * nValue;
5513
0
                    }
5514
0
                }
5515
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5516
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5517
0
            }
5518
0
        }
5519
0
        else
5520
0
        {
5521
0
            for (int iY = 0; iY < nYCheck; iY++)
5522
0
            {
5523
0
                int iX;
5524
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5525
0
                {
5526
0
                    const GPtrDiff_t iOffset =
5527
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5528
0
                    const GUInt32 nValue = pData[iOffset];
5529
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5530
0
                    if (nValue < nValue2)
5531
0
                    {
5532
0
                        if (nValue < nMin)
5533
0
                            nMin = nValue;
5534
0
                        if (nValue2 > nMax)
5535
0
                            nMax = nValue2;
5536
0
                    }
5537
0
                    else
5538
0
                    {
5539
0
                        if (nValue2 < nMin)
5540
0
                            nMin = nValue2;
5541
0
                        if (nValue > nMax)
5542
0
                            nMax = nValue;
5543
0
                    }
5544
                    if constexpr (COMPUTE_OTHER_STATS)
5545
0
                    {
5546
0
                        nSum += nValue;
5547
0
                        nSumSquare +=
5548
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5549
0
                            nValue;
5550
0
                        nSum += nValue2;
5551
0
                        nSumSquare +=
5552
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5553
0
                            nValue2;
5554
0
                    }
5555
0
                }
5556
0
                if (iX < nXCheck)
5557
0
                {
5558
0
                    const GPtrDiff_t iOffset =
5559
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5560
0
                    const GUInt32 nValue = pData[iOffset];
5561
0
                    if (nValue < nMin)
5562
0
                        nMin = nValue;
5563
0
                    if (nValue > nMax)
5564
0
                        nMax = nValue;
5565
0
                    if (COMPUTE_OTHER_STATS)
5566
0
                    {
5567
0
                        nSum += nValue;
5568
0
                        nSumSquare +=
5569
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5570
0
                            nValue;
5571
0
                    }
5572
0
                }
5573
0
            }
5574
            if constexpr (COMPUTE_OTHER_STATS)
5575
0
            {
5576
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5577
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5578
0
            }
5579
0
        }
5580
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&)
5581
};
5582
5583
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5584
// using 64bit accumulators in internal loops. This also slightly helps in
5585
// 64bit mode.
5586
template <bool COMPUTE_OTHER_STATS>
5587
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5588
{
5589
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5590
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5591
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5592
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5593
0
    {
5594
0
        int nOuterLoops = nXCheck / 65536;
5595
0
        if (nXCheck % 65536)
5596
0
            nOuterLoops++;
5597
5598
0
        if (bHasNoData)
5599
0
        {
5600
            // General case
5601
0
            for (int iY = 0; iY < nYCheck; iY++)
5602
0
            {
5603
0
                int iX = 0;
5604
0
                for (int k = 0; k < nOuterLoops; k++)
5605
0
                {
5606
0
                    int iMax = iX + 65536;
5607
0
                    if (iMax > nXCheck)
5608
0
                        iMax = nXCheck;
5609
0
                    GUInt32 nSum32bit = 0;
5610
0
                    GUInt32 nSumSquare32bit = 0;
5611
0
                    GUInt32 nValidCount32bit = 0;
5612
0
                    GUInt32 nSampleCount32bit = 0;
5613
0
                    for (; iX < iMax; iX++)
5614
0
                    {
5615
0
                        const GPtrDiff_t iOffset =
5616
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5617
0
                        const GUInt32 nValue = pData[iOffset];
5618
5619
0
                        nSampleCount32bit++;
5620
0
                        if (nValue == nNoDataValue)
5621
0
                            continue;
5622
0
                        if (nValue < nMin)
5623
0
                            nMin = nValue;
5624
0
                        if (nValue > nMax)
5625
0
                            nMax = nValue;
5626
                        if constexpr (COMPUTE_OTHER_STATS)
5627
0
                        {
5628
0
                            nValidCount32bit++;
5629
0
                            nSum32bit += nValue;
5630
0
                            nSumSquare32bit += nValue * nValue;
5631
0
                        }
5632
0
                    }
5633
                    if constexpr (COMPUTE_OTHER_STATS)
5634
0
                    {
5635
0
                        nSampleCount += nSampleCount32bit;
5636
0
                        nValidCount += nValidCount32bit;
5637
0
                        nSum += nSum32bit;
5638
0
                        nSumSquare += nSumSquare32bit;
5639
0
                    }
5640
0
                }
5641
0
            }
5642
0
        }
5643
0
        else if (nMin == 0 && nMax == 255)
5644
0
        {
5645
            if constexpr (COMPUTE_OTHER_STATS)
5646
0
            {
5647
                // Optimization when there is no nodata and we know we have already
5648
                // reached the min and max
5649
0
                for (int iY = 0; iY < nYCheck; iY++)
5650
0
                {
5651
0
                    int iX = 0;
5652
0
                    for (int k = 0; k < nOuterLoops; k++)
5653
0
                    {
5654
0
                        int iMax = iX + 65536;
5655
0
                        if (iMax > nXCheck)
5656
0
                            iMax = nXCheck;
5657
0
                        GUInt32 nSum32bit = 0;
5658
0
                        GUInt32 nSumSquare32bit = 0;
5659
0
                        for (; iX + 3 < iMax; iX += 4)
5660
0
                        {
5661
0
                            const GPtrDiff_t iOffset =
5662
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5663
0
                            const GUInt32 nValue = pData[iOffset];
5664
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5665
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5666
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5667
0
                            nSum32bit += nValue;
5668
0
                            nSumSquare32bit += nValue * nValue;
5669
0
                            nSum32bit += nValue2;
5670
0
                            nSumSquare32bit += nValue2 * nValue2;
5671
0
                            nSum32bit += nValue3;
5672
0
                            nSumSquare32bit += nValue3 * nValue3;
5673
0
                            nSum32bit += nValue4;
5674
0
                            nSumSquare32bit += nValue4 * nValue4;
5675
0
                        }
5676
0
                        nSum += nSum32bit;
5677
0
                        nSumSquare += nSumSquare32bit;
5678
0
                    }
5679
0
                    for (; iX < nXCheck; ++iX)
5680
0
                    {
5681
0
                        const GPtrDiff_t iOffset =
5682
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5683
0
                        const GUIntBig nValue = pData[iOffset];
5684
0
                        nSum += nValue;
5685
0
                        nSumSquare += nValue * nValue;
5686
0
                    }
5687
0
                }
5688
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5689
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5690
0
            }
5691
0
        }
5692
0
        else
5693
0
        {
5694
0
            for (int iY = 0; iY < nYCheck; iY++)
5695
0
            {
5696
0
                int iX = 0;
5697
0
                for (int k = 0; k < nOuterLoops; k++)
5698
0
                {
5699
0
                    int iMax = iX + 65536;
5700
0
                    if (iMax > nXCheck)
5701
0
                        iMax = nXCheck;
5702
0
                    GUInt32 nSum32bit = 0;
5703
0
                    GUInt32 nSumSquare32bit = 0;
5704
0
                    for (; iX + 1 < iMax; iX += 2)
5705
0
                    {
5706
0
                        const GPtrDiff_t iOffset =
5707
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5708
0
                        const GUInt32 nValue = pData[iOffset];
5709
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5710
0
                        if (nValue < nValue2)
5711
0
                        {
5712
0
                            if (nValue < nMin)
5713
0
                                nMin = nValue;
5714
0
                            if (nValue2 > nMax)
5715
0
                                nMax = nValue2;
5716
0
                        }
5717
0
                        else
5718
0
                        {
5719
0
                            if (nValue2 < nMin)
5720
0
                                nMin = nValue2;
5721
0
                            if (nValue > nMax)
5722
0
                                nMax = nValue;
5723
0
                        }
5724
                        if constexpr (COMPUTE_OTHER_STATS)
5725
0
                        {
5726
0
                            nSum32bit += nValue;
5727
0
                            nSumSquare32bit += nValue * nValue;
5728
0
                            nSum32bit += nValue2;
5729
0
                            nSumSquare32bit += nValue2 * nValue2;
5730
0
                        }
5731
0
                    }
5732
                    if constexpr (COMPUTE_OTHER_STATS)
5733
0
                    {
5734
0
                        nSum += nSum32bit;
5735
0
                        nSumSquare += nSumSquare32bit;
5736
0
                    }
5737
0
                }
5738
0
                if (iX < nXCheck)
5739
0
                {
5740
0
                    const GPtrDiff_t iOffset =
5741
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5742
0
                    const GUInt32 nValue = pData[iOffset];
5743
0
                    if (nValue < nMin)
5744
0
                        nMin = nValue;
5745
0
                    if (nValue > nMax)
5746
0
                        nMax = nValue;
5747
                    if constexpr (COMPUTE_OTHER_STATS)
5748
0
                    {
5749
0
                        nSum += nValue;
5750
0
                        nSumSquare +=
5751
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5752
0
                            nValue;
5753
0
                    }
5754
0
                }
5755
0
            }
5756
            if constexpr (COMPUTE_OTHER_STATS)
5757
0
            {
5758
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5759
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5760
0
            }
5761
0
        }
5762
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&)
5763
};
5764
5765
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5766
{
5767
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5768
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5769
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5770
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5771
    {
5772
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5773
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5774
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5775
    }
5776
};
5777
5778
constexpr int ALIGNMENT_AVX2_OPTIM = 32;
5779
5780
#if (defined(__x86_64__) || defined(_M_X64) ||                                 \
5781
     defined(USE_NEON_OPTIMIZATIONS)) &&                                       \
5782
    (defined(__GNUC__) || defined(_MSC_VER))
5783
5784
#include "gdal_avx2_emulation.hpp"
5785
5786
0
#define ZERO256 GDALmm256_setzero_si256()
5787
5788
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5789
static void
5790
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5791
                              // assumed to be aligned on 256 bits
5792
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5793
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5794
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5795
0
{
5796
    // 32-byte alignment may not be enforced by linker, so do it at hand
5797
0
    GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
5798
0
                             ALIGNMENT_AVX2_OPTIM +
5799
0
                             (COMPUTE_OTHER_STATS
5800
0
                                  ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
5801
0
                                  : 0)];
5802
0
    GByte *paby32ByteAligned =
5803
0
        aby32ByteUnaligned +
5804
0
        (ALIGNMENT_AVX2_OPTIM -
5805
0
         (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
5806
0
          ALIGNMENT_AVX2_OPTIM));
5807
0
    GByte *pabyMin = paby32ByteAligned;
5808
0
    GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
5809
0
    GUInt32 *panSum = COMPUTE_OTHER_STATS
5810
0
                          ? reinterpret_cast<GUInt32 *>(
5811
0
                                paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
5812
0
                          : nullptr;
5813
0
    GUInt32 *panSumSquare =
5814
0
        COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
5815
0
                                  paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
5816
0
                            : nullptr;
5817
5818
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
5819
5820
0
    GPtrDiff_t i = 0;
5821
    // Make sure that sumSquare can fit on uint32
5822
    // * 8 since we can hold 8 sums per vector register
5823
0
    const int nMaxIterationsPerInnerLoop =
5824
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5825
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5826
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5827
0
        nOuterLoops++;
5828
5829
0
    GDALm256i ymm_min =
5830
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5831
0
    GDALm256i ymm_max = ymm_min;
5832
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5833
5834
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5835
0
    {
5836
0
        const auto iMax =
5837
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5838
5839
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5840
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5841
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5842
0
            ZERO256;  // holds 8 uint32 sums
5843
0
        for (; i + 31 < iMax; i += 32)
5844
0
        {
5845
0
            const GDALm256i ymm = GDALmm256_load_si256(
5846
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5847
0
            if (COMPUTE_MIN)
5848
0
            {
5849
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5850
0
            }
5851
0
            if (COMPUTE_MAX)
5852
0
            {
5853
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5854
0
            }
5855
5856
            if constexpr (COMPUTE_OTHER_STATS)
5857
0
            {
5858
                // Extract even-8bit values
5859
0
                const GDALm256i ymm_even =
5860
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5861
                // Compute square of those 16 values as 32 bit result
5862
                // and add adjacent pairs
5863
0
                const GDALm256i ymm_even_square =
5864
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5865
                // Add to the sumsquare accumulator
5866
0
                ymm_sumsquare =
5867
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5868
5869
                // Extract odd-8bit values
5870
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5871
0
                const GDALm256i ymm_odd_square =
5872
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5873
0
                ymm_sumsquare =
5874
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5875
5876
                // Now compute the sums
5877
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5878
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5879
0
            }
5880
0
        }
5881
5882
        if constexpr (COMPUTE_OTHER_STATS)
5883
0
        {
5884
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5885
0
                                  ymm_sum);
5886
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5887
0
                                  ymm_sumsquare);
5888
5889
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5890
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5891
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5892
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5893
0
                          panSumSquare[7];
5894
0
        }
5895
0
    }
5896
5897
    if constexpr (COMPUTE_MIN)
5898
0
    {
5899
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5900
0
    }
5901
    if constexpr (COMPUTE_MAX)
5902
0
    {
5903
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5904
0
    }
5905
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5906
0
    {
5907
0
        for (int j = 0; j < 32; j++)
5908
0
        {
5909
            if constexpr (COMPUTE_MIN)
5910
0
            {
5911
0
                if (pabyMin[j] < nMin)
5912
0
                    nMin = pabyMin[j];
5913
0
            }
5914
            if constexpr (COMPUTE_MAX)
5915
0
            {
5916
0
                if (pabyMax[j] > nMax)
5917
0
                    nMax = pabyMax[j];
5918
0
            }
5919
0
        }
5920
0
    }
5921
5922
0
    for (; i < nBlockPixels; i++)
5923
0
    {
5924
0
        const GUInt32 nValue = pData[i];
5925
        if constexpr (COMPUTE_MIN)
5926
0
        {
5927
0
            if (nValue < nMin)
5928
0
                nMin = nValue;
5929
0
        }
5930
        if constexpr (COMPUTE_MAX)
5931
0
        {
5932
0
            if (nValue > nMax)
5933
0
                nMax = nValue;
5934
0
        }
5935
        if constexpr (COMPUTE_OTHER_STATS)
5936
0
        {
5937
0
            nSum += nValue;
5938
0
            nSumSquare +=
5939
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5940
0
        }
5941
0
    }
5942
5943
    if constexpr (COMPUTE_OTHER_STATS)
5944
0
    {
5945
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5946
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5947
0
    }
5948
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&)
5949
5950
// SSE2/AVX2 optimization for GByte case
5951
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5952
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5953
// there are strictly equivalent to 2 parallel SSE2 streams.
5954
template <bool COMPUTE_OTHER_STATS>
5955
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5956
{
5957
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5958
                  // assumed to be aligned on 256 bits
5959
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5960
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5961
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5962
                  GUIntBig &nValidCount)
5963
0
    {
5964
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5965
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5966
0
            nMin <= nMax)
5967
0
        {
5968
            // 32-byte alignment may not be enforced by linker, so do it at hand
5969
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5970
0
            GByte *paby32ByteAligned =
5971
0
                aby32ByteUnaligned +
5972
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5973
0
            GByte *pabyMin = paby32ByteAligned;
5974
0
            GByte *pabyMax = paby32ByteAligned + 32;
5975
0
            GUInt32 *panSum =
5976
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5977
0
            GUInt32 *panSumSquare =
5978
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5979
5980
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5981
5982
0
            GPtrDiff_t i = 0;
5983
            // Make sure that sumSquare can fit on uint32
5984
            // * 8 since we can hold 8 sums per vector register
5985
0
            const int nMaxIterationsPerInnerLoop =
5986
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5987
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5988
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5989
0
                nOuterLoops++;
5990
5991
0
            const GDALm256i ymm_nodata =
5992
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5993
            // any non noData value in [min,max] would do.
5994
0
            const GDALm256i ymm_neutral =
5995
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5996
0
            GDALm256i ymm_min = ymm_neutral;
5997
0
            GDALm256i ymm_max = ymm_neutral;
5998
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5999
0
                GDALmm256_set1_epi16(0xFF);
6000
6001
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
6002
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
6003
0
            const bool bComputeMinMax =
6004
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
6005
6006
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
6007
0
            {
6008
0
                const auto iMax =
6009
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6010
6011
                // holds 4 uint32 sums in [0], [2], [4] and [6]
6012
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
6013
                // holds 8 uint32 sums
6014
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
6015
                // holds 4 uint32 sums in [0], [2], [4] and [6]
6016
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
6017
0
                const auto iInit = i;
6018
0
                for (; i + 31 < iMax; i += 32)
6019
0
                {
6020
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6021
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6022
6023
                    // Check which values are nodata
6024
0
                    const GDALm256i ymm_eq_nodata =
6025
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6026
                    if constexpr (COMPUTE_OTHER_STATS)
6027
0
                    {
6028
                        // Count how many values are nodata (due to cmpeq
6029
                        // putting 255 when condition is met, this will actually
6030
                        // be 255 times the number of nodata value, spread in 4
6031
                        // 64 bits words). We can use add_epi32 as the counter
6032
                        // will not overflow uint32
6033
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6034
0
                            ymm_count_nodata_mul_255,
6035
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6036
0
                    }
6037
                    // Replace all nodata values by zero for the purpose of sum
6038
                    // and sumquare.
6039
0
                    const GDALm256i ymm_nodata_by_zero =
6040
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6041
0
                    if (bComputeMinMax)
6042
0
                    {
6043
                        // Replace all nodata values by a neutral value for the
6044
                        // purpose of min and max.
6045
0
                        const GDALm256i ymm_nodata_by_neutral =
6046
0
                            GDALmm256_or_si256(
6047
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6048
0
                                ymm_nodata_by_zero);
6049
6050
0
                        ymm_min =
6051
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6052
0
                        ymm_max =
6053
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6054
0
                    }
6055
6056
                    if constexpr (COMPUTE_OTHER_STATS)
6057
0
                    {
6058
                        // Extract even-8bit values
6059
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
6060
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
6061
                        // Compute square of those 16 values as 32 bit result
6062
                        // and add adjacent pairs
6063
0
                        const GDALm256i ymm_even_square =
6064
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
6065
                        // Add to the sumsquare accumulator
6066
0
                        ymm_sumsquare =
6067
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6068
6069
                        // Extract odd-8bit values
6070
0
                        const GDALm256i ymm_odd =
6071
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6072
0
                        const GDALm256i ymm_odd_square =
6073
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6074
0
                        ymm_sumsquare =
6075
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6076
6077
                        // Now compute the sums
6078
0
                        ymm_sum = GDALmm256_add_epi32(
6079
0
                            ymm_sum,
6080
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6081
0
                    }
6082
0
                }
6083
6084
                if constexpr (COMPUTE_OTHER_STATS)
6085
0
                {
6086
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
6087
0
                    GDALmm256_store_si256(
6088
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6089
0
                        ymm_count_nodata_mul_255);
6090
6091
0
                    nSampleCount += (i - iInit);
6092
6093
0
                    nValidCount +=
6094
0
                        (i - iInit) -
6095
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6096
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6097
0
                            255;
6098
6099
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6100
0
                                          ymm_sum);
6101
0
                    GDALmm256_store_si256(
6102
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
6103
0
                        ymm_sumsquare);
6104
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6105
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6106
0
                                  panSumSquare[1] + panSumSquare[2] +
6107
0
                                  panSumSquare[3] + panSumSquare[4] +
6108
0
                                  panSumSquare[5] + panSumSquare[6] +
6109
0
                                  panSumSquare[7];
6110
0
                }
6111
0
            }
6112
6113
0
            if (bComputeMinMax)
6114
0
            {
6115
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6116
0
                                      ymm_min);
6117
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6118
0
                                      ymm_max);
6119
0
                for (int j = 0; j < 32; j++)
6120
0
                {
6121
0
                    if (pabyMin[j] < nMin)
6122
0
                        nMin = pabyMin[j];
6123
0
                    if (pabyMax[j] > nMax)
6124
0
                        nMax = pabyMax[j];
6125
0
                }
6126
0
            }
6127
6128
            if constexpr (COMPUTE_OTHER_STATS)
6129
0
            {
6130
0
                nSampleCount += nBlockPixels - i;
6131
0
            }
6132
0
            for (; i < nBlockPixels; i++)
6133
0
            {
6134
0
                const GUInt32 nValue = pData[i];
6135
0
                if (nValue == nNoDataValue)
6136
0
                    continue;
6137
0
                if (nValue < nMin)
6138
0
                    nMin = nValue;
6139
0
                if (nValue > nMax)
6140
0
                    nMax = nValue;
6141
                if constexpr (COMPUTE_OTHER_STATS)
6142
0
                {
6143
0
                    nValidCount++;
6144
0
                    nSum += nValue;
6145
0
                    nSumSquare +=
6146
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6147
0
                        nValue;
6148
0
                }
6149
0
            }
6150
0
        }
6151
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6152
0
        {
6153
0
            if (nMin > 0)
6154
0
            {
6155
0
                if (nMax < 255)
6156
0
                {
6157
0
                    ComputeStatisticsByteNoNodata<true, true,
6158
0
                                                  COMPUTE_OTHER_STATS>(
6159
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6160
0
                        nSampleCount, nValidCount);
6161
0
                }
6162
0
                else
6163
0
                {
6164
0
                    ComputeStatisticsByteNoNodata<true, false,
6165
0
                                                  COMPUTE_OTHER_STATS>(
6166
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6167
0
                        nSampleCount, nValidCount);
6168
0
                }
6169
0
            }
6170
0
            else
6171
0
            {
6172
0
                if (nMax < 255)
6173
0
                {
6174
0
                    ComputeStatisticsByteNoNodata<false, true,
6175
0
                                                  COMPUTE_OTHER_STATS>(
6176
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6177
0
                        nSampleCount, nValidCount);
6178
0
                }
6179
0
                else
6180
0
                {
6181
0
                    ComputeStatisticsByteNoNodata<false, false,
6182
0
                                                  COMPUTE_OTHER_STATS>(
6183
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6184
0
                        nSampleCount, nValidCount);
6185
0
                }
6186
0
            }
6187
0
        }
6188
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6189
0
                 (nBlockXSize % 32) == 0)
6190
0
        {
6191
0
            for (int iY = 0; iY < nYCheck; iY++)
6192
0
            {
6193
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6194
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6195
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6196
0
            }
6197
0
        }
6198
0
        else
6199
0
        {
6200
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6201
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6202
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6203
0
        }
6204
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&)
6205
};
6206
6207
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6208
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6209
                             GUIntBig i)
6210
0
{
6211
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6212
0
}
6213
6214
// AVX2/SSE2 optimization for GUInt16 case
6215
template <bool COMPUTE_OTHER_STATS>
6216
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6217
{
6218
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6219
                  // assumed to be aligned on 128 bits
6220
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6221
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6222
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6223
                  GUIntBig &nValidCount)
6224
0
    {
6225
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6226
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6227
0
        {
6228
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6229
6230
0
            GPtrDiff_t i = 0;
6231
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6232
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6233
            // Furthermore the shift is also needed to use madd_epi16
6234
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6235
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6236
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6237
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6238
0
            GDALm256i ymm_max = ymm_min;
6239
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6240
0
                ZERO256;  // holds 4 uint64 sums
6241
6242
            // Make sure that sum can fit on uint32
6243
            // * 8 since we can hold 8 sums per vector register
6244
0
            const int nMaxIterationsPerInnerLoop =
6245
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6246
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6247
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6248
0
                nOuterLoops++;
6249
6250
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6251
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6252
0
                GDALmm256_set1_epi32(0xFFFF);
6253
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6254
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6255
6256
0
            GUIntBig nSumThis = 0;
6257
0
            for (int k = 0; k < nOuterLoops; k++)
6258
0
            {
6259
0
                const auto iMax =
6260
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6261
6262
0
                [[maybe_unused]] GDALm256i ymm_sum =
6263
0
                    ZERO256;  // holds 8 uint32 sums
6264
0
                for (; i + 15 < iMax; i += 16)
6265
0
                {
6266
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6267
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6268
0
                    const GDALm256i ymm_shifted =
6269
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6270
0
                    if (bComputeMinMax)
6271
0
                    {
6272
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6273
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6274
0
                    }
6275
6276
                    if constexpr (COMPUTE_OTHER_STATS)
6277
0
                    {
6278
                        // Note: the int32 range can overflow for (0-32768)^2 +
6279
                        // (0-32768)^2 = 0x80000000, but as we know the result
6280
                        // is positive, this is OK as we interpret is a uint32.
6281
0
                        const GDALm256i ymm_square =
6282
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6283
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6284
0
                            ymm_sumsquare,
6285
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6286
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6287
0
                            ymm_sumsquare,
6288
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6289
6290
                        // Now compute the sums
6291
0
                        ymm_sum = GDALmm256_add_epi32(
6292
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6293
0
                        ymm_sum = GDALmm256_add_epi32(
6294
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6295
0
                    }
6296
0
                }
6297
6298
                if constexpr (COMPUTE_OTHER_STATS)
6299
0
                {
6300
0
                    GUInt32 anSum[8];
6301
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6302
0
                                           ymm_sum);
6303
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6304
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6305
0
                                anSum[6] + anSum[7];
6306
0
                }
6307
0
            }
6308
6309
0
            if (bComputeMinMax)
6310
0
            {
6311
0
                GUInt16 anMin[16];
6312
0
                GUInt16 anMax[16];
6313
6314
                // Unshift the result
6315
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6316
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6317
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6318
0
                                       ymm_min);
6319
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6320
0
                                       ymm_max);
6321
0
                for (int j = 0; j < 16; j++)
6322
0
                {
6323
0
                    if (anMin[j] < nMin)
6324
0
                        nMin = anMin[j];
6325
0
                    if (anMax[j] > nMax)
6326
0
                        nMax = anMax[j];
6327
0
                }
6328
0
            }
6329
6330
            if constexpr (COMPUTE_OTHER_STATS)
6331
0
            {
6332
0
                GUIntBig anSumSquare[4];
6333
0
                GDALmm256_storeu_si256(
6334
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6335
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6336
0
                              anSumSquare[3];
6337
6338
                // Unshift the sum of squares
6339
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6340
0
                                 static_cast<GUIntBig>(i));
6341
6342
0
                nSum += nSumThis;
6343
6344
0
                for (; i < nBlockPixels; i++)
6345
0
                {
6346
0
                    const GUInt32 nValue = pData[i];
6347
0
                    if (nValue < nMin)
6348
0
                        nMin = nValue;
6349
0
                    if (nValue > nMax)
6350
0
                        nMax = nValue;
6351
0
                    nSum += nValue;
6352
0
                    nSumSquare +=
6353
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6354
0
                        nValue;
6355
0
                }
6356
6357
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6358
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6359
0
            }
6360
0
        }
6361
0
        else
6362
0
        {
6363
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6364
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6365
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6366
0
        }
6367
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&)
6368
};
6369
6370
#endif
6371
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6372
// defined(_MSC_VER))
6373
6374
/************************************************************************/
6375
/*                           GetPixelValue()                            */
6376
/************************************************************************/
6377
6378
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6379
                                   const void *pData, GPtrDiff_t iOffset,
6380
                                   const GDALNoDataValues &sNoDataValues,
6381
                                   bool &bValid)
6382
0
{
6383
0
    bValid = true;
6384
0
    double dfValue = 0;
6385
0
    switch (eDataType)
6386
0
    {
6387
0
        case GDT_UInt8:
6388
0
        {
6389
0
            if (bSignedByte)
6390
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6391
0
            else
6392
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6393
0
            break;
6394
0
        }
6395
0
        case GDT_Int8:
6396
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6397
0
            break;
6398
0
        case GDT_UInt16:
6399
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6400
0
            break;
6401
0
        case GDT_Int16:
6402
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6403
0
            break;
6404
0
        case GDT_UInt32:
6405
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6406
0
            break;
6407
0
        case GDT_Int32:
6408
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6409
0
            break;
6410
0
        case GDT_UInt64:
6411
0
            dfValue = static_cast<double>(
6412
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6413
0
            break;
6414
0
        case GDT_Int64:
6415
0
            dfValue = static_cast<double>(
6416
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6417
0
            break;
6418
0
        case GDT_Float16:
6419
0
        {
6420
0
            using namespace std;
6421
0
            const GFloat16 hfValue =
6422
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6423
0
            if (isnan(hfValue) ||
6424
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6425
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6426
0
            {
6427
0
                bValid = false;
6428
0
                return 0.0;
6429
0
            }
6430
0
            dfValue = hfValue;
6431
0
            return dfValue;
6432
0
        }
6433
0
        case GDT_Float32:
6434
0
        {
6435
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6436
0
            if (std::isnan(fValue) ||
6437
0
                (sNoDataValues.bGotFloatNoDataValue &&
6438
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6439
0
            {
6440
0
                bValid = false;
6441
0
                return 0.0;
6442
0
            }
6443
0
            dfValue = double(fValue);
6444
0
            return dfValue;
6445
0
        }
6446
0
        case GDT_Float64:
6447
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6448
0
            if (std::isnan(dfValue))
6449
0
            {
6450
0
                bValid = false;
6451
0
                return 0.0;
6452
0
            }
6453
0
            break;
6454
0
        case GDT_CInt16:
6455
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6456
0
            break;
6457
0
        case GDT_CInt32:
6458
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6459
0
            break;
6460
0
        case GDT_CFloat16:
6461
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6462
0
            if (std::isnan(dfValue))
6463
0
            {
6464
0
                bValid = false;
6465
0
                return 0.0;
6466
0
            }
6467
0
            break;
6468
0
        case GDT_CFloat32:
6469
0
            dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6470
0
            if (std::isnan(dfValue))
6471
0
            {
6472
0
                bValid = false;
6473
0
                return 0.0;
6474
0
            }
6475
0
            break;
6476
0
        case GDT_CFloat64:
6477
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6478
0
            if (std::isnan(dfValue))
6479
0
            {
6480
0
                bValid = false;
6481
0
                return 0.0;
6482
0
            }
6483
0
            break;
6484
0
        case GDT_Unknown:
6485
0
        case GDT_TypeCount:
6486
0
            CPLAssert(false);
6487
0
            break;
6488
0
    }
6489
6490
0
    if (sNoDataValues.bGotNoDataValue &&
6491
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6492
0
    {
6493
0
        bValid = false;
6494
0
        return 0.0;
6495
0
    }
6496
0
    return dfValue;
6497
0
}
6498
6499
/************************************************************************/
6500
/*                          SetValidPercent()                           */
6501
/************************************************************************/
6502
6503
//! @cond Doxygen_Suppress
6504
/**
6505
 * \brief Set percentage of valid (not nodata) pixels.
6506
 *
6507
 * Stores the percentage of valid pixels in the metadata item
6508
 * STATISTICS_VALID_PERCENT
6509
 *
6510
 * @param nSampleCount Number of sampled pixels.
6511
 *
6512
 * @param nValidCount Number of valid pixels.
6513
 */
6514
6515
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6516
                                     GUIntBig nValidCount)
6517
0
{
6518
0
    if (nValidCount == 0)
6519
0
    {
6520
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6521
0
    }
6522
0
    else if (nValidCount == nSampleCount)
6523
0
    {
6524
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6525
0
    }
6526
0
    else /* nValidCount < nSampleCount */
6527
0
    {
6528
0
        char szValue[128] = {0};
6529
6530
        /* percentage is only an indicator: limit precision */
6531
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6532
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6533
6534
0
        if (EQUAL(szValue, "100"))
6535
0
        {
6536
            /* don't set 100 percent valid
6537
             * because some of the sampled pixels were nodata */
6538
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6539
0
        }
6540
0
        else
6541
0
        {
6542
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6543
0
        }
6544
0
    }
6545
0
}
6546
6547
//! @endcond
6548
6549
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6550
6551
#ifdef __AVX2__
6552
6553
#define set1_ps _mm256_set1_ps
6554
#define loadu_ps _mm256_loadu_ps
6555
#define or_ps _mm256_or_ps
6556
#define min_ps _mm256_min_ps
6557
#define max_ps _mm256_max_ps
6558
#define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6559
#define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6560
#define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6561
#define movemask_ps _mm256_movemask_ps
6562
#define storeu_ps _mm256_storeu_ps
6563
#define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6564
#define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6565
6566
#define unpacklo_ps _mm256_unpacklo_ps
6567
#define castps_pd _mm256_castps_pd
6568
6569
inline __m256 dup_hi_ps(__m256 x)
6570
{
6571
    const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6572
    return _mm256_permutevar8x32_ps(x, idx);
6573
}
6574
6575
#define setzero_pd _mm256_setzero_pd
6576
#define set1_pd _mm256_set1_pd
6577
#define loadu_pd _mm256_loadu_pd
6578
#define or_pd _mm256_or_pd
6579
#define min_pd _mm256_min_pd
6580
#define max_pd _mm256_max_pd
6581
#define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6582
#define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6583
#define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6584
#define movemask_pd _mm256_movemask_pd
6585
#define add_pd _mm256_add_pd
6586
#define sub_pd _mm256_sub_pd
6587
#define mul_pd _mm256_mul_pd
6588
#define div_pd _mm256_div_pd
6589
#define storeu_pd _mm256_storeu_pd
6590
#define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6591
#define blendv_pd _mm256_blendv_pd
6592
#ifdef __FMA__
6593
#define fmadd_pd _mm256_fmadd_pd
6594
#else
6595
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6596
#endif
6597
6598
#else
6599
6600
0
#define set1_ps _mm_set1_ps
6601
0
#define loadu_ps _mm_loadu_ps
6602
0
#define or_ps _mm_or_ps
6603
0
#define min_ps _mm_min_ps
6604
0
#define max_ps _mm_max_ps
6605
0
#define cmpeq_ps _mm_cmpeq_ps
6606
0
#define cmpneq_ps _mm_cmpneq_ps
6607
0
#define cmpunord_ps _mm_cmpunord_ps
6608
0
#define movemask_ps _mm_movemask_ps
6609
0
#define storeu_ps _mm_storeu_ps
6610
0
#define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6611
0
#define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6612
0
#define unpacklo_ps _mm_unpacklo_ps
6613
0
#define castps_pd _mm_castps_pd
6614
0
#define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6615
6616
0
#define setzero_pd _mm_setzero_pd
6617
0
#define set1_pd _mm_set1_pd
6618
0
#define loadu_pd _mm_loadu_pd
6619
0
#define or_pd _mm_or_pd
6620
0
#define min_pd _mm_min_pd
6621
0
#define max_pd _mm_max_pd
6622
0
#define cmpeq_pd _mm_cmpeq_pd
6623
0
#define cmpneq_pd _mm_cmpneq_pd
6624
0
#define cmpunord_pd _mm_cmpunord_pd
6625
0
#define movemask_pd _mm_movemask_pd
6626
0
#define add_pd _mm_add_pd
6627
0
#define sub_pd _mm_sub_pd
6628
0
#define mul_pd _mm_mul_pd
6629
0
#define div_pd _mm_div_pd
6630
0
#define storeu_pd _mm_storeu_pd
6631
0
#define cvtsd_f64 _mm_cvtsd_f64
6632
#ifdef __FMA__
6633
#define fmadd_pd _mm_fmadd_pd
6634
#else
6635
0
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6636
#endif
6637
6638
inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6639
0
{
6640
#if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6641
    return _mm_blendv_pd(a, b, mask);
6642
#else
6643
0
    return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6644
0
#endif
6645
0
}
6646
#endif
6647
6648
0
#define dup_lo_ps(x) unpacklo_ps((x), (x))
6649
6650
/************************************************************************/
6651
/*                   ComputeStatisticsFloat32_SSE2()                    */
6652
/************************************************************************/
6653
6654
template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6655
#if defined(__GNUC__)
6656
__attribute__((noinline))
6657
#endif
6658
static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
6659
                                         [[maybe_unused]] float fNoDataValue,
6660
                                         int iX, int nCount, float &fMin,
6661
                                         float &fMax, double &dfBlockMean,
6662
                                         double &dfBlockM2,
6663
                                         double &dfBlockValidCount)
6664
0
{
6665
0
    auto vValidCount = setzero_pd();
6666
0
    const auto vOne = set1_pd(1);
6667
0
    [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6668
6669
0
    auto vMin = set1_ps(fMin);
6670
0
    auto vMax = set1_ps(fMax);
6671
6672
0
    auto vMean_lo = setzero_pd();
6673
0
    auto vM2_lo = setzero_pd();
6674
6675
0
    auto vMean_hi = setzero_pd();
6676
0
    auto vM2_hi = setzero_pd();
6677
6678
0
    constexpr int VALS_PER_LOOP =
6679
0
        static_cast<int>(sizeof(vOne) / sizeof(float));
6680
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6681
0
    {
6682
0
        const auto vValues = loadu_ps(pafData + iX);
6683
6684
        if constexpr (HAS_NAN)
6685
0
        {
6686
0
            auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6687
            if constexpr (HAS_NODATA)
6688
0
            {
6689
0
                isNaNOrNoData =
6690
0
                    or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6691
0
            }
6692
0
            if (movemask_ps(isNaNOrNoData))
6693
0
            {
6694
0
                break;
6695
0
            }
6696
        }
6697
        else if constexpr (HAS_NODATA)
6698
0
        {
6699
0
            if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6700
0
            {
6701
0
                break;
6702
0
            }
6703
0
        }
6704
6705
0
        vMin = min_ps(vMin, vValues);
6706
0
        vMax = max_ps(vMax, vValues);
6707
6708
0
        const auto vValues_lo = cvtps_lo_pd(vValues);
6709
0
        const auto vValues_hi = cvtps_hi_pd(vValues);
6710
0
        [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6711
6712
0
        vValidCount = add_pd(vValidCount, vOne);
6713
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6714
6715
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6716
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6717
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6718
0
        {
6719
0
            const auto vMinNotSameAsMax_lo =
6720
0
                castps_pd(dup_lo_ps(vMinNotSameAsMax));
6721
0
            vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6722
0
            const auto vNewM2_lo =
6723
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6724
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6725
        }
6726
        else
6727
0
        {
6728
0
            vMean_lo = vNewMean_lo;
6729
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6730
0
        }
6731
6732
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6733
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6734
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6735
0
        {
6736
0
            const auto vMinNotSameAsMax_hi =
6737
0
                castps_pd(dup_hi_ps(vMinNotSameAsMax));
6738
0
            vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6739
0
            const auto vNewM2_hi =
6740
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6741
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6742
        }
6743
        else
6744
0
        {
6745
0
            vMean_hi = vNewMean_hi;
6746
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6747
0
        }
6748
0
    }
6749
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6750
0
    if (dfValidVectorCount > 0)
6751
0
    {
6752
0
        float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6753
0
        storeu_ps(afMin, vMin);
6754
0
        storeu_ps(afMax, vMax);
6755
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6756
0
        {
6757
0
            fMin = std::min(fMin, afMin[i]);
6758
0
            fMax = std::max(fMax, afMax[i]);
6759
0
        }
6760
6761
0
        double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6762
0
        storeu_pd(adfMean, vMean_lo);
6763
0
        storeu_pd(adfM2, vM2_lo);
6764
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6765
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6766
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6767
0
        {
6768
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6769
0
            dfBlockM2 += adfM2[i];
6770
0
            if (adfMean[i] != dfBlockMean)
6771
0
            {
6772
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6773
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6774
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6775
0
                             dfValidVectorCount / dfNewValidCount;
6776
0
            }
6777
0
            dfBlockValidCount = dfNewValidCount;
6778
0
        }
6779
0
    }
6780
6781
0
    return iX;
6782
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&)
6783
6784
/************************************************************************/
6785
/*                   ComputeStatisticsFloat64_SSE2()                    */
6786
/************************************************************************/
6787
6788
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6789
#if defined(__GNUC__)
6790
__attribute__((noinline))
6791
#endif
6792
static int ComputeStatisticsFloat64_SSE2(const double *padfData,
6793
                                         [[maybe_unused]] double dfNoDataValue,
6794
                                         int iX, int nCount, double &dfMin,
6795
                                         double &dfMax, double &dfBlockMean,
6796
                                         double &dfBlockM2,
6797
                                         double &dfBlockValidCount)
6798
0
{
6799
0
    auto vValidCount = setzero_pd();
6800
0
    const auto vOne = set1_pd(1);
6801
0
    [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6802
6803
0
    auto vMin_lo = set1_pd(dfMin);
6804
0
    auto vMax_lo = set1_pd(dfMax);
6805
0
    auto vMean_lo = setzero_pd();
6806
0
    auto vM2_lo = setzero_pd();
6807
6808
0
    auto vMin_hi = vMin_lo;
6809
0
    auto vMax_hi = vMax_lo;
6810
0
    auto vMean_hi = setzero_pd();
6811
0
    auto vM2_hi = setzero_pd();
6812
6813
0
    constexpr int VALS_PER_LOOP =
6814
0
        2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6815
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6816
0
    {
6817
0
        const auto vValues_lo = loadu_pd(padfData + iX);
6818
0
        const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6819
        // Check if there's at least one NaN in both vectors
6820
0
        auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6821
        if constexpr (HAS_NODATA)
6822
0
        {
6823
0
            isNaNOrNoData =
6824
0
                or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6825
0
                                           cmpeq_pd(vValues_hi, vNoData)));
6826
0
        }
6827
0
        if (movemask_pd(isNaNOrNoData))
6828
0
        {
6829
0
            break;
6830
0
        }
6831
6832
0
        vValidCount = add_pd(vValidCount, vOne);
6833
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6834
6835
0
        vMin_lo = min_pd(vMin_lo, vValues_lo);
6836
0
        vMax_lo = max_pd(vMax_lo, vValues_lo);
6837
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6838
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6839
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6840
0
        {
6841
0
            const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6842
0
            vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6843
0
            const auto vNewM2_lo =
6844
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6845
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6846
        }
6847
        else
6848
0
        {
6849
0
            vMean_lo = vNewMean_lo;
6850
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6851
0
        }
6852
6853
0
        vMin_hi = min_pd(vMin_hi, vValues_hi);
6854
0
        vMax_hi = max_pd(vMax_hi, vValues_hi);
6855
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6856
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6857
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6858
0
        {
6859
0
            const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6860
0
            vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6861
0
            const auto vNewM2_hi =
6862
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6863
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6864
        }
6865
        else
6866
0
        {
6867
0
            vMean_hi = vNewMean_hi;
6868
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6869
0
        }
6870
0
    }
6871
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6872
0
    if (dfValidVectorCount > 0)
6873
0
    {
6874
0
        double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6875
0
            adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6876
0
        storeu_pd(adfMin, vMin_lo);
6877
0
        storeu_pd(adfMax, vMax_lo);
6878
0
        storeu_pd(adfMean, vMean_lo);
6879
0
        storeu_pd(adfM2, vM2_lo);
6880
0
        storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6881
0
        storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6882
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6883
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6884
6885
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6886
0
        {
6887
0
            dfMin = std::min(dfMin, adfMin[i]);
6888
0
            dfMax = std::max(dfMax, adfMax[i]);
6889
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6890
0
            dfBlockM2 += adfM2[i];
6891
0
            if (adfMean[i] != dfBlockMean)
6892
0
            {
6893
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6894
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6895
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6896
0
                             dfValidVectorCount / dfNewValidCount;
6897
0
            }
6898
0
            dfBlockValidCount = dfNewValidCount;
6899
0
        }
6900
0
    }
6901
6902
0
    return iX;
6903
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&)
6904
6905
#endif
6906
6907
/************************************************************************/
6908
/*                   ComputeBlockStatisticsFloat32()                    */
6909
/************************************************************************/
6910
6911
template <bool HAS_NAN, bool HAS_NODATA>
6912
static void ComputeBlockStatisticsFloat32(
6913
    const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6914
    const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6915
    float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6916
    double &dfBlockValidCountInOut)
6917
0
{
6918
0
    float fMin = fMinInOut;
6919
0
    float fMax = fMaxInOut;
6920
0
    double dfBlockMean = dfBlockMeanInOut;
6921
0
    double dfBlockM2 = dfBlockM2InOut;
6922
0
    double dfBlockValidCount = dfBlockValidCountInOut;
6923
6924
0
    for (int iY = 0; iY < nYCheck; iY++)
6925
0
    {
6926
0
        const int iOffset = iY * nBlockXSize;
6927
0
        if (dfBlockValidCount > 0 && fMin != fMax)
6928
0
        {
6929
0
            int iX = 0;
6930
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6931
0
            iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6932
0
                                               /* bCheckMinEqMax = */ false,
6933
0
                                               HAS_NODATA>(
6934
0
                pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6935
0
                fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6936
0
#endif
6937
0
            for (; iX < nXCheck; iX++)
6938
0
            {
6939
0
                const float fValue = pafSrcData[iOffset + iX];
6940
                if constexpr (HAS_NAN)
6941
0
                {
6942
0
                    if (std::isnan(fValue))
6943
0
                        continue;
6944
0
                }
6945
                if constexpr (HAS_NODATA)
6946
0
                {
6947
0
                    if (fValue == sNoDataValues.fNoDataValue)
6948
0
                        continue;
6949
0
                }
6950
0
                fMin = std::min(fMin, fValue);
6951
0
                fMax = std::max(fMax, fValue);
6952
0
                dfBlockValidCount += 1.0;
6953
0
                const double dfValue = static_cast<double>(fValue);
6954
0
                const double dfDelta = dfValue - dfBlockMean;
6955
0
                dfBlockMean += dfDelta / dfBlockValidCount;
6956
0
                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6957
0
            }
6958
0
        }
6959
0
        else
6960
0
        {
6961
0
            int iX = 0;
6962
0
            if (dfBlockValidCount == 0)
6963
0
            {
6964
0
                while (iX < nXCheck)
6965
0
                {
6966
0
                    const float fValue = pafSrcData[iOffset + iX];
6967
0
                    ++iX;
6968
                    if constexpr (HAS_NAN)
6969
0
                    {
6970
0
                        if (std::isnan(fValue))
6971
0
                            continue;
6972
0
                    }
6973
                    if constexpr (HAS_NODATA)
6974
0
                    {
6975
0
                        if (fValue == sNoDataValues.fNoDataValue)
6976
0
                            continue;
6977
0
                    }
6978
0
                    fMin = std::min(fMin, fValue);
6979
0
                    fMax = std::max(fMax, fValue);
6980
0
                    dfBlockValidCount = 1;
6981
0
                    dfBlockMean = static_cast<double>(fValue);
6982
0
                    break;
6983
0
                }
6984
0
            }
6985
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6986
0
            iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6987
0
                                               /* bCheckMinEqMax = */ true,
6988
0
                                               HAS_NODATA>(
6989
0
                pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6990
0
                fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6991
0
#endif
6992
0
            for (; iX < nXCheck; iX++)
6993
0
            {
6994
0
                const float fValue = pafSrcData[iOffset + iX];
6995
                if constexpr (HAS_NAN)
6996
0
                {
6997
0
                    if (std::isnan(fValue))
6998
0
                        continue;
6999
0
                }
7000
                if constexpr (HAS_NODATA)
7001
0
                {
7002
0
                    if (fValue == sNoDataValues.fNoDataValue)
7003
0
                        continue;
7004
0
                }
7005
0
                fMin = std::min(fMin, fValue);
7006
0
                fMax = std::max(fMax, fValue);
7007
0
                dfBlockValidCount += 1.0;
7008
0
                if (fMin != fMax)
7009
0
                {
7010
0
                    const double dfValue = static_cast<double>(fValue);
7011
0
                    const double dfDelta = dfValue - dfBlockMean;
7012
0
                    dfBlockMean += dfDelta / dfBlockValidCount;
7013
0
                    dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7014
0
                }
7015
0
            }
7016
0
        }
7017
0
    }
7018
7019
0
    fMinInOut = fMin;
7020
0
    fMaxInOut = fMax;
7021
0
    dfBlockMeanInOut = dfBlockMean;
7022
0
    dfBlockM2InOut = dfBlockM2;
7023
0
    dfBlockValidCountInOut = dfBlockValidCount;
7024
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&)
7025
7026
/************************************************************************/
7027
/*                        StatisticsTaskFloat32                         */
7028
/************************************************************************/
7029
7030
namespace
7031
{
7032
struct StatisticsTaskFloat32
7033
{
7034
    double dfBlockMean = 0;
7035
    double dfBlockM2 = 0;
7036
    double dfBlockValidCount = 0;
7037
    GDALDataType eDataType = GDT_Unknown;
7038
    bool bHasNoData = false;
7039
    GDALNoDataValues *psNoDataValues = nullptr;
7040
    const float *pafSrcData = nullptr;
7041
    float fMin = std::numeric_limits<float>::infinity();
7042
    float fMax = -std::numeric_limits<float>::infinity();
7043
    int nChunkXSize = 0;
7044
    int nXCheck = 0;
7045
    int nYCheck = 0;
7046
7047
    void Perform()
7048
0
    {
7049
0
        if (GDALDataTypeIsInteger(eDataType))
7050
0
        {
7051
0
            if (bHasNoData)
7052
0
            {
7053
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7054
0
                                              /* HAS_NODATA = */ true>(
7055
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7056
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7057
0
            }
7058
0
            else
7059
0
            {
7060
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7061
0
                                              /* HAS_NODATA = */ false>(
7062
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7063
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7064
0
            }
7065
0
        }
7066
0
        else
7067
0
        {
7068
0
            if (bHasNoData)
7069
0
            {
7070
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7071
0
                                              /* HAS_NODATA = */ true>(
7072
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7073
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7074
0
            }
7075
0
            else
7076
0
            {
7077
0
                ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7078
0
                                              /* HAS_NODATA = */ false>(
7079
0
                    pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7080
0
                    fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7081
0
            }
7082
0
        }
7083
0
    }
7084
};
7085
}  // namespace
7086
7087
/************************************************************************/
7088
/*                         ComputeStatistics()                          */
7089
/************************************************************************/
7090
7091
/**
7092
 * \brief Compute image statistics.
7093
 *
7094
 * Returns the minimum, maximum, mean and standard deviation of all
7095
 * pixel values in this band.  If approximate statistics are sufficient,
7096
 * the bApproxOK flag can be set to true in which case overviews, or a
7097
 * subset of image tiles may be used in computing the statistics.
7098
 *
7099
 * Once computed, the statistics will generally be "set" back on the
7100
 * raster band using SetStatistics().
7101
 *
7102
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7103
 *
7104
 * This method is the same as the C function GDALComputeRasterStatistics().
7105
 *
7106
 * @param bApproxOK If TRUE statistics may be computed based on overviews
7107
 * or a subset of all tiles.
7108
 *
7109
 * @param pdfMin Location into which to load image minimum (may be NULL).
7110
 *
7111
 * @param pdfMax Location into which to load image maximum (may be NULL).-
7112
 *
7113
 * @param pdfMean Location into which to load image mean (may be NULL).
7114
 *
7115
 * @param pdfStdDev Location into which to load image standard deviation
7116
 * (may be NULL).
7117
 *
7118
 * @param pfnProgress a function to call to report progress, or NULL.
7119
 *
7120
 * @param pProgressData application data to pass to the progress function.
7121
 *
7122
 * @return CE_None on success, or CE_Failure if an error occurs or processing
7123
 * is terminated by the user.
7124
 */
7125
7126
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7127
                                         double *pdfMax, double *pdfMean,
7128
                                         double *pdfStdDev,
7129
                                         GDALProgressFunc pfnProgress,
7130
                                         void *pProgressData)
7131
7132
0
{
7133
0
    if (pfnProgress == nullptr)
7134
0
        pfnProgress = GDALDummyProgress;
7135
7136
    /* -------------------------------------------------------------------- */
7137
    /*      If we have overview bands, use them for statistics.             */
7138
    /* -------------------------------------------------------------------- */
7139
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7140
0
    {
7141
0
        GDALRasterBand *poBand =
7142
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7143
7144
0
        if (poBand != this)
7145
0
        {
7146
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
7147
0
                                                    pdfMean, pdfStdDev,
7148
0
                                                    pfnProgress, pProgressData);
7149
0
            if (eErr == CE_None)
7150
0
            {
7151
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7152
0
                {
7153
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7154
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7155
0
                }
7156
7157
                /* transfer metadata from overview band to this */
7158
0
                const char *pszPercentValid =
7159
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7160
7161
0
                if (pszPercentValid != nullptr)
7162
0
                {
7163
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
7164
0
                                    pszPercentValid);
7165
0
                }
7166
0
            }
7167
0
            return eErr;
7168
0
        }
7169
0
    }
7170
7171
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7172
0
    {
7173
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7174
0
        return CE_Failure;
7175
0
    }
7176
7177
    /* -------------------------------------------------------------------- */
7178
    /*      Read actual data and compute statistics.                        */
7179
    /* -------------------------------------------------------------------- */
7180
    // Using Welford algorithm:
7181
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7182
    // to compute standard deviation in a more numerically robust way than
7183
    // the difference of the sum of square values with the square of the sum.
7184
    // dfMean and dfM2 are updated at each sample.
7185
    // dfM2 is the sum of square of differences to the current mean.
7186
0
    double dfMin = std::numeric_limits<double>::infinity();
7187
0
    double dfMax = -std::numeric_limits<double>::infinity();
7188
0
    double dfMean = 0.0;
7189
0
    double dfM2 = 0.0;
7190
7191
0
    GDALRasterIOExtraArg sExtraArg;
7192
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7193
7194
0
    GDALNoDataValues sNoDataValues(this, eDataType);
7195
0
    GDALRasterBand *poMaskBand = nullptr;
7196
0
    if (!sNoDataValues.bGotNoDataValue)
7197
0
    {
7198
0
        const int l_nMaskFlags = GetMaskFlags();
7199
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
7200
0
            GetColorInterpretation() != GCI_AlphaBand)
7201
0
        {
7202
0
            poMaskBand = GetMaskBand();
7203
0
        }
7204
0
    }
7205
7206
0
    bool bSignedByte = false;
7207
0
    if (eDataType == GDT_UInt8)
7208
0
    {
7209
0
        EnablePixelTypeSignedByteWarning(false);
7210
0
        const char *pszPixelType =
7211
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7212
0
        EnablePixelTypeSignedByteWarning(true);
7213
0
        bSignedByte =
7214
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7215
0
    }
7216
7217
0
    GUIntBig nSampleCount = 0;
7218
0
    GUIntBig nValidCount = 0;
7219
7220
0
    if (bApproxOK && HasArbitraryOverviews())
7221
0
    {
7222
        /* --------------------------------------------------------------------
7223
         */
7224
        /*      Figure out how much the image should be reduced to get an */
7225
        /*      approximate value. */
7226
        /* --------------------------------------------------------------------
7227
         */
7228
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7229
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7230
7231
0
        int nXReduced = nRasterXSize;
7232
0
        int nYReduced = nRasterYSize;
7233
0
        if (dfReduction > 1.0)
7234
0
        {
7235
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7236
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7237
7238
            // Catch the case of huge resizing ratios here
7239
0
            if (nXReduced == 0)
7240
0
                nXReduced = 1;
7241
0
            if (nYReduced == 0)
7242
0
                nYReduced = 1;
7243
0
        }
7244
7245
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
7246
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7247
7248
0
        const CPLErr eErr =
7249
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7250
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7251
0
        if (eErr != CE_None)
7252
0
        {
7253
0
            CPLFree(pData);
7254
0
            return eErr;
7255
0
        }
7256
7257
0
        GByte *pabyMaskData = nullptr;
7258
0
        if (poMaskBand)
7259
0
        {
7260
0
            pabyMaskData =
7261
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7262
0
            if (!pabyMaskData)
7263
0
            {
7264
0
                CPLFree(pData);
7265
0
                return CE_Failure;
7266
0
            }
7267
7268
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7269
0
                                     pabyMaskData, nXReduced, nYReduced,
7270
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
7271
0
            {
7272
0
                CPLFree(pData);
7273
0
                CPLFree(pabyMaskData);
7274
0
                return CE_Failure;
7275
0
            }
7276
0
        }
7277
7278
        /* this isn't the fastest way to do this, but is easier for now */
7279
0
        for (int iY = 0; iY < nYReduced; iY++)
7280
0
        {
7281
0
            for (int iX = 0; iX < nXReduced; iX++)
7282
0
            {
7283
0
                const int iOffset = iX + iY * nXReduced;
7284
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7285
0
                    continue;
7286
7287
0
                bool bValid = true;
7288
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7289
0
                                               iOffset, sNoDataValues, bValid);
7290
0
                if (!bValid)
7291
0
                    continue;
7292
7293
0
                dfMin = std::min(dfMin, dfValue);
7294
0
                dfMax = std::max(dfMax, dfValue);
7295
7296
0
                nValidCount++;
7297
0
                if (dfMin == dfMax)
7298
0
                {
7299
0
                    if (nValidCount == 1)
7300
0
                        dfMean = dfMin;
7301
0
                }
7302
0
                else
7303
0
                {
7304
0
                    const double dfDelta = dfValue - dfMean;
7305
0
                    dfMean += dfDelta / nValidCount;
7306
0
                    dfM2 += dfDelta * (dfValue - dfMean);
7307
0
                }
7308
0
            }
7309
0
        }
7310
7311
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7312
7313
0
        CPLFree(pData);
7314
0
        CPLFree(pabyMaskData);
7315
0
    }
7316
7317
0
    else  // No arbitrary overviews.
7318
0
    {
7319
0
        if (!InitBlockInfo())
7320
0
            return CE_Failure;
7321
7322
        /* --------------------------------------------------------------------
7323
         */
7324
        /*      Figure out the ratio of blocks we will read to get an */
7325
        /*      approximate value. */
7326
        /* --------------------------------------------------------------------
7327
         */
7328
0
        int nSampleRate = 1;
7329
0
        if (bApproxOK)
7330
0
        {
7331
0
            nSampleRate = static_cast<int>(std::max(
7332
0
                1.0,
7333
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7334
            // We want to avoid probing only the first column of blocks for
7335
            // a square shaped raster, because it is not unlikely that it may
7336
            // be padding only (#6378)
7337
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7338
0
                nSampleRate += 1;
7339
0
        }
7340
0
        if (nSampleRate == 1)
7341
0
            bApproxOK = false;
7342
7343
        // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7344
        // for each block, and possibly for the whole raster.
7345
0
        if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7346
0
                            eDataType == GDT_UInt16))
7347
0
        {
7348
            // We can do integer computation on the whole raster in the Byte case
7349
            // only if the number of pixels explored is lower than
7350
            // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7351
            // Should be 99.99999% of cases.
7352
            // For GUInt16, this limits to raster of 4 giga pixels
7353
7354
0
            const bool bIntegerStats =
7355
0
                ((eDataType == GDT_UInt8 &&
7356
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7357
0
                          nSampleRate <
7358
0
                      GUINTBIG_MAX / (255U * 255U) /
7359
0
                          (static_cast<GUInt64>(nBlockXSize) *
7360
0
                           static_cast<GUInt64>(nBlockYSize))) ||
7361
0
                 (eDataType == GDT_UInt16 &&
7362
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7363
0
                          nSampleRate <
7364
0
                      GUINTBIG_MAX / (65535U * 65535U) /
7365
0
                          (static_cast<GUInt64>(nBlockXSize) *
7366
0
                           static_cast<GUInt64>(nBlockYSize)))) &&
7367
                // Can be set to NO for easier debugging of the !bIntegerStats
7368
                // case which requires huge rasters to trigger
7369
0
                CPLTestBool(
7370
0
                    CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7371
7372
0
            const GUInt32 nMaxValueType =
7373
0
                (eDataType == GDT_UInt8) ? 255 : 65535;
7374
0
            GUInt32 nMin = nMaxValueType;
7375
0
            GUInt32 nMax = 0;
7376
0
            GUIntBig nSum = 0;
7377
0
            GUIntBig nSumSquare = 0;
7378
            // If no valid nodata, map to invalid value (256 for Byte)
7379
0
            const GUInt32 nNoDataValue =
7380
0
                (sNoDataValues.bGotNoDataValue &&
7381
0
                 sNoDataValues.dfNoDataValue >= 0 &&
7382
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
7383
0
                 fabs(sNoDataValues.dfNoDataValue -
7384
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7385
0
                                           1e-10)) < 1e-10)
7386
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7387
0
                    : nMaxValueType + 1;
7388
7389
0
            int nChunkXSize = nBlockXSize;
7390
0
            int nChunkYSize = nBlockYSize;
7391
0
            int nChunksPerRow = nBlocksPerRow;
7392
0
            int nChunksPerCol = nBlocksPerColumn;
7393
7394
0
            int nThreads = 1;
7395
0
            if (nChunkYSize > 1)
7396
0
            {
7397
0
                nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7398
0
                                             /* bDefaultToAllCPUs = */ false);
7399
0
            }
7400
7401
0
            int nNewChunkXSize = nChunkXSize;
7402
0
            const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
7403
0
            if (!bApproxOK && nThreads > 1 &&
7404
0
                MayMultiBlockReadingBeMultiThreaded())
7405
0
            {
7406
0
                const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7407
0
                const size_t nChunkPixels =
7408
0
                    static_cast<size_t>(nChunkXSize) * nChunkYSize;
7409
0
                if (nRAMAmount > 0 &&
7410
0
                    nChunkPixels <=
7411
0
                        std::numeric_limits<size_t>::max() / nDTSize)
7412
0
                {
7413
0
                    const size_t nBlockSize = nDTSize * nChunkPixels;
7414
0
                    const int64_t nBlockCount = nRAMAmount / nBlockSize;
7415
0
                    if (nBlockCount >= 2)
7416
0
                    {
7417
0
                        nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7418
0
                            nChunkXSize * std::min<int64_t>(
7419
0
                                              nBlockCount,
7420
0
                                              (std::numeric_limits<int>::max() -
7421
0
                                               ALIGNMENT_AVX2_OPTIM) /
7422
0
                                                  nChunkPixels),
7423
0
                            nRasterXSize));
7424
7425
0
                        CPLAssert(nChunkXSize <
7426
0
                                  std::numeric_limits<int>::max() /
7427
0
                                      nChunkYSize);
7428
0
                    }
7429
0
                }
7430
0
            }
7431
7432
0
            std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
7433
0
            GByte *pabyTemp = nullptr;
7434
0
            if (nNewChunkXSize != nBlockXSize)
7435
0
            {
7436
0
                pabyTempUnaligned.reset(static_cast<GByte *>(
7437
0
                    VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
7438
0
                              ALIGNMENT_AVX2_OPTIM)));
7439
0
                if (pabyTempUnaligned)
7440
0
                {
7441
0
                    pabyTemp = reinterpret_cast<GByte *>(
7442
0
                        reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
7443
0
                        (ALIGNMENT_AVX2_OPTIM -
7444
0
                         (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
7445
0
                          ALIGNMENT_AVX2_OPTIM)));
7446
0
                    nChunkXSize = nNewChunkXSize;
7447
0
                    nChunksPerRow =
7448
0
                        cpl::div_round_up(nRasterXSize, nChunkXSize);
7449
0
                }
7450
0
            }
7451
7452
0
            for (GIntBig iSampleBlock = 0;
7453
0
                 iSampleBlock <
7454
0
                 static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7455
0
                 iSampleBlock += nSampleRate)
7456
0
            {
7457
0
                const int iYBlock =
7458
0
                    static_cast<int>(iSampleBlock / nChunksPerRow);
7459
0
                const int iXBlock =
7460
0
                    static_cast<int>(iSampleBlock % nChunksPerRow);
7461
7462
0
                const int nXCheck =
7463
0
                    std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7464
0
                const int nYCheck =
7465
0
                    std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7466
7467
0
                GDALRasterBlock *poBlock = nullptr;
7468
0
                if (pabyTemp)
7469
0
                {
7470
0
                    if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7471
0
                                 iYBlock * nChunkYSize, nXCheck, nYCheck,
7472
0
                                 pabyTemp, nXCheck, nYCheck, eDataType, 0,
7473
0
                                 static_cast<GSpacing>(nChunkXSize) * nDTSize,
7474
0
                                 nullptr) != CE_None)
7475
0
                    {
7476
0
                        return CE_Failure;
7477
0
                    }
7478
0
                }
7479
0
                else
7480
0
                {
7481
0
                    poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7482
0
                    if (poBlock == nullptr)
7483
0
                    {
7484
0
                        return CE_Failure;
7485
0
                    }
7486
0
                }
7487
7488
0
                const void *const pData =
7489
0
                    poBlock ? poBlock->GetDataRef() : pabyTemp;
7490
7491
0
                GUIntBig nBlockSum = 0;
7492
0
                GUIntBig nBlockSumSquare = 0;
7493
0
                GUIntBig nBlockSampleCount = 0;
7494
0
                GUIntBig nBlockValidCount = 0;
7495
0
                GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7496
0
                GUIntBig &nBlockSumSquareRef =
7497
0
                    bIntegerStats ? nSumSquare : nBlockSumSquare;
7498
0
                GUIntBig &nBlockSampleCountRef =
7499
0
                    bIntegerStats ? nSampleCount : nBlockSampleCount;
7500
0
                GUIntBig &nBlockValidCountRef =
7501
0
                    bIntegerStats ? nValidCount : nBlockValidCount;
7502
7503
0
                if (eDataType == GDT_UInt8)
7504
0
                {
7505
0
                    ComputeStatisticsInternal<
7506
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
7507
0
                        f(nXCheck, nChunkXSize, nYCheck,
7508
0
                          static_cast<const GByte *>(pData),
7509
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7510
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7511
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7512
0
                }
7513
0
                else
7514
0
                {
7515
0
                    ComputeStatisticsInternal<
7516
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7517
0
                        f(nXCheck, nChunkXSize, nYCheck,
7518
0
                          static_cast<const GUInt16 *>(pData),
7519
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7520
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7521
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7522
0
                }
7523
7524
0
                if (poBlock)
7525
0
                    poBlock->DropLock();
7526
7527
0
                if (!bIntegerStats)
7528
0
                {
7529
0
                    nSampleCount += nBlockSampleCount;
7530
0
                    if (nBlockValidCount)
7531
0
                    {
7532
                        // Update the global mean and M2 (the difference of the
7533
                        // square to the mean) from the values of the block
7534
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7535
0
                        const double dfBlockValidCount =
7536
0
                            static_cast<double>(nBlockValidCount);
7537
0
                        const double dfBlockMean =
7538
0
                            static_cast<double>(nBlockSum) / dfBlockValidCount;
7539
0
                        const double dfBlockM2 =
7540
0
                            static_cast<double>(
7541
0
                                GDALUInt128::Mul(nBlockSumSquare,
7542
0
                                                 nBlockValidCount) -
7543
0
                                GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7544
0
                            dfBlockValidCount;
7545
0
                        const double dfDelta = dfBlockMean - dfMean;
7546
0
                        const auto nNewValidCount =
7547
0
                            nValidCount + nBlockValidCount;
7548
0
                        const double dfNewValidCount =
7549
0
                            static_cast<double>(nNewValidCount);
7550
0
                        dfMean +=
7551
0
                            dfDelta * (dfBlockValidCount / dfNewValidCount);
7552
0
                        dfM2 +=
7553
0
                            dfBlockM2 + dfDelta * dfDelta *
7554
0
                                            static_cast<double>(nValidCount) *
7555
0
                                            dfBlockValidCount / dfNewValidCount;
7556
0
                        nValidCount = nNewValidCount;
7557
0
                    }
7558
0
                }
7559
7560
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
7561
0
                                     (static_cast<double>(nChunksPerRow) *
7562
0
                                      nChunksPerCol),
7563
0
                                 "Compute Statistics", pProgressData))
7564
0
                {
7565
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
7566
0
                                "User terminated");
7567
0
                    return CE_Failure;
7568
0
                }
7569
0
            }
7570
7571
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7572
0
            {
7573
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7574
0
                return CE_Failure;
7575
0
            }
7576
7577
0
            double dfStdDev = 0;
7578
0
            if (bIntegerStats)
7579
0
            {
7580
0
                if (nValidCount)
7581
0
                    dfMean = static_cast<double>(nSum) / nValidCount;
7582
7583
                // To avoid potential precision issues when doing the difference,
7584
                // we need to do that computation on 128 bit rather than casting
7585
                // to double
7586
0
                const GDALUInt128 nTmpForStdDev(
7587
0
                    GDALUInt128::Mul(nSumSquare, nValidCount) -
7588
0
                    GDALUInt128::Mul(nSum, nSum));
7589
0
                dfStdDev =
7590
0
                    nValidCount > 0
7591
0
                        ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7592
0
                        : 0.0;
7593
0
            }
7594
0
            else if (nValidCount > 0)
7595
0
            {
7596
0
                dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7597
0
            }
7598
7599
            /// Save computed information
7600
0
            if (nValidCount > 0)
7601
0
            {
7602
0
                if (bApproxOK)
7603
0
                {
7604
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7605
0
                }
7606
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7607
0
                {
7608
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7609
0
                }
7610
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
7611
0
            }
7612
7613
0
            SetValidPercent(nSampleCount, nValidCount);
7614
7615
            /* --------------------------------------------------------------------
7616
             */
7617
            /*      Record results. */
7618
            /* --------------------------------------------------------------------
7619
             */
7620
0
            if (pdfMin != nullptr)
7621
0
                *pdfMin = nValidCount ? nMin : 0;
7622
0
            if (pdfMax != nullptr)
7623
0
                *pdfMax = nValidCount ? nMax : 0;
7624
7625
0
            if (pdfMean != nullptr)
7626
0
                *pdfMean = dfMean;
7627
7628
0
            if (pdfStdDev != nullptr)
7629
0
                *pdfStdDev = dfStdDev;
7630
7631
0
            if (nValidCount > 0)
7632
0
                return CE_None;
7633
7634
0
            ReportError(CE_Failure, CPLE_AppDefined,
7635
0
                        "Failed to compute statistics, no valid pixels found "
7636
0
                        "in sampling.");
7637
0
            return CE_Failure;
7638
0
        }
7639
7640
0
        GByte *pabyMaskData = nullptr;
7641
0
        if (poMaskBand)
7642
0
        {
7643
0
            pabyMaskData = static_cast<GByte *>(
7644
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7645
0
            if (!pabyMaskData)
7646
0
            {
7647
0
                return CE_Failure;
7648
0
            }
7649
0
        }
7650
7651
0
        float fMin = std::numeric_limits<float>::infinity();
7652
0
        float fMax = -std::numeric_limits<float>::infinity();
7653
0
        bool bFloat32Optim =
7654
0
            (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7655
0
             eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7656
0
            !pabyMaskData &&
7657
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7658
0
            CPLTestBool(
7659
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7660
0
        std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7661
7662
0
        int nChunkXSize = nBlockXSize;
7663
0
        int nChunkYSize = nBlockYSize;
7664
0
        int nChunksPerRow = nBlocksPerRow;
7665
0
        int nChunksPerCol = nBlocksPerColumn;
7666
7667
0
#define nBlockXSize use_nChunkXSize_instead
7668
0
#define nBlockYSize use_nChunkYSize_instead
7669
0
#define nBlocksPerRow use_nChunksPerRow_instead
7670
0
#define nBlocksPerColumn use_nChunksPerCol_instead
7671
7672
0
        int nThreads = 1;
7673
0
        CPLWorkerThreadPool *psThreadPool = nullptr;
7674
0
        if (bFloat32Optim)
7675
0
        {
7676
0
            if (nChunkYSize > 1)
7677
0
            {
7678
0
                nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7679
0
                                             /* bDefaultToAllCPUs = */ false);
7680
0
            }
7681
7682
0
            int nNewChunkXSize = nChunkXSize;
7683
0
            if (!bApproxOK && nThreads > 1 &&
7684
0
                MayMultiBlockReadingBeMultiThreaded())
7685
0
            {
7686
0
                const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7687
0
                const size_t nChunkPixels =
7688
0
                    static_cast<size_t>(nChunkXSize) * nChunkYSize;
7689
0
                if (nRAMAmount > 0 &&
7690
0
                    nChunkPixels <=
7691
0
                        std::numeric_limits<size_t>::max() / sizeof(float))
7692
0
                {
7693
0
                    const size_t nBlockSizeAsFloat32 =
7694
0
                        sizeof(float) * nChunkPixels;
7695
0
                    const int64_t nBlockCount =
7696
0
                        nRAMAmount / nBlockSizeAsFloat32;
7697
0
                    if (nBlockCount >= 2)
7698
0
                    {
7699
0
                        nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7700
0
                            nChunkXSize * std::min<int64_t>(
7701
0
                                              nBlockCount,
7702
0
                                              std::numeric_limits<int>::max() /
7703
0
                                                  nChunkPixels),
7704
0
                            nRasterXSize));
7705
7706
0
                        CPLAssert(nChunkXSize <
7707
0
                                  std::numeric_limits<int>::max() /
7708
0
                                      nChunkYSize);
7709
0
                    }
7710
0
                }
7711
0
            }
7712
0
            if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7713
0
            {
7714
0
                pafTemp.reset(static_cast<float *>(
7715
0
                    VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7716
0
                bFloat32Optim = pafTemp != nullptr;
7717
0
                if (bFloat32Optim)
7718
0
                {
7719
0
                    nChunkXSize = nNewChunkXSize;
7720
0
                    nChunksPerRow =
7721
0
                        cpl::div_round_up(nRasterXSize, nChunkXSize);
7722
0
                }
7723
0
            }
7724
0
            CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7725
0
                     nChunkXSize, nChunkYSize);
7726
0
        }
7727
7728
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7729
0
        const bool bFloat64Optim =
7730
0
            eDataType == GDT_Float64 && !pabyMaskData &&
7731
0
            nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7732
0
            CPLTestBool(
7733
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7734
0
#endif
7735
7736
0
        std::vector<StatisticsTaskFloat32> tasksFloat32;
7737
7738
0
        for (GIntBig iSampleBlock = 0;
7739
0
             iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7740
0
             iSampleBlock += nSampleRate)
7741
0
        {
7742
0
            const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7743
0
            const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7744
7745
0
            const int nXCheck =
7746
0
                std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7747
0
            const int nYCheck =
7748
0
                std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7749
7750
0
            if (poMaskBand &&
7751
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7752
0
                                     iYBlock * nChunkYSize, nXCheck, nYCheck,
7753
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7754
0
                                     0, nChunkXSize, nullptr) != CE_None)
7755
0
            {
7756
0
                CPLFree(pabyMaskData);
7757
0
                return CE_Failure;
7758
0
            }
7759
7760
0
            GDALRasterBlock *poBlock = nullptr;
7761
0
            if (pafTemp)
7762
0
            {
7763
0
                if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7764
0
                             iYBlock * nChunkYSize, nXCheck, nYCheck,
7765
0
                             pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7766
0
                             static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7767
0
                             nullptr) != CE_None)
7768
0
                {
7769
0
                    CPLFree(pabyMaskData);
7770
0
                    return CE_Failure;
7771
0
                }
7772
0
            }
7773
0
            else
7774
0
            {
7775
0
                poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7776
0
                if (poBlock == nullptr)
7777
0
                {
7778
0
                    CPLFree(pabyMaskData);
7779
0
                    return CE_Failure;
7780
0
                }
7781
0
            }
7782
7783
0
            const void *const pData =
7784
0
                poBlock ? poBlock->GetDataRef() : pafTemp.get();
7785
7786
0
            if (bFloat32Optim)
7787
0
            {
7788
0
                const float *const pafSrcData =
7789
0
                    static_cast<const float *>(pData);
7790
7791
0
                const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7792
0
                                        !std::isnan(sNoDataValues.fNoDataValue);
7793
0
                const int nTasks = std::min(nYCheck, nThreads);
7794
0
                const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7795
0
                tasksFloat32.clear();
7796
0
                for (int i = 0; i < nTasks; ++i)
7797
0
                {
7798
0
                    StatisticsTaskFloat32 task;
7799
0
                    task.eDataType = eDataType;
7800
0
                    task.bHasNoData = bHasNoData;
7801
0
                    task.psNoDataValues = &sNoDataValues;
7802
0
                    task.nChunkXSize = nChunkXSize;
7803
0
                    task.fMin = fMin;
7804
0
                    task.fMax = fMax;
7805
0
                    task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7806
0
                                                       nRowsPerTask *
7807
0
                                                       nChunkXSize;
7808
0
                    task.nXCheck = nXCheck;
7809
0
                    task.nYCheck =
7810
0
                        std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7811
0
                    tasksFloat32.emplace_back(std::move(task));
7812
0
                }
7813
0
                if (psThreadPool)
7814
0
                {
7815
0
                    auto poJobQueue = psThreadPool->CreateJobQueue();
7816
0
                    for (auto &task : tasksFloat32)
7817
0
                    {
7818
0
                        poJobQueue->SubmitJob([&task]() { task.Perform(); });
7819
0
                    }
7820
0
                    poJobQueue->WaitCompletion();
7821
0
                }
7822
0
                else
7823
0
                {
7824
0
                    tasksFloat32[0].Perform();
7825
0
                }
7826
7827
0
                for (const auto &task : tasksFloat32)
7828
0
                {
7829
0
                    if (task.dfBlockValidCount > 0)
7830
0
                    {
7831
0
                        fMin = std::min(fMin, task.fMin);
7832
0
                        fMax = std::max(fMax, task.fMax);
7833
7834
                        // Update the global mean and M2 (the difference of the
7835
                        // square to the mean) from the values of the block
7836
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7837
0
                        const auto nNewValidCount =
7838
0
                            nValidCount +
7839
0
                            static_cast<int>(task.dfBlockValidCount);
7840
0
                        dfM2 += task.dfBlockM2;
7841
0
                        if (task.dfBlockMean != dfMean)
7842
0
                        {
7843
0
                            if (nValidCount == 0)
7844
0
                            {
7845
0
                                dfMean = task.dfBlockMean;
7846
0
                            }
7847
0
                            else
7848
0
                            {
7849
0
                                const double dfDelta =
7850
0
                                    task.dfBlockMean - dfMean;
7851
0
                                const double dfNewValidCount =
7852
0
                                    static_cast<double>(nNewValidCount);
7853
0
                                dfMean += dfDelta * (task.dfBlockValidCount /
7854
0
                                                     dfNewValidCount);
7855
0
                                dfM2 += dfDelta * dfDelta *
7856
0
                                        static_cast<double>(nValidCount) *
7857
0
                                        task.dfBlockValidCount /
7858
0
                                        dfNewValidCount;
7859
0
                            }
7860
0
                        }
7861
0
                        nValidCount = nNewValidCount;
7862
0
                    }
7863
0
                }
7864
0
            }
7865
7866
0
#if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7867
0
            else if (bFloat64Optim)
7868
0
            {
7869
0
                const bool bHasNoData =
7870
0
                    sNoDataValues.bGotNoDataValue &&
7871
0
                    !std::isnan(sNoDataValues.dfNoDataValue);
7872
0
                double dfBlockMean = 0;
7873
0
                double dfBlockM2 = 0;
7874
0
                double dfBlockValidCount = 0;
7875
0
                for (int iY = 0; iY < nYCheck; iY++)
7876
0
                {
7877
0
                    const int iOffset = iY * nChunkXSize;
7878
0
                    if (dfBlockValidCount != 0 && dfMin != dfMax)
7879
0
                    {
7880
0
                        int iX = 0;
7881
0
                        if (bHasNoData)
7882
0
                        {
7883
0
                            iX = ComputeStatisticsFloat64_SSE2<
7884
0
                                /* bCheckMinEqMax = */ false,
7885
0
                                /* bHasNoData = */ true>(
7886
0
                                static_cast<const double *>(pData) + iOffset,
7887
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7888
0
                                dfMax, dfBlockMean, dfBlockM2,
7889
0
                                dfBlockValidCount);
7890
0
                        }
7891
0
                        else
7892
0
                        {
7893
0
                            iX = ComputeStatisticsFloat64_SSE2<
7894
0
                                /* bCheckMinEqMax = */ false,
7895
0
                                /* bHasNoData = */ false>(
7896
0
                                static_cast<const double *>(pData) + iOffset,
7897
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7898
0
                                dfMax, dfBlockMean, dfBlockM2,
7899
0
                                dfBlockValidCount);
7900
0
                        }
7901
0
                        for (; iX < nXCheck; iX++)
7902
0
                        {
7903
0
                            const double dfValue = static_cast<const double *>(
7904
0
                                pData)[iOffset + iX];
7905
0
                            if (std::isnan(dfValue) ||
7906
0
                                (bHasNoData &&
7907
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7908
0
                                continue;
7909
0
                            dfMin = std::min(dfMin, dfValue);
7910
0
                            dfMax = std::max(dfMax, dfValue);
7911
0
                            dfBlockValidCount += 1.0;
7912
0
                            const double dfDelta = dfValue - dfBlockMean;
7913
0
                            dfBlockMean += dfDelta / dfBlockValidCount;
7914
0
                            dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7915
0
                        }
7916
0
                    }
7917
0
                    else
7918
0
                    {
7919
0
                        int iX = 0;
7920
0
                        if (dfBlockValidCount == 0)
7921
0
                        {
7922
0
                            for (; iX < nXCheck; iX++)
7923
0
                            {
7924
0
                                const double dfValue =
7925
0
                                    static_cast<const double *>(
7926
0
                                        pData)[iOffset + iX];
7927
0
                                if (std::isnan(dfValue) ||
7928
0
                                    (bHasNoData &&
7929
0
                                     dfValue == sNoDataValues.dfNoDataValue))
7930
0
                                    continue;
7931
0
                                dfMin = std::min(dfMin, dfValue);
7932
0
                                dfMax = std::max(dfMax, dfValue);
7933
0
                                dfBlockValidCount = 1;
7934
0
                                dfBlockMean = dfValue;
7935
0
                                iX++;
7936
0
                                break;
7937
0
                            }
7938
0
                        }
7939
0
                        if (bHasNoData)
7940
0
                        {
7941
0
                            iX = ComputeStatisticsFloat64_SSE2<
7942
0
                                /* bCheckMinEqMax = */ true,
7943
0
                                /* bHasNoData = */ true>(
7944
0
                                static_cast<const double *>(pData) + iOffset,
7945
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7946
0
                                dfMax, dfBlockMean, dfBlockM2,
7947
0
                                dfBlockValidCount);
7948
0
                        }
7949
0
                        else
7950
0
                        {
7951
0
                            iX = ComputeStatisticsFloat64_SSE2<
7952
0
                                /* bCheckMinEqMax = */ true,
7953
0
                                /* bHasNoData = */ false>(
7954
0
                                static_cast<const double *>(pData) + iOffset,
7955
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7956
0
                                dfMax, dfBlockMean, dfBlockM2,
7957
0
                                dfBlockValidCount);
7958
0
                        }
7959
0
                        for (; iX < nXCheck; iX++)
7960
0
                        {
7961
0
                            const double dfValue = static_cast<const double *>(
7962
0
                                pData)[iOffset + iX];
7963
0
                            if (std::isnan(dfValue) ||
7964
0
                                (bHasNoData &&
7965
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7966
0
                                continue;
7967
0
                            dfMin = std::min(dfMin, dfValue);
7968
0
                            dfMax = std::max(dfMax, dfValue);
7969
0
                            dfBlockValidCount += 1.0;
7970
0
                            if (dfMin != dfMax)
7971
0
                            {
7972
0
                                const double dfDelta = dfValue - dfBlockMean;
7973
0
                                dfBlockMean += dfDelta / dfBlockValidCount;
7974
0
                                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7975
0
                            }
7976
0
                        }
7977
0
                    }
7978
0
                }
7979
7980
0
                if (dfBlockValidCount > 0)
7981
0
                {
7982
                    // Update the global mean and M2 (the difference of the
7983
                    // square to the mean) from the values of the block
7984
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7985
0
                    const auto nNewValidCount =
7986
0
                        nValidCount + static_cast<int>(dfBlockValidCount);
7987
0
                    dfM2 += dfBlockM2;
7988
0
                    if (dfBlockMean != dfMean)
7989
0
                    {
7990
0
                        if (nValidCount == 0)
7991
0
                        {
7992
0
                            dfMean = dfBlockMean;
7993
0
                        }
7994
0
                        else
7995
0
                        {
7996
0
                            const double dfDelta = dfBlockMean - dfMean;
7997
0
                            const double dfNewValidCount =
7998
0
                                static_cast<double>(nNewValidCount);
7999
0
                            dfMean +=
8000
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
8001
0
                            dfM2 += dfDelta * dfDelta *
8002
0
                                    static_cast<double>(nValidCount) *
8003
0
                                    dfBlockValidCount / dfNewValidCount;
8004
0
                        }
8005
0
                    }
8006
0
                    nValidCount = nNewValidCount;
8007
0
                }
8008
0
            }
8009
0
#endif  // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
8010
8011
0
            else
8012
0
            {
8013
                // This isn't the fastest way to do this, but is easier for now.
8014
0
                for (int iY = 0; iY < nYCheck; iY++)
8015
0
                {
8016
0
                    if (nValidCount && dfMin != dfMax)
8017
0
                    {
8018
0
                        for (int iX = 0; iX < nXCheck; iX++)
8019
0
                        {
8020
0
                            const GPtrDiff_t iOffset =
8021
0
                                iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8022
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8023
0
                                continue;
8024
8025
0
                            bool bValid = true;
8026
0
                            double dfValue =
8027
0
                                GetPixelValue(eDataType, bSignedByte, pData,
8028
0
                                              iOffset, sNoDataValues, bValid);
8029
8030
0
                            if (!bValid)
8031
0
                                continue;
8032
8033
0
                            dfMin = std::min(dfMin, dfValue);
8034
0
                            dfMax = std::max(dfMax, dfValue);
8035
8036
0
                            nValidCount++;
8037
0
                            const double dfDelta = dfValue - dfMean;
8038
0
                            dfMean += dfDelta / nValidCount;
8039
0
                            dfM2 += dfDelta * (dfValue - dfMean);
8040
0
                        }
8041
0
                    }
8042
0
                    else
8043
0
                    {
8044
0
                        int iX = 0;
8045
0
                        if (nValidCount == 0)
8046
0
                        {
8047
0
                            for (; iX < nXCheck; iX++)
8048
0
                            {
8049
0
                                const GPtrDiff_t iOffset =
8050
0
                                    iX +
8051
0
                                    static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8052
0
                                if (pabyMaskData && pabyMaskData[iOffset] == 0)
8053
0
                                    continue;
8054
8055
0
                                bool bValid = true;
8056
0
                                double dfValue = GetPixelValue(
8057
0
                                    eDataType, bSignedByte, pData, iOffset,
8058
0
                                    sNoDataValues, bValid);
8059
8060
0
                                if (!bValid)
8061
0
                                    continue;
8062
8063
0
                                dfMin = dfValue;
8064
0
                                dfMax = dfValue;
8065
0
                                dfMean = dfValue;
8066
0
                                nValidCount = 1;
8067
0
                                iX++;
8068
0
                                break;
8069
0
                            }
8070
0
                        }
8071
0
                        for (; iX < nXCheck; iX++)
8072
0
                        {
8073
0
                            const GPtrDiff_t iOffset =
8074
0
                                iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8075
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8076
0
                                continue;
8077
8078
0
                            bool bValid = true;
8079
0
                            double dfValue =
8080
0
                                GetPixelValue(eDataType, bSignedByte, pData,
8081
0
                                              iOffset, sNoDataValues, bValid);
8082
8083
0
                            if (!bValid)
8084
0
                                continue;
8085
8086
0
                            dfMin = std::min(dfMin, dfValue);
8087
0
                            dfMax = std::max(dfMax, dfValue);
8088
8089
0
                            nValidCount++;
8090
0
                            if (dfMin != dfMax)
8091
0
                            {
8092
0
                                const double dfDelta = dfValue - dfMean;
8093
0
                                dfMean += dfDelta / nValidCount;
8094
0
                                dfM2 += dfDelta * (dfValue - dfMean);
8095
0
                            }
8096
0
                        }
8097
0
                    }
8098
0
                }
8099
0
            }
8100
8101
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8102
8103
0
            if (poBlock)
8104
0
                poBlock->DropLock();
8105
8106
0
            if (!pfnProgress(
8107
0
                    static_cast<double>(iSampleBlock) /
8108
0
                        (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8109
0
                    "Compute Statistics", pProgressData))
8110
0
            {
8111
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8112
0
                CPLFree(pabyMaskData);
8113
0
                return CE_Failure;
8114
0
            }
8115
0
        }
8116
8117
0
#undef nBlockXSize
8118
0
#undef nBlockYSize
8119
0
#undef nBlocksPerRow
8120
0
#undef nBlocksPerColumn
8121
8122
0
        if (bFloat32Optim)
8123
0
        {
8124
0
            dfMin = static_cast<double>(fMin);
8125
0
            dfMax = static_cast<double>(fMax);
8126
0
        }
8127
0
        CPLFree(pabyMaskData);
8128
0
    }
8129
8130
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8131
0
    {
8132
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8133
0
        return CE_Failure;
8134
0
    }
8135
8136
    /* -------------------------------------------------------------------- */
8137
    /*      Save computed information.                                      */
8138
    /* -------------------------------------------------------------------- */
8139
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8140
8141
0
    if (nValidCount > 0)
8142
0
    {
8143
0
        if (bApproxOK)
8144
0
        {
8145
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8146
0
        }
8147
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8148
0
        {
8149
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8150
0
        }
8151
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8152
0
    }
8153
0
    else
8154
0
    {
8155
0
        dfMin = 0.0;
8156
0
        dfMax = 0.0;
8157
0
    }
8158
8159
0
    SetValidPercent(nSampleCount, nValidCount);
8160
8161
    /* -------------------------------------------------------------------- */
8162
    /*      Record results.                                                 */
8163
    /* -------------------------------------------------------------------- */
8164
0
    if (pdfMin != nullptr)
8165
0
        *pdfMin = dfMin;
8166
0
    if (pdfMax != nullptr)
8167
0
        *pdfMax = dfMax;
8168
8169
0
    if (pdfMean != nullptr)
8170
0
        *pdfMean = dfMean;
8171
8172
0
    if (pdfStdDev != nullptr)
8173
0
        *pdfStdDev = dfStdDev;
8174
8175
0
    if (nValidCount > 0)
8176
0
        return CE_None;
8177
8178
0
    ReportError(
8179
0
        CE_Failure, CPLE_AppDefined,
8180
0
        "Failed to compute statistics, no valid pixels found in sampling.");
8181
0
    return CE_Failure;
8182
0
}
8183
8184
/************************************************************************/
8185
/*                    GDALComputeRasterStatistics()                     */
8186
/************************************************************************/
8187
8188
/**
8189
 * \brief Compute image statistics.
8190
 *
8191
 * @see GDALRasterBand::ComputeStatistics()
8192
 */
8193
8194
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8195
                                               int bApproxOK, double *pdfMin,
8196
                                               double *pdfMax, double *pdfMean,
8197
                                               double *pdfStdDev,
8198
                                               GDALProgressFunc pfnProgress,
8199
                                               void *pProgressData)
8200
8201
0
{
8202
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8203
8204
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8205
8206
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8207
0
                                     pdfStdDev, pfnProgress, pProgressData);
8208
0
}
8209
8210
/************************************************************************/
8211
/*                           SetStatistics()                            */
8212
/************************************************************************/
8213
8214
/**
8215
 * \brief Set statistics on band.
8216
 *
8217
 * This method can be used to store min/max/mean/standard deviation
8218
 * statistics on a raster band.
8219
 *
8220
 * The default implementation stores them as metadata, and will only work
8221
 * on formats that can save arbitrary metadata.  This method cannot detect
8222
 * whether metadata will be properly saved and so may return CE_None even
8223
 * if the statistics will never be saved.
8224
 *
8225
 * This method is the same as the C function GDALSetRasterStatistics().
8226
 *
8227
 * @param dfMin minimum pixel value.
8228
 *
8229
 * @param dfMax maximum pixel value.
8230
 *
8231
 * @param dfMean mean (average) of all pixel values.
8232
 *
8233
 * @param dfStdDev Standard deviation of all pixel values.
8234
 *
8235
 * @return CE_None on success or CE_Failure on failure.
8236
 */
8237
8238
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8239
                                     double dfStdDev)
8240
8241
0
{
8242
0
    char szValue[128] = {0};
8243
8244
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8245
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
8246
8247
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8248
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8249
8250
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8251
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
8252
8253
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8254
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
8255
8256
0
    return CE_None;
8257
0
}
8258
8259
/************************************************************************/
8260
/*                      GDALSetRasterStatistics()                       */
8261
/************************************************************************/
8262
8263
/**
8264
 * \brief Set statistics on band.
8265
 *
8266
 * @see GDALRasterBand::SetStatistics()
8267
 */
8268
8269
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8270
                                           double dfMax, double dfMean,
8271
                                           double dfStdDev)
8272
8273
0
{
8274
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8275
8276
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8277
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8278
0
}
8279
8280
/************************************************************************/
8281
/*                        ComputeRasterMinMax()                         */
8282
/************************************************************************/
8283
8284
template <class T, bool HAS_NODATA>
8285
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8286
                          T *pMax)
8287
0
{
8288
0
    T min0 = *pMin;
8289
0
    T max0 = *pMax;
8290
0
    T min1 = *pMin;
8291
0
    T max1 = *pMax;
8292
0
    size_t i;
8293
0
    for (i = 0; i + 1 < nElts; i += 2)
8294
0
    {
8295
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
8296
0
        {
8297
0
            min0 = std::min(min0, buffer[i]);
8298
0
            max0 = std::max(max0, buffer[i]);
8299
0
        }
8300
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8301
0
        {
8302
0
            min1 = std::min(min1, buffer[i + 1]);
8303
0
            max1 = std::max(max1, buffer[i + 1]);
8304
0
        }
8305
0
    }
8306
0
    T min = std::min(min0, min1);
8307
0
    T max = std::max(max0, max1);
8308
0
    if (i < nElts)
8309
0
    {
8310
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
8311
0
        {
8312
0
            min = std::min(min, buffer[i]);
8313
0
            max = std::max(max, buffer[i]);
8314
0
        }
8315
0
    }
8316
0
    *pMin = min;
8317
0
    *pMax = max;
8318
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*)
8319
8320
template <GDALDataType eDataType, bool bSignedByte>
8321
static void
8322
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8323
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8324
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
8325
0
{
8326
0
    double dfLocalMin = dfMin;
8327
0
    double dfLocalMax = dfMax;
8328
8329
0
    for (int iY = 0; iY < nYCheck; iY++)
8330
0
    {
8331
0
        for (int iX = 0; iX < nXCheck; iX++)
8332
0
        {
8333
0
            const GPtrDiff_t iOffset =
8334
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8335
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
8336
0
                continue;
8337
0
            bool bValid = true;
8338
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8339
0
                                           iOffset, sNoDataValues, bValid);
8340
0
            if (!bValid)
8341
0
                continue;
8342
8343
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
8344
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
8345
0
        }
8346
0
    }
8347
8348
0
    dfMin = dfLocalMin;
8349
0
    dfMax = dfLocalMax;
8350
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&)
8351
8352
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8353
                                 bool bSignedByte, int nXCheck, int nYCheck,
8354
                                 int nBlockXSize,
8355
                                 const GDALNoDataValues &sNoDataValues,
8356
                                 const GByte *pabyMaskData, double &dfMin,
8357
                                 double &dfMax)
8358
0
{
8359
0
    switch (eDataType)
8360
0
    {
8361
0
        case GDT_Unknown:
8362
0
            CPLAssert(false);
8363
0
            break;
8364
0
        case GDT_UInt8:
8365
0
            if (bSignedByte)
8366
0
            {
8367
0
                ComputeMinMaxGeneric<GDT_UInt8, true>(
8368
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8369
0
                    pabyMaskData, dfMin, dfMax);
8370
0
            }
8371
0
            else
8372
0
            {
8373
0
                ComputeMinMaxGeneric<GDT_UInt8, false>(
8374
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8375
0
                    pabyMaskData, dfMin, dfMax);
8376
0
            }
8377
0
            break;
8378
0
        case GDT_Int8:
8379
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8380
0
                                                  nBlockXSize, sNoDataValues,
8381
0
                                                  pabyMaskData, dfMin, dfMax);
8382
0
            break;
8383
0
        case GDT_UInt16:
8384
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8385
0
                                                    nBlockXSize, sNoDataValues,
8386
0
                                                    pabyMaskData, dfMin, dfMax);
8387
0
            break;
8388
0
        case GDT_Int16:
8389
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8390
0
                                                   nBlockXSize, sNoDataValues,
8391
0
                                                   pabyMaskData, dfMin, dfMax);
8392
0
            break;
8393
0
        case GDT_UInt32:
8394
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8395
0
                                                    nBlockXSize, sNoDataValues,
8396
0
                                                    pabyMaskData, dfMin, dfMax);
8397
0
            break;
8398
0
        case GDT_Int32:
8399
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8400
0
                                                   nBlockXSize, sNoDataValues,
8401
0
                                                   pabyMaskData, dfMin, dfMax);
8402
0
            break;
8403
0
        case GDT_UInt64:
8404
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8405
0
                                                    nBlockXSize, sNoDataValues,
8406
0
                                                    pabyMaskData, dfMin, dfMax);
8407
0
            break;
8408
0
        case GDT_Int64:
8409
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8410
0
                                                   nBlockXSize, sNoDataValues,
8411
0
                                                   pabyMaskData, dfMin, dfMax);
8412
0
            break;
8413
0
        case GDT_Float16:
8414
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
8415
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8416
0
                pabyMaskData, dfMin, dfMax);
8417
0
            break;
8418
0
        case GDT_Float32:
8419
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
8420
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8421
0
                pabyMaskData, dfMin, dfMax);
8422
0
            break;
8423
0
        case GDT_Float64:
8424
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
8425
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8426
0
                pabyMaskData, dfMin, dfMax);
8427
0
            break;
8428
0
        case GDT_CInt16:
8429
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8430
0
                                                    nBlockXSize, sNoDataValues,
8431
0
                                                    pabyMaskData, dfMin, dfMax);
8432
0
            break;
8433
0
        case GDT_CInt32:
8434
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8435
0
                                                    nBlockXSize, sNoDataValues,
8436
0
                                                    pabyMaskData, dfMin, dfMax);
8437
0
            break;
8438
0
        case GDT_CFloat16:
8439
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
8440
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8441
0
                pabyMaskData, dfMin, dfMax);
8442
0
            break;
8443
0
        case GDT_CFloat32:
8444
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
8445
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8446
0
                pabyMaskData, dfMin, dfMax);
8447
0
            break;
8448
0
        case GDT_CFloat64:
8449
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
8450
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8451
0
                pabyMaskData, dfMin, dfMax);
8452
0
            break;
8453
0
        case GDT_TypeCount:
8454
0
            CPLAssert(false);
8455
0
            break;
8456
0
    }
8457
0
}
8458
8459
static bool ComputeMinMaxGenericIterBlocks(
8460
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8461
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8462
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8463
    double &dfMin, double &dfMax)
8464
8465
0
{
8466
0
    GByte *pabyMaskData = nullptr;
8467
0
    int nBlockXSize, nBlockYSize;
8468
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8469
8470
0
    if (poMaskBand)
8471
0
    {
8472
0
        pabyMaskData =
8473
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8474
0
        if (!pabyMaskData)
8475
0
        {
8476
0
            return false;
8477
0
        }
8478
0
    }
8479
8480
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8481
0
         iSampleBlock += nSampleRate)
8482
0
    {
8483
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8484
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8485
8486
0
        int nXCheck = 0, nYCheck = 0;
8487
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8488
8489
0
        if (poMaskBand &&
8490
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8491
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8492
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8493
0
                                 nBlockXSize, nullptr) != CE_None)
8494
0
        {
8495
0
            CPLFree(pabyMaskData);
8496
0
            return false;
8497
0
        }
8498
8499
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8500
0
        if (poBlock == nullptr)
8501
0
        {
8502
0
            CPLFree(pabyMaskData);
8503
0
            return false;
8504
0
        }
8505
8506
0
        void *const pData = poBlock->GetDataRef();
8507
8508
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8509
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8510
0
                             dfMax);
8511
8512
0
        poBlock->DropLock();
8513
0
    }
8514
8515
0
    CPLFree(pabyMaskData);
8516
0
    return true;
8517
0
}
8518
8519
/**
8520
 * \brief Compute the min/max values for a band.
8521
 *
8522
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8523
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
8524
 * get an approximate min/max.  If the band has a nodata value it will
8525
 * be excluded from the minimum and maximum.
8526
 *
8527
 * If bApprox is FALSE, then all pixels will be read and used to compute
8528
 * an exact range.
8529
 *
8530
 * This method is the same as the C function GDALComputeRasterMinMax().
8531
 *
8532
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8533
 * FALSE.
8534
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8535
 * maximum (adfMinMax[1]) are returned.
8536
 *
8537
 * @return CE_None on success or CE_Failure on failure.
8538
 */
8539
8540
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8541
0
{
8542
    /* -------------------------------------------------------------------- */
8543
    /*      Does the driver already know the min/max?                       */
8544
    /* -------------------------------------------------------------------- */
8545
0
    if (bApproxOK)
8546
0
    {
8547
0
        int bSuccessMin = FALSE;
8548
0
        int bSuccessMax = FALSE;
8549
8550
0
        double dfMin = GetMinimum(&bSuccessMin);
8551
0
        double dfMax = GetMaximum(&bSuccessMax);
8552
8553
0
        if (bSuccessMin && bSuccessMax)
8554
0
        {
8555
0
            adfMinMax[0] = dfMin;
8556
0
            adfMinMax[1] = dfMax;
8557
0
            return CE_None;
8558
0
        }
8559
0
    }
8560
8561
    /* -------------------------------------------------------------------- */
8562
    /*      If we have overview bands, use them for min/max.                */
8563
    /* -------------------------------------------------------------------- */
8564
    // cppcheck-suppress knownConditionTrueFalse
8565
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8566
0
    {
8567
0
        GDALRasterBand *poBand =
8568
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8569
8570
0
        if (poBand != this)
8571
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8572
0
    }
8573
8574
    /* -------------------------------------------------------------------- */
8575
    /*      Read actual data and compute minimum and maximum.               */
8576
    /* -------------------------------------------------------------------- */
8577
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8578
0
    GDALRasterBand *poMaskBand = nullptr;
8579
0
    if (!sNoDataValues.bGotNoDataValue)
8580
0
    {
8581
0
        const int l_nMaskFlags = GetMaskFlags();
8582
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8583
0
            GetColorInterpretation() != GCI_AlphaBand)
8584
0
        {
8585
0
            poMaskBand = GetMaskBand();
8586
0
        }
8587
0
    }
8588
8589
0
    if (!bApproxOK &&
8590
0
        (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8591
0
         eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8592
0
         eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8593
0
         eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8594
0
         eDataType == GDT_Float64) &&
8595
0
        !poMaskBand)
8596
0
    {
8597
0
        CPLErr eErr = ComputeRasterMinMaxLocation(
8598
0
            &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8599
0
        if (eErr == CE_Warning)
8600
0
        {
8601
0
            ReportError(CE_Failure, CPLE_AppDefined,
8602
0
                        "Failed to compute min/max, no valid pixels found in "
8603
0
                        "sampling.");
8604
0
            eErr = CE_Failure;
8605
0
        }
8606
0
        return eErr;
8607
0
    }
8608
8609
0
    bool bSignedByte = false;
8610
0
    if (eDataType == GDT_UInt8)
8611
0
    {
8612
0
        EnablePixelTypeSignedByteWarning(false);
8613
0
        const char *pszPixelType =
8614
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8615
0
        EnablePixelTypeSignedByteWarning(true);
8616
0
        bSignedByte =
8617
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8618
0
    }
8619
8620
0
    GDALRasterIOExtraArg sExtraArg;
8621
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8622
8623
0
    GUInt32 nMin = (eDataType == GDT_UInt8)
8624
0
                       ? 255
8625
0
                       : 65535;  // used for GByte & GUInt16 cases
8626
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
8627
0
    GInt16 nMinInt16 =
8628
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
8629
0
    GInt16 nMaxInt16 =
8630
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
8631
0
    double dfMin =
8632
0
        std::numeric_limits<double>::infinity();  // used for generic code path
8633
0
    double dfMax =
8634
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
8635
0
    const bool bUseOptimizedPath =
8636
0
        !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8637
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8638
8639
0
    const auto ComputeMinMaxForBlock =
8640
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8641
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8642
0
                     int nYCheck)
8643
0
    {
8644
0
        if (eDataType == GDT_UInt8 && !bSignedByte)
8645
0
        {
8646
0
            const bool bHasNoData =
8647
0
                sNoDataValues.bGotNoDataValue &&
8648
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8649
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8650
0
                    sNoDataValues.dfNoDataValue;
8651
0
            const GUInt32 nNoDataValue =
8652
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8653
0
                           : 0;
8654
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8655
0
            ComputeStatisticsInternal<GByte,
8656
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8657
0
                f(nXCheck, nBufferWidth, nYCheck,
8658
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8659
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8660
0
        }
8661
0
        else if (eDataType == GDT_UInt16)
8662
0
        {
8663
0
            const bool bHasNoData =
8664
0
                sNoDataValues.bGotNoDataValue &&
8665
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8666
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8667
0
                    sNoDataValues.dfNoDataValue;
8668
0
            const GUInt32 nNoDataValue =
8669
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8670
0
                           : 0;
8671
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8672
0
            ComputeStatisticsInternal<GUInt16,
8673
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8674
0
                f(nXCheck, nBufferWidth, nYCheck,
8675
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8676
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8677
0
        }
8678
0
        else if (eDataType == GDT_Int16)
8679
0
        {
8680
0
            const bool bHasNoData =
8681
0
                sNoDataValues.bGotNoDataValue &&
8682
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8683
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8684
0
                    sNoDataValues.dfNoDataValue;
8685
0
            if (bHasNoData)
8686
0
            {
8687
0
                const int16_t nNoDataValue =
8688
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8689
0
                for (int iY = 0; iY < nYCheck; iY++)
8690
0
                {
8691
0
                    ComputeMinMax<int16_t, true>(
8692
0
                        static_cast<const int16_t *>(pData) +
8693
0
                            static_cast<size_t>(iY) * nBufferWidth,
8694
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8695
0
                }
8696
0
            }
8697
0
            else
8698
0
            {
8699
0
                for (int iY = 0; iY < nYCheck; iY++)
8700
0
                {
8701
0
                    ComputeMinMax<int16_t, false>(
8702
0
                        static_cast<const int16_t *>(pData) +
8703
0
                            static_cast<size_t>(iY) * nBufferWidth,
8704
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
8705
0
                }
8706
0
            }
8707
0
        }
8708
0
    };
8709
8710
0
    if (bApproxOK && HasArbitraryOverviews())
8711
0
    {
8712
        /* --------------------------------------------------------------------
8713
         */
8714
        /*      Figure out how much the image should be reduced to get an */
8715
        /*      approximate value. */
8716
        /* --------------------------------------------------------------------
8717
         */
8718
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8719
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8720
8721
0
        int nXReduced = nRasterXSize;
8722
0
        int nYReduced = nRasterYSize;
8723
0
        if (dfReduction > 1.0)
8724
0
        {
8725
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8726
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8727
8728
            // Catch the case of huge resizing ratios here
8729
0
            if (nXReduced == 0)
8730
0
                nXReduced = 1;
8731
0
            if (nYReduced == 0)
8732
0
                nYReduced = 1;
8733
0
        }
8734
8735
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
8736
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8737
8738
0
        const CPLErr eErr =
8739
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8740
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8741
0
        if (eErr != CE_None)
8742
0
        {
8743
0
            CPLFree(pData);
8744
0
            return eErr;
8745
0
        }
8746
8747
0
        GByte *pabyMaskData = nullptr;
8748
0
        if (poMaskBand)
8749
0
        {
8750
0
            pabyMaskData =
8751
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8752
0
            if (!pabyMaskData)
8753
0
            {
8754
0
                CPLFree(pData);
8755
0
                return CE_Failure;
8756
0
            }
8757
8758
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8759
0
                                     pabyMaskData, nXReduced, nYReduced,
8760
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
8761
0
            {
8762
0
                CPLFree(pData);
8763
0
                CPLFree(pabyMaskData);
8764
0
                return CE_Failure;
8765
0
            }
8766
0
        }
8767
8768
0
        if (bUseOptimizedPath)
8769
0
        {
8770
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8771
0
        }
8772
0
        else
8773
0
        {
8774
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8775
0
                                 nYReduced, nXReduced, sNoDataValues,
8776
0
                                 pabyMaskData, dfMin, dfMax);
8777
0
        }
8778
8779
0
        CPLFree(pData);
8780
0
        CPLFree(pabyMaskData);
8781
0
    }
8782
8783
0
    else  // No arbitrary overviews
8784
0
    {
8785
0
        if (!InitBlockInfo())
8786
0
            return CE_Failure;
8787
8788
        /* --------------------------------------------------------------------
8789
         */
8790
        /*      Figure out the ratio of blocks we will read to get an */
8791
        /*      approximate value. */
8792
        /* --------------------------------------------------------------------
8793
         */
8794
0
        int nSampleRate = 1;
8795
8796
0
        if (bApproxOK)
8797
0
        {
8798
0
            nSampleRate = static_cast<int>(std::max(
8799
0
                1.0,
8800
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8801
            // We want to avoid probing only the first column of blocks for
8802
            // a square shaped raster, because it is not unlikely that it may
8803
            // be padding only (#6378).
8804
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8805
0
                nSampleRate += 1;
8806
0
        }
8807
8808
0
        if (bUseOptimizedPath)
8809
0
        {
8810
0
            for (GIntBig iSampleBlock = 0;
8811
0
                 iSampleBlock <
8812
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8813
0
                 iSampleBlock += nSampleRate)
8814
0
            {
8815
0
                const int iYBlock =
8816
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
8817
0
                const int iXBlock =
8818
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
8819
8820
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8821
0
                if (poBlock == nullptr)
8822
0
                    return CE_Failure;
8823
8824
0
                void *const pData = poBlock->GetDataRef();
8825
8826
0
                int nXCheck = 0, nYCheck = 0;
8827
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8828
8829
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8830
8831
0
                poBlock->DropLock();
8832
8833
0
                if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8834
0
                    nMax == 255)
8835
0
                    break;
8836
0
            }
8837
0
        }
8838
0
        else
8839
0
        {
8840
0
            const GIntBig nTotalBlocks =
8841
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8842
0
            if (!ComputeMinMaxGenericIterBlocks(
8843
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8844
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8845
0
            {
8846
0
                return CE_Failure;
8847
0
            }
8848
0
        }
8849
0
    }
8850
8851
0
    if (bUseOptimizedPath)
8852
0
    {
8853
0
        if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8854
0
        {
8855
0
            dfMin = nMin;
8856
0
            dfMax = nMax;
8857
0
        }
8858
0
        else if (eDataType == GDT_Int16)
8859
0
        {
8860
0
            dfMin = nMinInt16;
8861
0
            dfMax = nMaxInt16;
8862
0
        }
8863
0
    }
8864
8865
0
    if (dfMin > dfMax)
8866
0
    {
8867
0
        adfMinMax[0] = 0;
8868
0
        adfMinMax[1] = 0;
8869
0
        ReportError(
8870
0
            CE_Failure, CPLE_AppDefined,
8871
0
            "Failed to compute min/max, no valid pixels found in sampling.");
8872
0
        return CE_Failure;
8873
0
    }
8874
8875
0
    adfMinMax[0] = dfMin;
8876
0
    adfMinMax[1] = dfMax;
8877
8878
0
    return CE_None;
8879
0
}
8880
8881
/************************************************************************/
8882
/*                      GDALComputeRasterMinMax()                       */
8883
/************************************************************************/
8884
8885
/**
8886
 * \brief Compute the min/max values for a band.
8887
 *
8888
 * @see GDALRasterBand::ComputeRasterMinMax()
8889
 *
8890
 * @note Prior to GDAL 3.6, this function returned void
8891
 */
8892
8893
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8894
                                           double adfMinMax[2])
8895
8896
0
{
8897
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8898
8899
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8900
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8901
0
}
8902
8903
/************************************************************************/
8904
/*                    ComputeRasterMinMaxLocation()                     */
8905
/************************************************************************/
8906
8907
/**
8908
 * \brief Compute the min/max values for a band, and their location.
8909
 *
8910
 * Pixels whose value matches the nodata value or are masked by the mask
8911
 * band are ignored.
8912
 *
8913
 * If the minimum or maximum value is hit in several locations, it is not
8914
 * specified which one will be returned.
8915
 *
8916
 * @param[out] pdfMin Pointer to the minimum value.
8917
 * @param[out] pdfMax Pointer to the maximum value.
8918
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8919
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8920
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8921
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8922
 *
8923
 * @return CE_None in case of success, CE_Warning if there are no valid values,
8924
 *         CE_Failure in case of error.
8925
 *
8926
 * @since GDAL 3.11
8927
 */
8928
8929
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8930
                                                   double *pdfMax, int *pnMinX,
8931
                                                   int *pnMinY, int *pnMaxX,
8932
                                                   int *pnMaxY)
8933
0
{
8934
0
    int nMinX = -1;
8935
0
    int nMinY = -1;
8936
0
    int nMaxX = -1;
8937
0
    int nMaxY = -1;
8938
0
    double dfMin = std::numeric_limits<double>::infinity();
8939
0
    double dfMax = -std::numeric_limits<double>::infinity();
8940
0
    if (pdfMin)
8941
0
        *pdfMin = dfMin;
8942
0
    if (pdfMax)
8943
0
        *pdfMax = dfMax;
8944
0
    if (pnMinX)
8945
0
        *pnMinX = nMinX;
8946
0
    if (pnMinY)
8947
0
        *pnMinY = nMinY;
8948
0
    if (pnMaxX)
8949
0
        *pnMaxX = nMaxX;
8950
0
    if (pnMaxY)
8951
0
        *pnMaxY = nMaxY;
8952
8953
0
    if (GDALDataTypeIsComplex(eDataType))
8954
0
    {
8955
0
        CPLError(CE_Failure, CPLE_NotSupported,
8956
0
                 "Complex data type not supported");
8957
0
        return CE_Failure;
8958
0
    }
8959
8960
0
    if (!InitBlockInfo())
8961
0
        return CE_Failure;
8962
8963
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8964
0
    GDALRasterBand *poMaskBand = nullptr;
8965
0
    if (!sNoDataValues.bGotNoDataValue)
8966
0
    {
8967
0
        const int l_nMaskFlags = GetMaskFlags();
8968
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8969
0
            GetColorInterpretation() != GCI_AlphaBand)
8970
0
        {
8971
0
            poMaskBand = GetMaskBand();
8972
0
        }
8973
0
    }
8974
8975
0
    bool bSignedByte = false;
8976
0
    if (eDataType == GDT_UInt8)
8977
0
    {
8978
0
        EnablePixelTypeSignedByteWarning(false);
8979
0
        const char *pszPixelType =
8980
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8981
0
        EnablePixelTypeSignedByteWarning(true);
8982
0
        bSignedByte =
8983
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8984
0
    }
8985
8986
0
    GByte *pabyMaskData = nullptr;
8987
0
    if (poMaskBand)
8988
0
    {
8989
0
        pabyMaskData =
8990
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8991
0
        if (!pabyMaskData)
8992
0
        {
8993
0
            return CE_Failure;
8994
0
        }
8995
0
    }
8996
8997
0
    const GIntBig nTotalBlocks =
8998
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8999
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
9000
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
9001
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
9002
0
    {
9003
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
9004
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
9005
9006
0
        int nXCheck = 0, nYCheck = 0;
9007
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
9008
9009
0
        if (poMaskBand &&
9010
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
9011
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
9012
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
9013
0
                                 nBlockXSize, nullptr) != CE_None)
9014
0
        {
9015
0
            CPLFree(pabyMaskData);
9016
0
            return CE_Failure;
9017
0
        }
9018
9019
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
9020
0
        if (poBlock == nullptr)
9021
0
        {
9022
0
            CPLFree(pabyMaskData);
9023
0
            return CE_Failure;
9024
0
        }
9025
9026
0
        void *const pData = poBlock->GetDataRef();
9027
9028
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
9029
0
        {
9030
0
            for (int iY = 0; iY < nYCheck; ++iY)
9031
0
            {
9032
0
                for (int iX = 0; iX < nXCheck; ++iX)
9033
0
                {
9034
0
                    const GPtrDiff_t iOffset =
9035
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9036
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
9037
0
                        continue;
9038
0
                    bool bValid = true;
9039
0
                    double dfValue =
9040
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
9041
0
                                      sNoDataValues, bValid);
9042
0
                    if (!bValid)
9043
0
                        continue;
9044
0
                    if (dfValue < dfMin)
9045
0
                    {
9046
0
                        dfMin = dfValue;
9047
0
                        nMinX = iXBlock * nBlockXSize + iX;
9048
0
                        nMinY = iYBlock * nBlockYSize + iY;
9049
0
                    }
9050
0
                    if (dfValue > dfMax)
9051
0
                    {
9052
0
                        dfMax = dfValue;
9053
0
                        nMaxX = iXBlock * nBlockXSize + iX;
9054
0
                        nMaxY = iYBlock * nBlockYSize + iY;
9055
0
                    }
9056
0
                }
9057
0
            }
9058
0
        }
9059
0
        else
9060
0
        {
9061
0
            size_t pos_min = 0;
9062
0
            size_t pos_max = 0;
9063
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
9064
0
            if (bNeedsMin && bNeedsMax)
9065
0
            {
9066
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
9067
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9068
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
9069
0
                    sNoDataValues.dfNoDataValue);
9070
0
            }
9071
0
            else if (bNeedsMin)
9072
0
            {
9073
0
                pos_min = gdal::min_element(
9074
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9075
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
9076
0
                    sNoDataValues.dfNoDataValue);
9077
0
            }
9078
0
            else if (bNeedsMax)
9079
0
            {
9080
0
                pos_max = gdal::max_element(
9081
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9082
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
9083
0
                    sNoDataValues.dfNoDataValue);
9084
0
            }
9085
9086
0
            if (bNeedsMin)
9087
0
            {
9088
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
9089
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
9090
0
                bool bValid = true;
9091
0
                const double dfMinValueBlock =
9092
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9093
0
                                  sNoDataValues, bValid);
9094
0
                if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9095
0
                {
9096
0
                    dfMin = dfMinValueBlock;
9097
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
9098
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
9099
0
                }
9100
0
            }
9101
9102
0
            if (bNeedsMax)
9103
0
            {
9104
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9105
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9106
0
                bool bValid = true;
9107
0
                const double dfMaxValueBlock =
9108
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9109
0
                                  sNoDataValues, bValid);
9110
0
                if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9111
0
                {
9112
0
                    dfMax = dfMaxValueBlock;
9113
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9114
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9115
0
                }
9116
0
            }
9117
0
        }
9118
9119
0
        poBlock->DropLock();
9120
9121
0
        if (eDataType == GDT_UInt8)
9122
0
        {
9123
0
            if (bNeedsMin && dfMin == 0)
9124
0
            {
9125
0
                bNeedsMin = false;
9126
0
            }
9127
0
            if (bNeedsMax && dfMax == 255)
9128
0
            {
9129
0
                bNeedsMax = false;
9130
0
            }
9131
0
            if (!bNeedsMin && !bNeedsMax)
9132
0
            {
9133
0
                break;
9134
0
            }
9135
0
        }
9136
0
    }
9137
9138
0
    CPLFree(pabyMaskData);
9139
9140
0
    if (pdfMin)
9141
0
        *pdfMin = dfMin;
9142
0
    if (pdfMax)
9143
0
        *pdfMax = dfMax;
9144
0
    if (pnMinX)
9145
0
        *pnMinX = nMinX;
9146
0
    if (pnMinY)
9147
0
        *pnMinY = nMinY;
9148
0
    if (pnMaxX)
9149
0
        *pnMaxX = nMaxX;
9150
0
    if (pnMaxY)
9151
0
        *pnMaxY = nMaxY;
9152
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9153
0
                                                                  : CE_None;
9154
0
}
9155
9156
/************************************************************************/
9157
/*                  GDALComputeRasterMinMaxLocation()                   */
9158
/************************************************************************/
9159
9160
/**
9161
 * \brief Compute the min/max values for a band, and their location.
9162
 *
9163
 * @see GDALRasterBand::ComputeRasterMinMax()
9164
 * @since GDAL 3.11
9165
 */
9166
9167
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9168
                                       double *pdfMax, int *pnMinX, int *pnMinY,
9169
                                       int *pnMaxX, int *pnMaxY)
9170
9171
0
{
9172
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9173
9174
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9175
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9176
0
                                               pnMaxX, pnMaxY);
9177
0
}
9178
9179
/************************************************************************/
9180
/*                        SetDefaultHistogram()                         */
9181
/************************************************************************/
9182
9183
/* FIXME : add proper documentation */
9184
/**
9185
 * \brief Set default histogram.
9186
 *
9187
 * This method is the same as the C function GDALSetDefaultHistogram() and
9188
 * GDALSetDefaultHistogramEx()
9189
 */
9190
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9191
                                           double /* dfMax */,
9192
                                           int /* nBuckets */,
9193
                                           GUIntBig * /* panHistogram */)
9194
9195
0
{
9196
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9197
0
        ReportError(CE_Failure, CPLE_NotSupported,
9198
0
                    "SetDefaultHistogram() not implemented for this format.");
9199
9200
0
    return CE_Failure;
9201
0
}
9202
9203
/************************************************************************/
9204
/*                      GDALSetDefaultHistogram()                       */
9205
/************************************************************************/
9206
9207
/**
9208
 * \brief Set default histogram.
9209
 *
9210
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9211
 * 2 billion.
9212
 *
9213
 * @see GDALRasterBand::SetDefaultHistogram()
9214
 * @see GDALSetRasterHistogramEx()
9215
 */
9216
9217
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9218
                                           double dfMax, int nBuckets,
9219
                                           int *panHistogram)
9220
9221
0
{
9222
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9223
9224
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9225
9226
0
    GUIntBig *panHistogramTemp =
9227
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9228
0
    if (panHistogramTemp == nullptr)
9229
0
    {
9230
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9231
0
                            "Out of memory in GDALSetDefaultHistogram().");
9232
0
        return CE_Failure;
9233
0
    }
9234
9235
0
    for (int i = 0; i < nBuckets; ++i)
9236
0
    {
9237
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9238
0
    }
9239
9240
0
    const CPLErr eErr =
9241
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9242
9243
0
    CPLFree(panHistogramTemp);
9244
9245
0
    return eErr;
9246
0
}
9247
9248
/************************************************************************/
9249
/*                     GDALSetDefaultHistogramEx()                      */
9250
/************************************************************************/
9251
9252
/**
9253
 * \brief Set default histogram.
9254
 *
9255
 * @see GDALRasterBand::SetDefaultHistogram()
9256
 *
9257
 */
9258
9259
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9260
                                             double dfMin, double dfMax,
9261
                                             int nBuckets,
9262
                                             GUIntBig *panHistogram)
9263
9264
0
{
9265
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9266
9267
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9268
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9269
0
}
9270
9271
/************************************************************************/
9272
/*                           GetDefaultRAT()                            */
9273
/************************************************************************/
9274
9275
/**
9276
 * \brief Fetch default Raster Attribute Table.
9277
 *
9278
 * A RAT will be returned if there is a default one associated with the
9279
 * band, otherwise NULL is returned.  The returned RAT is owned by the
9280
 * band and should not be deleted by the application.
9281
 *
9282
 * This method is the same as the C function GDALGetDefaultRAT().
9283
 *
9284
 * @return NULL, or a pointer to an internal RAT owned by the band.
9285
 */
9286
9287
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9288
9289
0
{
9290
0
    return nullptr;
9291
0
}
9292
9293
/************************************************************************/
9294
/*                         GDALGetDefaultRAT()                          */
9295
/************************************************************************/
9296
9297
/**
9298
 * \brief Fetch default Raster Attribute Table.
9299
 *
9300
 * @see GDALRasterBand::GetDefaultRAT()
9301
 */
9302
9303
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9304
9305
0
{
9306
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9307
9308
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9309
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9310
0
}
9311
9312
/************************************************************************/
9313
/*                           SetDefaultRAT()                            */
9314
/************************************************************************/
9315
9316
/**
9317
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9318
 * \brief Set default Raster Attribute Table.
9319
 *
9320
 * Associates a default RAT with the band.  If not implemented for the
9321
 * format a CPLE_NotSupported error will be issued.  If successful a copy
9322
 * of the RAT is made, the original remains owned by the caller.
9323
 *
9324
 * This method is the same as the C function GDALSetDefaultRAT().
9325
 *
9326
 * @param poRAT the RAT to assign to the band.
9327
 *
9328
 * @return CE_None on success or CE_Failure if unsupported or otherwise
9329
 * failing.
9330
 */
9331
9332
/**/
9333
/**/
9334
9335
CPLErr
9336
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9337
0
{
9338
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9339
0
    {
9340
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
9341
0
        ReportError(CE_Failure, CPLE_NotSupported,
9342
0
                    "SetDefaultRAT() not implemented for this format.");
9343
0
        CPLPopErrorHandler();
9344
0
    }
9345
0
    return CE_Failure;
9346
0
}
9347
9348
/************************************************************************/
9349
/*                         GDALSetDefaultRAT()                          */
9350
/************************************************************************/
9351
9352
/**
9353
 * \brief Set default Raster Attribute Table.
9354
 *
9355
 * @see GDALRasterBand::GDALSetDefaultRAT()
9356
 */
9357
9358
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9359
                                     GDALRasterAttributeTableH hRAT)
9360
9361
0
{
9362
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9363
9364
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9365
9366
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9367
0
}
9368
9369
/************************************************************************/
9370
/*                             HasNoData()                              */
9371
/************************************************************************/
9372
9373
bool GDALRasterBand::HasNoData() const
9374
0
{
9375
0
    int bHaveNoDataRaw = FALSE;
9376
0
    bool bHaveNoData = false;
9377
0
    GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9378
0
    if (eDataType == GDT_Int64)
9379
0
    {
9380
0
        CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9381
0
        bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9382
0
    }
9383
0
    else if (eDataType == GDT_UInt64)
9384
0
    {
9385
0
        CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9386
0
        bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9387
0
    }
9388
0
    else
9389
0
    {
9390
0
        const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9391
0
        if (bHaveNoDataRaw &&
9392
0
            GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9393
0
        {
9394
0
            bHaveNoData = true;
9395
0
        }
9396
0
    }
9397
0
    return bHaveNoData;
9398
0
}
9399
9400
/************************************************************************/
9401
/*                            GetMaskBand()                             */
9402
/************************************************************************/
9403
9404
/**
9405
 * \brief Return the mask band associated with the band.
9406
 *
9407
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9408
 * that returns one of four default implementations :
9409
 * <ul>
9410
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9411
 * </li>
9412
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9413
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9414
 * GMF_NODATA | GMF_PER_DATASET.
9415
 * </li>
9416
 * <li>If the band has a nodata value set, an instance of the new
9417
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9418
 * GMF_NODATA.
9419
 * </li>
9420
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
9421
 * to apply to this band (specific rules yet to be determined) and that is of
9422
 * type GDT_UInt8 then that alpha band will be returned, and the flags
9423
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9424
 * </li>
9425
 * <li>If neither of the above apply, an instance of the new
9426
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9427
 * pixels. The null flags will return GMF_ALL_VALID.
9428
 * </li>
9429
 * </ul>
9430
 *
9431
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9432
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9433
 *
9434
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9435
 * dataset, with the same name as the main dataset and suffixed with .msk,
9436
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9437
 * main dataset.
9438
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9439
 * level, where xx matches the band number of a band of the main dataset. The
9440
 * value of those items is a combination of the flags GMF_ALL_VALID,
9441
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9442
 * a band, then the other rules explained above will be used to generate a
9443
 * on-the-fly mask band.
9444
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9445
 *
9446
 * This method is the same as the C function GDALGetMaskBand().
9447
 *
9448
 * @return a valid mask band.
9449
 *
9450
 *
9451
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9452
 *
9453
 */
9454
GDALRasterBand *GDALRasterBand::GetMaskBand()
9455
9456
0
{
9457
0
    if (poMask != nullptr)
9458
0
    {
9459
0
        if (poMask.IsOwned())
9460
0
        {
9461
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9462
0
            {
9463
0
                if (HasNoData())
9464
0
                {
9465
0
                    InvalidateMaskBand();
9466
0
                }
9467
0
            }
9468
0
            else if (auto poNoDataMaskBand =
9469
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9470
0
            {
9471
0
                int bHaveNoDataRaw = FALSE;
9472
0
                bool bIsSame = false;
9473
0
                if (eDataType == GDT_Int64)
9474
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9475
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9476
0
                              bHaveNoDataRaw;
9477
0
                else if (eDataType == GDT_UInt64)
9478
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9479
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9480
0
                              bHaveNoDataRaw;
9481
0
                else
9482
0
                {
9483
0
                    const double dfNoDataValue =
9484
0
                        GetNoDataValue(&bHaveNoDataRaw);
9485
0
                    if (bHaveNoDataRaw)
9486
0
                    {
9487
0
                        bIsSame =
9488
0
                            std::isnan(dfNoDataValue)
9489
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9490
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
9491
0
                                      dfNoDataValue;
9492
0
                    }
9493
0
                }
9494
0
                if (!bIsSame)
9495
0
                    InvalidateMaskBand();
9496
0
            }
9497
0
        }
9498
9499
0
        if (poMask)
9500
0
            return poMask.get();
9501
0
    }
9502
9503
    /* -------------------------------------------------------------------- */
9504
    /*      Check for a mask in a .msk file.                                */
9505
    /* -------------------------------------------------------------------- */
9506
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9507
0
    {
9508
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9509
0
        if (poMask != nullptr)
9510
0
        {
9511
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9512
0
            return poMask.get();
9513
0
        }
9514
0
    }
9515
9516
    /* -------------------------------------------------------------------- */
9517
    /*      Check for NODATA_VALUES metadata.                               */
9518
    /* -------------------------------------------------------------------- */
9519
0
    if (poDS != nullptr)
9520
0
    {
9521
0
        const char *pszGDALNoDataValues =
9522
0
            poDS->GetMetadataItem("NODATA_VALUES");
9523
0
        if (pszGDALNoDataValues != nullptr)
9524
0
        {
9525
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9526
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
9527
9528
            // Make sure we have as many values as bands.
9529
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9530
0
                poDS->GetRasterCount() != 0)
9531
0
            {
9532
                // Make sure that all bands have the same data type
9533
                // This is clearly not a fundamental condition, just a
9534
                // condition to make implementation easier.
9535
0
                GDALDataType eDT = GDT_Unknown;
9536
0
                int i = 0;  // Used after for.
9537
0
                for (; i < poDS->GetRasterCount(); ++i)
9538
0
                {
9539
0
                    if (i == 0)
9540
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9541
0
                    else if (eDT !=
9542
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
9543
0
                    {
9544
0
                        break;
9545
0
                    }
9546
0
                }
9547
0
                if (i == poDS->GetRasterCount())
9548
0
                {
9549
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9550
0
                    try
9551
0
                    {
9552
0
                        poMask.reset(
9553
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9554
0
                    }
9555
0
                    catch (const std::bad_alloc &)
9556
0
                    {
9557
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9558
0
                        poMask.reset();
9559
0
                    }
9560
0
                    CSLDestroy(papszGDALNoDataValues);
9561
0
                    return poMask.get();
9562
0
                }
9563
0
                else
9564
0
                {
9565
0
                    ReportError(CE_Warning, CPLE_AppDefined,
9566
0
                                "All bands should have the same type in "
9567
0
                                "order the NODATA_VALUES metadata item "
9568
0
                                "to be used as a mask.");
9569
0
                }
9570
0
            }
9571
0
            else
9572
0
            {
9573
0
                ReportError(
9574
0
                    CE_Warning, CPLE_AppDefined,
9575
0
                    "NODATA_VALUES metadata item doesn't have the same number "
9576
0
                    "of values as the number of bands.  "
9577
0
                    "Ignoring it for mask.");
9578
0
            }
9579
9580
0
            CSLDestroy(papszGDALNoDataValues);
9581
0
        }
9582
0
    }
9583
9584
    /* -------------------------------------------------------------------- */
9585
    /*      Check for nodata case.                                          */
9586
    /* -------------------------------------------------------------------- */
9587
0
    if (HasNoData())
9588
0
    {
9589
0
        nMaskFlags = GMF_NODATA;
9590
0
        try
9591
0
        {
9592
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9593
0
        }
9594
0
        catch (const std::bad_alloc &)
9595
0
        {
9596
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9597
0
            poMask.reset();
9598
0
        }
9599
0
        return poMask.get();
9600
0
    }
9601
9602
    /* -------------------------------------------------------------------- */
9603
    /*      Check for alpha case.                                           */
9604
    /* -------------------------------------------------------------------- */
9605
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9606
0
        this == poDS->GetRasterBand(1) &&
9607
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9608
0
    {
9609
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9610
0
        {
9611
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9612
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
9613
0
            return poMask.get();
9614
0
        }
9615
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9616
0
        {
9617
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9618
0
            try
9619
0
            {
9620
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9621
0
                    poDS->GetRasterBand(2)));
9622
0
            }
9623
0
            catch (const std::bad_alloc &)
9624
0
            {
9625
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9626
0
                poMask.reset();
9627
0
            }
9628
0
            return poMask.get();
9629
0
        }
9630
0
    }
9631
9632
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9633
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9634
0
         this == poDS->GetRasterBand(3)) &&
9635
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9636
0
    {
9637
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9638
0
        {
9639
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9640
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
9641
0
            return poMask.get();
9642
0
        }
9643
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9644
0
        {
9645
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9646
0
            try
9647
0
            {
9648
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9649
0
                    poDS->GetRasterBand(4)));
9650
0
            }
9651
0
            catch (const std::bad_alloc &)
9652
0
            {
9653
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9654
0
                poMask.reset();
9655
0
            }
9656
0
            return poMask.get();
9657
0
        }
9658
0
    }
9659
9660
    /* -------------------------------------------------------------------- */
9661
    /*      Fallback to all valid case.                                     */
9662
    /* -------------------------------------------------------------------- */
9663
0
    nMaskFlags = GMF_ALL_VALID;
9664
0
    try
9665
0
    {
9666
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9667
0
    }
9668
0
    catch (const std::bad_alloc &)
9669
0
    {
9670
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9671
0
        poMask.reset();
9672
0
    }
9673
9674
0
    return poMask.get();
9675
0
}
9676
9677
/************************************************************************/
9678
/*                          GDALGetMaskBand()                           */
9679
/************************************************************************/
9680
9681
/**
9682
 * \brief Return the mask band associated with the band.
9683
 *
9684
 * @see GDALRasterBand::GetMaskBand()
9685
 */
9686
9687
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9688
9689
0
{
9690
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9691
9692
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9693
0
    return poBand->GetMaskBand();
9694
0
}
9695
9696
/************************************************************************/
9697
/*                            GetMaskFlags()                            */
9698
/************************************************************************/
9699
9700
/**
9701
 * \brief Return the status flags of the mask band associated with the band.
9702
 *
9703
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9704
 * the following available definitions that may be extended in the future:
9705
 * <ul>
9706
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9707
 * 255. When used this will normally be the only flag set.
9708
 * </li>
9709
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9710
 * dataset.
9711
 * </li>
9712
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9713
 * and may have values other than 0 and 255.
9714
 * </li>
9715
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9716
 * nodata values. (mutually exclusive of GMF_ALPHA)
9717
 * </li>
9718
 * </ul>
9719
 *
9720
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9721
 * that returns one of four default implementations:
9722
 * <ul>
9723
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9724
 * </li>
9725
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9726
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9727
 * GMF_NODATA | GMF_PER_DATASET.
9728
 * </li>
9729
 * <li>If the band has a nodata value set, an instance of the new
9730
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9731
 * GMF_NODATA.
9732
 * </li>
9733
 * <li>If there is no nodata value, but the dataset has an alpha band that
9734
 * seems to apply to this band (specific rules yet to be determined) and that is
9735
 * of type GDT_UInt8 then that alpha band will be returned, and the flags
9736
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9737
 * </li>
9738
 * <li>If neither of the above apply, an instance of the new
9739
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9740
 * pixels. The null flags will return GMF_ALL_VALID.
9741
 * </li>
9742
 * </ul>
9743
 *
9744
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9745
 * dataset, with the same name as the main dataset and suffixed with .msk,
9746
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9747
 * main dataset.
9748
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9749
 * level, where xx matches the band number of a band of the main dataset. The
9750
 * value of those items is a combination of the flags GMF_ALL_VALID,
9751
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9752
 * a band, then the other rules explained above will be used to generate a
9753
 * on-the-fly mask band.
9754
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9755
 *
9756
 * This method is the same as the C function GDALGetMaskFlags().
9757
 *
9758
 *
9759
 * @return a valid mask band.
9760
 *
9761
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9762
 *
9763
 */
9764
int GDALRasterBand::GetMaskFlags()
9765
9766
0
{
9767
    // If we don't have a band yet, force this now so that the masks value
9768
    // will be initialized.
9769
9770
0
    if (poMask == nullptr)
9771
0
        GetMaskBand();
9772
9773
0
    return nMaskFlags;
9774
0
}
9775
9776
/************************************************************************/
9777
/*                          GDALGetMaskFlags()                          */
9778
/************************************************************************/
9779
9780
/**
9781
 * \brief Return the status flags of the mask band associated with the band.
9782
 *
9783
 * @see GDALRasterBand::GetMaskFlags()
9784
 */
9785
9786
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9787
9788
0
{
9789
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9790
9791
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9792
0
    return poBand->GetMaskFlags();
9793
0
}
9794
9795
/************************************************************************/
9796
/*                         InvalidateMaskBand()                         */
9797
/************************************************************************/
9798
9799
//! @cond Doxygen_Suppress
9800
void GDALRasterBand::InvalidateMaskBand()
9801
0
{
9802
0
    poMask.reset();
9803
0
    nMaskFlags = 0;
9804
0
}
9805
9806
//! @endcond
9807
9808
/************************************************************************/
9809
/*                           CreateMaskBand()                           */
9810
/************************************************************************/
9811
9812
/**
9813
 * \brief Adds a mask band to the current band
9814
 *
9815
 * The default implementation of the CreateMaskBand() method is implemented
9816
 * based on similar rules to the .ovr handling implemented using the
9817
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9818
 * be created with the same basename as the original file, and it will have
9819
 * as many bands as the original image (or just one for GMF_PER_DATASET).
9820
 * The mask images will be deflate compressed tiled images with the same
9821
 * block size as the original image if possible.
9822
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9823
 * level, where xx matches the band number of a band of the main dataset. The
9824
 * value of those items will be the one of the nFlagsIn parameter.
9825
 *
9826
 * Note that if you got a mask band with a previous call to GetMaskBand(),
9827
 * it might be invalidated by CreateMaskBand(). So you have to call
9828
 * GetMaskBand() again.
9829
 *
9830
 * This method is the same as the C function GDALCreateMaskBand().
9831
 *
9832
 *
9833
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9834
 *
9835
 * @return CE_None on success or CE_Failure on an error.
9836
 *
9837
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9838
 * @see GDALDataset::CreateMaskBand()
9839
 *
9840
 */
9841
9842
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9843
9844
0
{
9845
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9846
0
    {
9847
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9848
0
        if (eErr != CE_None)
9849
0
            return eErr;
9850
9851
0
        InvalidateMaskBand();
9852
9853
0
        return CE_None;
9854
0
    }
9855
9856
0
    ReportError(CE_Failure, CPLE_NotSupported,
9857
0
                "CreateMaskBand() not supported for this band.");
9858
9859
0
    return CE_Failure;
9860
0
}
9861
9862
/************************************************************************/
9863
/*                         GDALCreateMaskBand()                         */
9864
/************************************************************************/
9865
9866
/**
9867
 * \brief Adds a mask band to the current band
9868
 *
9869
 * @see GDALRasterBand::CreateMaskBand()
9870
 */
9871
9872
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9873
9874
0
{
9875
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9876
9877
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9878
0
    return poBand->CreateMaskBand(nFlags);
9879
0
}
9880
9881
/************************************************************************/
9882
/*                             IsMaskBand()                             */
9883
/************************************************************************/
9884
9885
/**
9886
 * \brief Returns whether a band is a mask band.
9887
 *
9888
 * Mask band must be understood in the broad term: it can be a per-dataset
9889
 * mask band, an alpha band, or an implicit mask band.
9890
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9891
 *
9892
 * This method is the same as the C function GDALIsMaskBand().
9893
 *
9894
 * @return true if the band is a mask band.
9895
 *
9896
 * @see GDALDataset::CreateMaskBand()
9897
 *
9898
 * @since GDAL 3.5.0
9899
 *
9900
 */
9901
9902
bool GDALRasterBand::IsMaskBand() const
9903
0
{
9904
    // The GeoTIFF driver, among others, override this method to
9905
    // also handle external .msk bands.
9906
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9907
0
           GCI_AlphaBand;
9908
0
}
9909
9910
/************************************************************************/
9911
/*                           GDALIsMaskBand()                           */
9912
/************************************************************************/
9913
9914
/**
9915
 * \brief Returns whether a band is a mask band.
9916
 *
9917
 * Mask band must be understood in the broad term: it can be a per-dataset
9918
 * mask band, an alpha band, or an implicit mask band.
9919
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9920
 *
9921
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9922
 *
9923
 * @return true if the band is a mask band.
9924
 *
9925
 * @see GDALRasterBand::IsMaskBand()
9926
 *
9927
 * @since GDAL 3.5.0
9928
 *
9929
 */
9930
9931
bool GDALIsMaskBand(GDALRasterBandH hBand)
9932
9933
0
{
9934
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9935
9936
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9937
0
    return poBand->IsMaskBand();
9938
0
}
9939
9940
/************************************************************************/
9941
/*                         GetMaskValueRange()                          */
9942
/************************************************************************/
9943
9944
/**
9945
 * \brief Returns the range of values that a mask band can take.
9946
 *
9947
 * @return the range of values that a mask band can take.
9948
 *
9949
 * @since GDAL 3.5.0
9950
 *
9951
 */
9952
9953
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9954
0
{
9955
0
    return GMVR_UNKNOWN;
9956
0
}
9957
9958
/************************************************************************/
9959
/*                     HasConflictingMaskSources()                      */
9960
/************************************************************************/
9961
9962
/**
9963
 * \brief Returns whether a raster band has conflicting mask sources.
9964
 *
9965
 * That is, if more than one of the following conditions is met:
9966
 * - it has a binary mask band (that is not an alpha band)
9967
 * - it has an external mask flags (.msk file)
9968
 * - it has a nodata value
9969
 * - it belongs to a dataset with the NODATA_VALUES metadata item set
9970
 * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
9971
 *
9972
 * @param[out] posDetailMessage Pointer to a string that will contain the
9973
 *                              details of the conflict.
9974
 * @param bMentionPrioritarySource Whether the mask source used should be
9975
 *                                 mentioned in *posDetailMessage.
9976
 * @since GDAL 3.13.0
9977
 */
9978
9979
bool GDALRasterBand::HasConflictingMaskSources(
9980
    std::string *posDetailMessage, bool bMentionPrioritarySource) const
9981
0
{
9982
0
    const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
9983
0
    const bool bHasBinaryMaskBand =
9984
0
        ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
9985
0
          (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
9986
0
        (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
9987
0
    const bool bHasNoData = HasNoData();
9988
0
    const bool bHasNODATA_VALUES =
9989
0
        poDS && poDS->GetMetadataItem("NODATA_VALUES");
9990
0
    const bool bHasAlphaBand =
9991
0
        poDS &&
9992
0
        poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
9993
0
            GCI_AlphaBand;
9994
0
    const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
9995
0
                                  bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
9996
0
    const size_t nCount =
9997
0
        std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
9998
0
    if (nCount >= 2)
9999
0
    {
10000
0
        if (posDetailMessage)
10001
0
        {
10002
0
            *posDetailMessage = "Raster band ";
10003
0
            *posDetailMessage += std::to_string(nBand);
10004
0
            if (poDS && poDS->GetDescription()[0])
10005
0
            {
10006
0
                *posDetailMessage += " of dataset ";
10007
0
                *posDetailMessage += poDS->GetDescription();
10008
0
            }
10009
0
            *posDetailMessage += " has several conflicting mask sources:\n";
10010
0
            if (bHasExternalMask)
10011
0
                *posDetailMessage += "- internal binary mask band\n";
10012
0
            if (bHasExternalMask)
10013
0
                *posDetailMessage += "- external mask band (.msk)\n";
10014
0
            if (bHasNoData)
10015
0
                *posDetailMessage += "- nodata value\n";
10016
0
            if (bHasNODATA_VALUES)
10017
0
                *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
10018
0
            if (bHasAlphaBand)
10019
0
                *posDetailMessage +=
10020
0
                    "- related to a raster band that is an alpha band\n";
10021
0
            if (bMentionPrioritarySource)
10022
0
                *posDetailMessage +=
10023
0
                    "Only the first listed one will be taken into account.";
10024
0
        }
10025
0
        return true;
10026
0
    }
10027
0
    return false;
10028
0
}
10029
10030
/************************************************************************/
10031
/*                     GetIndexColorTranslationTo()                     */
10032
/************************************************************************/
10033
10034
/**
10035
 * \brief Compute translation table for color tables.
10036
 *
10037
 * When the raster band has a palette index, it may be useful to compute
10038
 * the "translation" of this palette to the palette of another band.
10039
 * The translation tries to do exact matching first, and then approximate
10040
 * matching if no exact matching is possible.
10041
 * This method returns a table such that table[i] = j where i is an index
10042
 * of the 'this' rasterband and j the corresponding index for the reference
10043
 * rasterband.
10044
 *
10045
 * This method is thought as internal to GDAL and is used for drivers
10046
 * like RPFTOC.
10047
 *
10048
 * The implementation only supports 1-byte palette rasterbands.
10049
 *
10050
 * @param poReferenceBand the raster band
10051
 * @param pTranslationTable an already allocated translation table (at least 256
10052
 * bytes), or NULL to let the method allocate it
10053
 * @param pApproximateMatching a pointer to a flag that is set if the matching
10054
 *                              is approximate. May be NULL.
10055
 *
10056
 * @return a translation table if the two bands are palette index and that they
10057
 * do not match or NULL in other cases. The table must be freed with CPLFree if
10058
 * NULL was passed for pTranslationTable.
10059
 */
10060
10061
unsigned char *
10062
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
10063
                                           unsigned char *pTranslationTable,
10064
                                           int *pApproximateMatching)
10065
0
{
10066
0
    if (poReferenceBand == nullptr)
10067
0
        return nullptr;
10068
10069
    // cppcheck-suppress knownConditionTrueFalse
10070
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
10071
        // cppcheck-suppress knownConditionTrueFalse
10072
0
        GetColorInterpretation() == GCI_PaletteIndex &&
10073
0
        poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
10074
0
        GetRasterDataType() == GDT_UInt8)
10075
0
    {
10076
0
        const GDALColorTable *srcColorTable = GetColorTable();
10077
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
10078
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
10079
0
        {
10080
0
            const int nEntries = srcColorTable->GetColorEntryCount();
10081
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
10082
10083
0
            int bHasNoDataValueSrc = FALSE;
10084
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
10085
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
10086
0
                  dfNoDataValueSrc <= 255 &&
10087
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
10088
0
                bHasNoDataValueSrc = FALSE;
10089
0
            const int noDataValueSrc =
10090
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10091
10092
0
            int bHasNoDataValueRef = FALSE;
10093
0
            const double dfNoDataValueRef =
10094
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10095
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10096
0
                  dfNoDataValueRef <= 255 &&
10097
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10098
0
                bHasNoDataValueRef = FALSE;
10099
0
            const int noDataValueRef =
10100
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10101
10102
0
            bool samePalette = false;
10103
10104
0
            if (pApproximateMatching)
10105
0
                *pApproximateMatching = FALSE;
10106
10107
0
            if (nEntries == nRefEntries &&
10108
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
10109
0
                (bHasNoDataValueSrc == FALSE ||
10110
0
                 noDataValueSrc == noDataValueRef))
10111
0
            {
10112
0
                samePalette = true;
10113
0
                for (int i = 0; i < nEntries; ++i)
10114
0
                {
10115
0
                    if (noDataValueSrc == i)
10116
0
                        continue;
10117
0
                    const GDALColorEntry *entry =
10118
0
                        srcColorTable->GetColorEntry(i);
10119
0
                    const GDALColorEntry *entryRef =
10120
0
                        destColorTable->GetColorEntry(i);
10121
0
                    if (entry->c1 != entryRef->c1 ||
10122
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10123
0
                    {
10124
0
                        samePalette = false;
10125
0
                    }
10126
0
                }
10127
0
            }
10128
10129
0
            if (!samePalette)
10130
0
            {
10131
0
                if (pTranslationTable == nullptr)
10132
0
                {
10133
0
                    pTranslationTable = static_cast<unsigned char *>(
10134
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10135
0
                    if (pTranslationTable == nullptr)
10136
0
                        return nullptr;
10137
0
                }
10138
10139
                // Trying to remap the product palette on the subdataset
10140
                // palette.
10141
0
                for (int i = 0; i < nEntries; ++i)
10142
0
                {
10143
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10144
0
                        noDataValueSrc == i)
10145
0
                        continue;
10146
0
                    const GDALColorEntry *entry =
10147
0
                        srcColorTable->GetColorEntry(i);
10148
0
                    bool bMatchFound = false;
10149
0
                    for (int j = 0; j < nRefEntries; ++j)
10150
0
                    {
10151
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
10152
0
                            continue;
10153
0
                        const GDALColorEntry *entryRef =
10154
0
                            destColorTable->GetColorEntry(j);
10155
0
                        if (entry->c1 == entryRef->c1 &&
10156
0
                            entry->c2 == entryRef->c2 &&
10157
0
                            entry->c3 == entryRef->c3)
10158
0
                        {
10159
0
                            pTranslationTable[i] =
10160
0
                                static_cast<unsigned char>(j);
10161
0
                            bMatchFound = true;
10162
0
                            break;
10163
0
                        }
10164
0
                    }
10165
0
                    if (!bMatchFound)
10166
0
                    {
10167
                        // No exact match. Looking for closest color now.
10168
0
                        int best_j = 0;
10169
0
                        int best_distance = 0;
10170
0
                        if (pApproximateMatching)
10171
0
                            *pApproximateMatching = TRUE;
10172
0
                        for (int j = 0; j < nRefEntries; ++j)
10173
0
                        {
10174
0
                            const GDALColorEntry *entryRef =
10175
0
                                destColorTable->GetColorEntry(j);
10176
0
                            int distance = (entry->c1 - entryRef->c1) *
10177
0
                                               (entry->c1 - entryRef->c1) +
10178
0
                                           (entry->c2 - entryRef->c2) *
10179
0
                                               (entry->c2 - entryRef->c2) +
10180
0
                                           (entry->c3 - entryRef->c3) *
10181
0
                                               (entry->c3 - entryRef->c3);
10182
0
                            if (j == 0 || distance < best_distance)
10183
0
                            {
10184
0
                                best_j = j;
10185
0
                                best_distance = distance;
10186
0
                            }
10187
0
                        }
10188
0
                        pTranslationTable[i] =
10189
0
                            static_cast<unsigned char>(best_j);
10190
0
                    }
10191
0
                }
10192
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
10193
0
                    pTranslationTable[noDataValueSrc] =
10194
0
                        static_cast<unsigned char>(noDataValueRef);
10195
10196
0
                return pTranslationTable;
10197
0
            }
10198
0
        }
10199
0
    }
10200
0
    return nullptr;
10201
0
}
10202
10203
/************************************************************************/
10204
/*                          SetFlushBlockErr()                          */
10205
/************************************************************************/
10206
10207
/**
10208
 * \brief Store that an error occurred while writing a dirty block.
10209
 *
10210
 * This function stores the fact that an error occurred while writing a dirty
10211
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10212
 * flushed when the block cache get full, it is not convenient/possible to
10213
 * report that a dirty block could not be written correctly. This function
10214
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10215
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10216
 * places where the user can easily match the error with the relevant dataset.
10217
 */
10218
10219
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10220
0
{
10221
0
    eFlushBlockErr = eErr;
10222
0
}
10223
10224
/************************************************************************/
10225
/*                           IncDirtyBlocks()                           */
10226
/************************************************************************/
10227
10228
/**
10229
 * \brief Increment/decrement the number of dirty blocks
10230
 */
10231
10232
void GDALRasterBand::IncDirtyBlocks(int nInc)
10233
0
{
10234
0
    if (poBandBlockCache)
10235
0
        poBandBlockCache->IncDirtyBlocks(nInc);
10236
0
}
10237
10238
/************************************************************************/
10239
/*                            ReportError()                             */
10240
/************************************************************************/
10241
10242
#ifndef DOXYGEN_XML
10243
/**
10244
 * \brief Emits an error related to a raster band.
10245
 *
10246
 * This function is a wrapper for regular CPLError(). The only difference
10247
 * with CPLError() is that it prepends the error message with the dataset
10248
 * name and the band number.
10249
 *
10250
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10251
 * @param err_no the error number (CPLE_*) from cpl_error.h.
10252
 * @param fmt a printf() style format string.  Any additional arguments
10253
 * will be treated as arguments to fill in this format in a manner
10254
 * similar to printf().
10255
 *
10256
 */
10257
10258
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10259
                                 const char *fmt, ...) const
10260
0
{
10261
0
    va_list args;
10262
10263
0
    va_start(args, fmt);
10264
10265
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
10266
0
    pszDSName = CPLGetFilename(pszDSName);
10267
0
    if (pszDSName[0] != '\0')
10268
0
    {
10269
0
        CPLError(eErrClass, err_no, "%s",
10270
0
                 CPLString()
10271
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
10272
0
                     .append(CPLString().vPrintf(fmt, args))
10273
0
                     .c_str());
10274
0
    }
10275
0
    else
10276
0
    {
10277
0
        CPLErrorV(eErrClass, err_no, fmt, args);
10278
0
    }
10279
10280
0
    va_end(args);
10281
0
}
10282
#endif
10283
10284
/************************************************************************/
10285
/*                         GetVirtualMemAuto()                          */
10286
/************************************************************************/
10287
10288
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10289
 *
10290
 * Only supported on Linux and Unix systems with mmap() for now.
10291
 *
10292
 * This method allows creating a virtual memory object for a GDALRasterBand,
10293
 * that exposes the whole image data as a virtual array.
10294
 *
10295
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10296
 * specialized implementation, such as for raw files, may also directly use
10297
 * mechanisms of the operating system to create a view of the underlying file
10298
 * into virtual memory ( CPLVirtualMemFileMapNew() )
10299
 *
10300
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10301
 * offer a specialized implementation with direct file mapping, provided that
10302
 * some requirements are met :
10303
 *   - for all drivers, the dataset must be backed by a "real" file in the file
10304
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10305
 *     must match the native ordering of the CPU.
10306
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10307
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10308
 * the file in sequential order, and be equally spaced (which is generally the
10309
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10310
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10311
 *
10312
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
10313
 * CPLVirtualMemFree() must be called before the raster band object is
10314
 * destroyed.
10315
 *
10316
 * If p is such a pointer and base_type the type matching
10317
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10318
 * accessed with
10319
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10320
 *
10321
 * This method is the same as the C GDALGetVirtualMemAuto() function.
10322
 *
10323
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10324
 * read/write the band.
10325
 *
10326
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
10327
 * one pixel value in the buffer to the start of the next pixel value within a
10328
 * scanline.
10329
 *
10330
 * @param pnLineSpace Output parameter giving the byte offset from the start of
10331
 * one scanline in the buffer to the start of the next.
10332
 *
10333
 * @param papszOptions NULL terminated list of options.
10334
 *                     If a specialized implementation exists, defining
10335
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10336
 * used. On the contrary, defining
10337
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10338
 * being used (thus only allowing efficient implementations to be used). When
10339
 * requiring or falling back to the default implementation, the following
10340
 *                     options are available : CACHE_SIZE (in bytes, defaults to
10341
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10342
 * to FALSE)
10343
 *
10344
 * @return a virtual memory object that must be unreferenced by
10345
 * CPLVirtualMemFree(), or NULL in case of failure.
10346
 *
10347
 */
10348
10349
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10350
                                                 int *pnPixelSpace,
10351
                                                 GIntBig *pnLineSpace,
10352
                                                 CSLConstList papszOptions)
10353
0
{
10354
0
    const char *pszImpl = CSLFetchNameValueDef(
10355
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10356
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10357
0
        EQUAL(pszImpl, "FALSE"))
10358
0
    {
10359
0
        return nullptr;
10360
0
    }
10361
10362
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10363
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10364
0
    if (pnPixelSpace)
10365
0
        *pnPixelSpace = nPixelSpace;
10366
0
    if (pnLineSpace)
10367
0
        *pnLineSpace = nLineSpace;
10368
0
    const size_t nCacheSize =
10369
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10370
0
    const size_t nPageSizeHint =
10371
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10372
0
    const bool bSingleThreadUsage = CPLTestBool(
10373
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10374
0
    return GDALRasterBandGetVirtualMem(
10375
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10376
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10377
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10378
0
        papszOptions);
10379
0
}
10380
10381
/************************************************************************/
10382
/*                       GDALGetVirtualMemAuto()                        */
10383
/************************************************************************/
10384
10385
/**
10386
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10387
 *
10388
 * @see GDALRasterBand::GetVirtualMemAuto()
10389
 */
10390
10391
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10392
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
10393
                                     CSLConstList papszOptions)
10394
0
{
10395
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10396
10397
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10398
10399
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10400
0
                                     const_cast<char **>(papszOptions));
10401
0
}
10402
10403
/************************************************************************/
10404
/*                     GDALGetDataCoverageStatus()                      */
10405
/************************************************************************/
10406
10407
/**
10408
 * \brief Get the coverage status of a sub-window of the raster.
10409
 *
10410
 * Returns whether a sub-window of the raster contains only data, only empty
10411
 * blocks or a mix of both. This function can be used to determine quickly
10412
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10413
 * be sparse.
10414
 *
10415
 * Empty blocks are blocks that are generally not physically present in the
10416
 * file, and when read through GDAL, contain only pixels whose value is the
10417
 * nodata value when it is set, or whose value is 0 when the nodata value is
10418
 * not set.
10419
 *
10420
 * The query is done in an efficient way without reading the actual pixel
10421
 * values. If not possible, or not implemented at all by the driver,
10422
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10423
 * be returned.
10424
 *
10425
 * The values that can be returned by the function are the following,
10426
 * potentially combined with the binary or operator :
10427
 * <ul>
10428
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10429
 * GetDataCoverageStatus(). This flag should be returned together with
10430
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10431
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10432
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10433
 * the queried window. This is typically identified by the concept of missing
10434
 * block in formats that supports it.
10435
 * </li>
10436
 * </ul>
10437
 *
10438
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10439
 * should be interpreted more as hint of potential presence of data. For example
10440
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10441
 * nodata value), instead of using the missing block mechanism,
10442
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10443
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10444
 *
10445
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10446
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10447
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10448
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10449
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10450
 * the function will exit, so that you can potentially refine the requested area
10451
 * to find which particular region(s) have missing blocks.
10452
 *
10453
 * @see GDALRasterBand::GetDataCoverageStatus()
10454
 *
10455
 * @param hBand raster band
10456
 *
10457
 * @param nXOff The pixel offset to the top left corner of the region
10458
 * of the band to be queried. This would be zero to start from the left side.
10459
 *
10460
 * @param nYOff The line offset to the top left corner of the region
10461
 * of the band to be queried. This would be zero to start from the top.
10462
 *
10463
 * @param nXSize The width of the region of the band to be queried in pixels.
10464
 *
10465
 * @param nYSize The height of the region of the band to be queried in lines.
10466
 *
10467
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10468
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10469
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10470
 * as the computation of the coverage matches the mask, the computation will be
10471
 * stopped. *pdfDataPct will not be valid in that case.
10472
 *
10473
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10474
 * to the (approximate) percentage in [0,100] of pixels in the queried
10475
 * sub-window that have valid values. The implementation might not always be
10476
 * able to compute it, in which case it will be set to a negative value.
10477
 *
10478
 * @return a binary-or'ed combination of possible values
10479
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10480
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10481
 */
10482
10483
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10484
                                          int nYOff, int nXSize, int nYSize,
10485
                                          int nMaskFlagStop, double *pdfDataPct)
10486
0
{
10487
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10488
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10489
10490
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10491
10492
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10493
0
                                         nMaskFlagStop, pdfDataPct);
10494
0
}
10495
10496
/************************************************************************/
10497
/*                       GetDataCoverageStatus()                        */
10498
/************************************************************************/
10499
10500
/**
10501
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10502
 *                                           int nYOff,
10503
 *                                           int nXSize,
10504
 *                                           int nYSize,
10505
 *                                           int nMaskFlagStop,
10506
 *                                           double* pdfDataPct)
10507
 * \brief Get the coverage status of a sub-window of the raster.
10508
 *
10509
 * Returns whether a sub-window of the raster contains only data, only empty
10510
 * blocks or a mix of both. This function can be used to determine quickly
10511
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10512
 * be sparse.
10513
 *
10514
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10515
 * value when it is set, or whose value is 0 when the nodata value is not set.
10516
 *
10517
 * The query is done in an efficient way without reading the actual pixel
10518
 * values. If not possible, or not implemented at all by the driver,
10519
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10520
 * be returned.
10521
 *
10522
 * The values that can be returned by the function are the following,
10523
 * potentially combined with the binary or operator :
10524
 * <ul>
10525
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10526
 * GetDataCoverageStatus(). This flag should be returned together with
10527
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10528
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10529
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10530
 * the queried window. This is typically identified by the concept of missing
10531
 * block in formats that supports it.
10532
 * </li>
10533
 * </ul>
10534
 *
10535
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10536
 * should be interpreted more as hint of potential presence of data. For example
10537
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10538
 * nodata value), instead of using the missing block mechanism,
10539
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10540
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10541
 *
10542
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10543
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10544
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10545
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10546
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10547
 * the function will exit, so that you can potentially refine the requested area
10548
 * to find which particular region(s) have missing blocks.
10549
 *
10550
 * @see GDALGetDataCoverageStatus()
10551
 *
10552
 * @param nXOff The pixel offset to the top left corner of the region
10553
 * of the band to be queried. This would be zero to start from the left side.
10554
 *
10555
 * @param nYOff The line offset to the top left corner of the region
10556
 * of the band to be queried. This would be zero to start from the top.
10557
 *
10558
 * @param nXSize The width of the region of the band to be queried in pixels.
10559
 *
10560
 * @param nYSize The height of the region of the band to be queried in lines.
10561
 *
10562
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10563
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10564
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10565
 * as the computation of the coverage matches the mask, the computation will be
10566
 * stopped. *pdfDataPct will not be valid in that case.
10567
 *
10568
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10569
 * to the (approximate) percentage in [0,100] of pixels in the queried
10570
 * sub-window that have valid values. The implementation might not always be
10571
 * able to compute it, in which case it will be set to a negative value.
10572
 *
10573
 * @return a binary-or'ed combination of possible values
10574
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10575
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10576
 */
10577
10578
/**
10579
 * \brief Get the coverage status of a sub-window of the raster.
10580
 *
10581
 * Returns whether a sub-window of the raster contains only data, only empty
10582
 * blocks or a mix of both. This function can be used to determine quickly
10583
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10584
 * be sparse.
10585
 *
10586
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10587
 * value when it is set, or whose value is 0 when the nodata value is not set.
10588
 *
10589
 * The query is done in an efficient way without reading the actual pixel
10590
 * values. If not possible, or not implemented at all by the driver,
10591
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10592
 * be returned.
10593
 *
10594
 * The values that can be returned by the function are the following,
10595
 * potentially combined with the binary or operator :
10596
 * <ul>
10597
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10598
 * GetDataCoverageStatus(). This flag should be returned together with
10599
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10600
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10601
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10602
 * the queried window. This is typically identified by the concept of missing
10603
 * block in formats that supports it.
10604
 * </li>
10605
 * </ul>
10606
 *
10607
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10608
 * should be interpreted more as hint of potential presence of data. For example
10609
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10610
 * nodata value), instead of using the missing block mechanism,
10611
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10612
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10613
 *
10614
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10615
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10616
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10617
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10618
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10619
 * the function will exit, so that you can potentially refine the requested area
10620
 * to find which particular region(s) have missing blocks.
10621
 *
10622
 * @see GDALGetDataCoverageStatus()
10623
 *
10624
 * @param nXOff The pixel offset to the top left corner of the region
10625
 * of the band to be queried. This would be zero to start from the left side.
10626
 *
10627
 * @param nYOff The line offset to the top left corner of the region
10628
 * of the band to be queried. This would be zero to start from the top.
10629
 *
10630
 * @param nXSize The width of the region of the band to be queried in pixels.
10631
 *
10632
 * @param nYSize The height of the region of the band to be queried in lines.
10633
 *
10634
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10635
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10636
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10637
 * as the computation of the coverage matches the mask, the computation will be
10638
 * stopped. *pdfDataPct will not be valid in that case.
10639
 *
10640
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10641
 * to the (approximate) percentage in [0,100] of pixels in the queried
10642
 * sub-window that have valid values. The implementation might not always be
10643
 * able to compute it, in which case it will be set to a negative value.
10644
 *
10645
 * @return a binary-or'ed combination of possible values
10646
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10647
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10648
 */
10649
10650
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10651
                                          int nYSize, int nMaskFlagStop,
10652
                                          double *pdfDataPct)
10653
0
{
10654
0
    if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10655
0
        nYSize > nRasterYSize - nYOff)
10656
0
    {
10657
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10658
0
        if (pdfDataPct)
10659
0
            *pdfDataPct = 0.0;
10660
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10661
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
10662
0
    }
10663
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10664
0
                                  pdfDataPct);
10665
0
}
10666
10667
/************************************************************************/
10668
/*                       IGetDataCoverageStatus()                       */
10669
/************************************************************************/
10670
10671
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10672
                                           int /*nXSize*/, int /*nYSize*/,
10673
                                           int /*nMaskFlagStop*/,
10674
                                           double *pdfDataPct)
10675
0
{
10676
0
    if (pdfDataPct != nullptr)
10677
0
        *pdfDataPct = 100.0;
10678
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10679
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
10680
0
}
10681
10682
//! @cond Doxygen_Suppress
10683
/************************************************************************/
10684
/*                           EnterReadWrite()                           */
10685
/************************************************************************/
10686
10687
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10688
0
{
10689
0
    if (poDS != nullptr)
10690
0
        return poDS->EnterReadWrite(eRWFlag);
10691
0
    return FALSE;
10692
0
}
10693
10694
/************************************************************************/
10695
/*                           LeaveReadWrite()                           */
10696
/************************************************************************/
10697
10698
void GDALRasterBand::LeaveReadWrite()
10699
0
{
10700
0
    if (poDS != nullptr)
10701
0
        poDS->LeaveReadWrite();
10702
0
}
10703
10704
/************************************************************************/
10705
/*                             InitRWLock()                             */
10706
/************************************************************************/
10707
10708
void GDALRasterBand::InitRWLock()
10709
0
{
10710
0
    if (poDS != nullptr)
10711
0
        poDS->InitRWLock();
10712
0
}
10713
10714
//! @endcond
10715
10716
// clang-format off
10717
10718
/**
10719
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10720
 * \brief Set metadata.
10721
 *
10722
 * CAUTION: depending on the format, older values of the updated information
10723
 * might still be found in the file in a "ghost" state, even if no longer
10724
 * accessible through the GDAL API. This is for example the case of the GTiff
10725
 * format (this is not a exhaustive list)
10726
 *
10727
 * The C function GDALSetMetadata() does the same thing as this method.
10728
 *
10729
 * @param papszMetadata the metadata in name=value string list format to
10730
 * apply.
10731
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
10732
 * domain.
10733
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10734
 * metadata has been accepted, but is likely not maintained persistently
10735
 * by the underlying object between sessions.
10736
 */
10737
10738
/**
10739
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10740
 * \brief Set single metadata item.
10741
 *
10742
 * CAUTION: depending on the format, older values of the updated information
10743
 * might still be found in the file in a "ghost" state, even if no longer
10744
 * accessible through the GDAL API. This is for example the case of the GTiff
10745
 * format (this is not a exhaustive list)
10746
 *
10747
 * The C function GDALSetMetadataItem() does the same thing as this method.
10748
 *
10749
 * @param pszName the key for the metadata item to fetch.
10750
 * @param pszValue the value to assign to the key.
10751
 * @param pszDomain the domain to set within, use NULL for the default domain.
10752
 *
10753
 * @return CE_None on success, or an error code on failure.
10754
 */
10755
10756
// clang-format on
10757
10758
//! @cond Doxygen_Suppress
10759
/************************************************************************/
10760
/*                  EnablePixelTypeSignedByteWarning()                  */
10761
/************************************************************************/
10762
10763
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10764
0
{
10765
0
    m_bEnablePixelTypeSignedByteWarning = b;
10766
0
}
10767
10768
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10769
0
{
10770
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10771
0
}
10772
10773
//! @endcond
10774
10775
/************************************************************************/
10776
/*                          GetMetadataItem()                           */
10777
/************************************************************************/
10778
10779
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10780
                                            const char *pszDomain)
10781
0
{
10782
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10783
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10784
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10785
0
        EQUAL(pszName, "PIXELTYPE"))
10786
0
    {
10787
0
        CPLError(CE_Warning, CPLE_AppDefined,
10788
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10789
0
                 "used to signal signed 8-bit raster. Change your code to "
10790
0
                 "test for the new GDT_Int8 data type instead.");
10791
0
    }
10792
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10793
0
}
10794
10795
/************************************************************************/
10796
/*                      GDALRasterBandAsMDArray()                       */
10797
/************************************************************************/
10798
10799
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10800
 *
10801
 * The band must be linked to a GDALDataset. If this dataset is not already
10802
 * marked as shared, it will be, so that the returned array holds a reference
10803
 * to it.
10804
 *
10805
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10806
 * returned array will have an associated indexing variable.
10807
 *
10808
 * The returned pointer must be released with GDALMDArrayRelease().
10809
 *
10810
 * This is the same as the C++ method GDALRasterBand::AsMDArray().
10811
 *
10812
 * @return a new array, or NULL.
10813
 *
10814
 * @since GDAL 3.1
10815
 */
10816
GDALMDArrayH GDALRasterBandAsMDArray(GDALRasterBandH hBand)
10817
0
{
10818
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
10819
0
    auto poArray(GDALRasterBand::FromHandle(hBand)->AsMDArray());
10820
0
    if (!poArray)
10821
0
        return nullptr;
10822
0
    return new GDALMDArrayHS(poArray);
10823
0
}
10824
10825
/************************************************************************/
10826
/*                            WindowIterator                            */
10827
/************************************************************************/
10828
10829
//! @cond Doxygen_Suppress
10830
10831
GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10832
                                               int nRasterYSize,
10833
                                               int nBlockXSize, int nBlockYSize,
10834
                                               int nRow, int nCol)
10835
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10836
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10837
0
      m_col(nCol)
10838
0
{
10839
0
}
10840
10841
bool GDALRasterBand::WindowIterator::operator==(
10842
    const WindowIterator &other) const
10843
0
{
10844
0
    return m_row == other.m_row && m_col == other.m_col &&
10845
0
           m_nRasterXSize == other.m_nRasterXSize &&
10846
0
           m_nRasterYSize == other.m_nRasterYSize &&
10847
0
           m_nBlockXSize == other.m_nBlockXSize &&
10848
0
           m_nBlockYSize == other.m_nBlockYSize;
10849
0
}
10850
10851
bool GDALRasterBand::WindowIterator::operator!=(
10852
    const WindowIterator &other) const
10853
0
{
10854
0
    return !(*this == other);
10855
0
}
10856
10857
GDALRasterBand::WindowIterator::value_type
10858
GDALRasterBand::WindowIterator::operator*() const
10859
0
{
10860
0
    GDALRasterWindow ret;
10861
0
    ret.nXOff = m_col * m_nBlockXSize;
10862
0
    ret.nYOff = m_row * m_nBlockYSize;
10863
0
    ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10864
0
    ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10865
10866
0
    return ret;
10867
0
}
10868
10869
GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10870
0
{
10871
0
    m_col++;
10872
0
    if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10873
0
    {
10874
0
        m_col = 0;
10875
0
        m_row++;
10876
0
    }
10877
0
    return *this;
10878
0
}
10879
10880
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10881
    const GDALRasterBand &band, size_t maxSize)
10882
0
    : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10883
0
                            band.nBlockYSize, maxSize)
10884
0
{
10885
0
}
10886
10887
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10888
    const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10889
0
    : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10890
0
                            std::min(band1.GetYSize(), band2.GetYSize()),
10891
0
                            std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10892
0
                            std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10893
0
                            maxSize)
10894
0
{
10895
0
    if (band1.GetXSize() != band2.GetXSize() ||
10896
0
        band1.GetYSize() != band2.GetYSize())
10897
0
    {
10898
0
        CPLError(CE_Warning, CPLE_AppDefined,
10899
0
                 "WindowIteratorWrapper called on bands of different "
10900
0
                 "dimensions. Selecting smallest one");
10901
0
    }
10902
0
}
10903
10904
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10905
                                                             int nRasterYSize,
10906
                                                             int nBlockXSize,
10907
                                                             int nBlockYSize,
10908
                                                             size_t maxSize)
10909
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10910
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10911
0
{
10912
#ifdef CSA_BUILD
10913
    assert(this);
10914
#endif
10915
0
    int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10916
0
    int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10917
10918
0
    if (nXSize < 1 || nYSize < 1)
10919
0
    {
10920
        // If invalid block size is reported, assume scanlines
10921
0
        nXSize = m_nRasterXSize;
10922
0
        nYSize = 1;
10923
0
    }
10924
10925
0
    if (maxSize == 0)
10926
0
    {
10927
0
        m_nBlockXSize = nXSize;
10928
0
        m_nBlockYSize = nYSize;
10929
0
        return;
10930
0
    }
10931
10932
0
    const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10933
0
    const double dfBlocksPerChunk =
10934
0
        static_cast<double>(maxSize) /
10935
0
        (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10936
10937
0
    if (dfBlocksPerChunk < dfBlocksPerRow)
10938
0
    {
10939
0
        m_nBlockXSize = static_cast<int>(std::min<double>(
10940
0
            m_nRasterXSize,
10941
0
            nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10942
0
        m_nBlockYSize = nYSize;
10943
0
    }
10944
0
    else
10945
0
    {
10946
0
        m_nBlockXSize = m_nRasterXSize;
10947
0
        m_nBlockYSize = static_cast<int>(std::min<double>(
10948
0
            m_nRasterYSize,
10949
0
            nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10950
0
    }
10951
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
10952
    {
10953
        if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10954
        {
10955
            m_nBlockXSize = m_nRasterXSize;
10956
            m_nBlockYSize = 1;
10957
        }
10958
    }
10959
0
}
10960
10961
GDALRasterBand::WindowIterator
10962
GDALRasterBand::WindowIteratorWrapper::begin() const
10963
0
{
10964
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10965
0
                          m_nBlockYSize, 0, 0);
10966
0
}
10967
10968
GDALRasterBand::WindowIterator
10969
GDALRasterBand::WindowIteratorWrapper::end() const
10970
0
{
10971
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10972
0
                          m_nBlockYSize,
10973
0
                          DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10974
0
}
10975
10976
uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10977
0
{
10978
0
    return static_cast<uint64_t>(
10979
0
               cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10980
0
           static_cast<uint64_t>(
10981
0
               cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10982
0
}
10983
10984
//! @endcond
10985
10986
/** Return an object whose begin() and end() methods can be used to iterate
10987
 *  over GDALRasterWindow objects that are aligned with blocks in this raster
10988
 *  band. The iteration order is from left to right, then from top to bottom.
10989
 *
10990
\code{.cpp}
10991
    std::vector<double> pixelValues;
10992
    for (const auto& window : poBand->IterateWindows()) {
10993
        CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10994
                                         window.nXSize, window.nYSize);
10995
        // check eErr
10996
    }
10997
\endcode
10998
 *
10999
 *
11000
 *  @param maxSize The maximum number of pixels in each window. If set to
11001
 *         zero (the default), or a number smaller than the block size,
11002
 *         the window size will be the same as the block size.
11003
 *  @since GDAL 3.12
11004
 */
11005
GDALRasterBand::WindowIteratorWrapper
11006
GDALRasterBand::IterateWindows(size_t maxSize) const
11007
0
{
11008
0
    return WindowIteratorWrapper(*this, maxSize);
11009
0
}
11010
11011
/************************************************************************/
11012
/*                MayMultiBlockReadingBeMultiThreaded()                 */
11013
/************************************************************************/
11014
11015
/** Return whether a RasterIO(GF_Read) request spanning over multiple
11016
 * blocks may be accelerated internally using multi-threading.
11017
 *
11018
 * This can be used to determine the best chunk size to read a raster band.
11019
 *
11020
 * Note that such optimizations may require that the window is perfectly aligned
11021
 * on block boundaries and does not involve resampling or data type translation
11022
 * occurs, etc.
11023
 *
11024
 * @since GDAL 3.13
11025
 */
11026
bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
11027
0
{
11028
0
    return false;
11029
0
}
11030
11031
/************************************************************************/
11032
/*                      GDALMDArrayFromRasterBand                       */
11033
/************************************************************************/
11034
11035
class GDALMDArrayFromRasterBand final : public GDALMDArray
11036
{
11037
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
11038
11039
    GDALDataset *m_poDS;
11040
    GDALRasterBand *m_poBand;
11041
    GDALExtendedDataType m_dt;
11042
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11043
    std::string m_osUnit;
11044
    std::vector<GByte> m_pabyNoData{};
11045
    std::shared_ptr<GDALMDArray> m_varX{};
11046
    std::shared_ptr<GDALMDArray> m_varY{};
11047
    std::string m_osFilename{};
11048
    mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11049
11050
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11051
                   const size_t *count, const GInt64 *arrayStep,
11052
                   const GPtrDiff_t *bufferStride,
11053
                   const GDALExtendedDataType &bufferDataType,
11054
                   void *pBuffer) const;
11055
11056
  protected:
11057
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
11058
0
        : GDALAbstractMDArray(std::string(),
11059
0
                              std::string(poDS->GetDescription()) +
11060
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
11061
0
          GDALMDArray(std::string(),
11062
0
                      std::string(poDS->GetDescription()) +
11063
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
11064
0
          m_poDS(poDS), m_poBand(poBand),
11065
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
11066
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
11067
0
    {
11068
0
        m_poDS->Reference();
11069
11070
0
        int bHasNoData = false;
11071
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
11072
0
        {
11073
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
11074
0
            if (bHasNoData)
11075
0
            {
11076
0
                m_pabyNoData.resize(m_dt.GetSize());
11077
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
11078
0
                                m_dt.GetNumericDataType(), 0, 1);
11079
0
            }
11080
0
        }
11081
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
11082
0
        {
11083
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
11084
0
            if (bHasNoData)
11085
0
            {
11086
0
                m_pabyNoData.resize(m_dt.GetSize());
11087
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
11088
0
                                m_dt.GetNumericDataType(), 0, 1);
11089
0
            }
11090
0
        }
11091
0
        else
11092
0
        {
11093
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
11094
0
            if (bHasNoData)
11095
0
            {
11096
0
                m_pabyNoData.resize(m_dt.GetSize());
11097
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
11098
0
                                m_dt.GetNumericDataType(), 0, 1);
11099
0
            }
11100
0
        }
11101
11102
0
        const int nXSize = poBand->GetXSize();
11103
0
        const int nYSize = poBand->GetYSize();
11104
11105
0
        auto poSRS = m_poDS->GetSpatialRef();
11106
0
        std::string osTypeY;
11107
0
        std::string osTypeX;
11108
0
        std::string osDirectionY;
11109
0
        std::string osDirectionX;
11110
0
        if (poSRS && poSRS->GetAxesCount() == 2)
11111
0
        {
11112
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11113
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
11114
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
11115
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
11116
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
11117
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11118
0
            {
11119
0
                if (mapping == std::vector<int>{1, 2})
11120
0
                {
11121
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11122
0
                    osDirectionY = "NORTH";
11123
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11124
0
                    osDirectionX = "EAST";
11125
0
                }
11126
0
            }
11127
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11128
0
            {
11129
0
                if (mapping == std::vector<int>{2, 1})
11130
0
                {
11131
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11132
0
                    osDirectionY = "NORTH";
11133
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11134
0
                    osDirectionX = "EAST";
11135
0
                }
11136
0
            }
11137
0
        }
11138
11139
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11140
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
11141
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
11142
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
11143
11144
0
        GDALGeoTransform gt;
11145
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
11146
0
        {
11147
0
            m_varX = GDALMDArrayRegularlySpaced::Create(
11148
0
                "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
11149
0
            m_dims[1]->SetIndexingVariable(m_varX);
11150
11151
0
            m_varY = GDALMDArrayRegularlySpaced::Create(
11152
0
                "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
11153
0
            m_dims[0]->SetIndexingVariable(m_varY);
11154
0
        }
11155
0
    }
11156
11157
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11158
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11159
               const GDALExtendedDataType &bufferDataType,
11160
               void *pDstBuffer) const override;
11161
11162
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11163
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11164
                const GDALExtendedDataType &bufferDataType,
11165
                const void *pSrcBuffer) override
11166
0
    {
11167
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11168
0
                         bufferStride, bufferDataType,
11169
0
                         const_cast<void *>(pSrcBuffer));
11170
0
    }
11171
11172
  public:
11173
    ~GDALMDArrayFromRasterBand() override
11174
0
    {
11175
0
        m_poDS->ReleaseRef();
11176
0
    }
11177
11178
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11179
                                               GDALRasterBand *poBand)
11180
0
    {
11181
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11182
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
11183
0
        array->SetSelf(array);
11184
0
        return array;
11185
0
    }
11186
11187
    bool IsWritable() const override
11188
0
    {
11189
0
        return m_poDS->GetAccess() == GA_Update;
11190
0
    }
11191
11192
    const std::string &GetFilename() const override
11193
0
    {
11194
0
        return m_osFilename;
11195
0
    }
11196
11197
    const std::vector<std::shared_ptr<GDALDimension>> &
11198
    GetDimensions() const override
11199
0
    {
11200
0
        return m_dims;
11201
0
    }
11202
11203
    const GDALExtendedDataType &GetDataType() const override
11204
0
    {
11205
0
        return m_dt;
11206
0
    }
11207
11208
    const std::string &GetUnit() const override
11209
0
    {
11210
0
        return m_osUnit;
11211
0
    }
11212
11213
    const void *GetRawNoDataValue() const override
11214
0
    {
11215
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11216
0
    }
11217
11218
    double GetOffset(bool *pbHasOffset,
11219
                     GDALDataType *peStorageType) const override
11220
0
    {
11221
0
        int bHasOffset = false;
11222
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
11223
0
        if (pbHasOffset)
11224
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11225
0
        if (peStorageType)
11226
0
            *peStorageType = GDT_Unknown;
11227
0
        return dfRes;
11228
0
    }
11229
11230
    double GetScale(bool *pbHasScale,
11231
                    GDALDataType *peStorageType) const override
11232
0
    {
11233
0
        int bHasScale = false;
11234
0
        double dfRes = m_poBand->GetScale(&bHasScale);
11235
0
        if (pbHasScale)
11236
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
11237
0
        if (peStorageType)
11238
0
            *peStorageType = GDT_Unknown;
11239
0
        return dfRes;
11240
0
    }
11241
11242
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11243
0
    {
11244
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
11245
0
        if (!poSrcSRS)
11246
0
            return nullptr;
11247
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11248
11249
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11250
0
        constexpr int iYDim = 0;
11251
0
        constexpr int iXDim = 1;
11252
0
        for (auto &m : axisMapping)
11253
0
        {
11254
0
            if (m == 1)
11255
0
                m = iXDim + 1;
11256
0
            else if (m == 2)
11257
0
                m = iYDim + 1;
11258
0
            else
11259
0
                m = 0;
11260
0
        }
11261
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11262
0
        return poSRS;
11263
0
    }
11264
11265
    std::vector<GUInt64> GetBlockSize() const override
11266
0
    {
11267
0
        int nBlockXSize = 0;
11268
0
        int nBlockYSize = 0;
11269
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11270
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11271
0
                                    static_cast<GUInt64>(nBlockXSize)};
11272
0
    }
11273
11274
    std::vector<std::shared_ptr<GDALAttribute>>
11275
    GetAttributes(CSLConstList) const override
11276
0
    {
11277
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
11278
0
        auto papszMD = m_poBand->GetMetadata();
11279
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
11280
0
        {
11281
0
            char *pszKey = nullptr;
11282
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11283
0
            if (pszKey && pszValue)
11284
0
            {
11285
0
                res.emplace_back(
11286
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11287
0
            }
11288
0
            CPLFree(pszKey);
11289
0
        }
11290
0
        return res;
11291
0
    }
11292
11293
    int GetOverviewCount() const override
11294
0
    {
11295
0
        return m_poBand->GetOverviewCount();
11296
0
    }
11297
11298
    std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11299
0
    {
11300
0
        const int nOverviews = GetOverviewCount();
11301
0
        if (idx < 0 || idx >= nOverviews)
11302
0
            return nullptr;
11303
0
        m_apoOverviews.resize(nOverviews);
11304
0
        if (!m_apoOverviews[idx])
11305
0
        {
11306
0
            if (auto poOvrBand = m_poBand->GetOverview(idx))
11307
0
            {
11308
0
                if (auto poOvrDS = poOvrBand->GetDataset())
11309
0
                {
11310
0
                    m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11311
0
                }
11312
0
            }
11313
0
        }
11314
0
        return m_apoOverviews[idx];
11315
0
    }
11316
};
11317
11318
bool GDALMDArrayFromRasterBand::IRead(
11319
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11320
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11321
    void *pDstBuffer) const
11322
0
{
11323
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11324
0
                     bufferDataType, pDstBuffer);
11325
0
}
11326
11327
/************************************************************************/
11328
/*                             ReadWrite()                              */
11329
/************************************************************************/
11330
11331
bool GDALMDArrayFromRasterBand::ReadWrite(
11332
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11333
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11334
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11335
0
{
11336
0
    constexpr size_t iDimX = 1;
11337
0
    constexpr size_t iDimY = 0;
11338
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11339
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
11340
0
                                  bufferDataType, pBuffer);
11341
0
}
11342
11343
/************************************************************************/
11344
/*                       GDALMDRasterIOFromBand()                       */
11345
/************************************************************************/
11346
11347
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11348
                            size_t iDimX, size_t iDimY,
11349
                            const GUInt64 *arrayStartIdx, const size_t *count,
11350
                            const GInt64 *arrayStep,
11351
                            const GPtrDiff_t *bufferStride,
11352
                            const GDALExtendedDataType &bufferDataType,
11353
                            void *pBuffer)
11354
0
{
11355
0
    const auto eDT(bufferDataType.GetNumericDataType());
11356
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11357
0
    const int nX =
11358
0
        arrayStep[iDimX] > 0
11359
0
            ? static_cast<int>(arrayStartIdx[iDimX])
11360
0
            : static_cast<int>(arrayStartIdx[iDimX] -
11361
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
11362
0
    const int nY =
11363
0
        arrayStep[iDimY] > 0
11364
0
            ? static_cast<int>(arrayStartIdx[iDimY])
11365
0
            : static_cast<int>(arrayStartIdx[iDimY] -
11366
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
11367
0
    const int nSizeX =
11368
0
        static_cast<int>(count[iDimX] * std::abs(arrayStep[iDimX]));
11369
0
    const int nSizeY =
11370
0
        static_cast<int>(count[iDimY] * std::abs(arrayStep[iDimY]));
11371
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11372
0
    int nStrideXSign = 1;
11373
0
    if (arrayStep[iDimX] < 0)
11374
0
    {
11375
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11376
0
        nStrideXSign = -1;
11377
0
    }
11378
0
    int nStrideYSign = 1;
11379
0
    if (arrayStep[iDimY] < 0)
11380
0
    {
11381
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11382
0
        nStrideYSign = -1;
11383
0
    }
11384
11385
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11386
0
                            static_cast<int>(count[iDimX]),
11387
0
                            static_cast<int>(count[iDimY]), eDT,
11388
0
                            static_cast<GSpacing>(
11389
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
11390
0
                            static_cast<GSpacing>(
11391
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
11392
0
                            nullptr) == CE_None;
11393
0
}
11394
11395
/************************************************************************/
11396
/*                             AsMDArray()                              */
11397
/************************************************************************/
11398
11399
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11400
 *
11401
 * The band must be linked to a GDALDataset. If this dataset is not already
11402
 * marked as shared, it will be, so that the returned array holds a reference
11403
 * to it.
11404
 *
11405
 * If the dataset has a geotransform attached, the X and Y dimensions of the
11406
 * returned array will have an associated indexing variable.
11407
 *
11408
 * This is the same as the C function GDALRasterBandAsMDArray().
11409
 *
11410
 * The "reverse" method is GDALMDArray::AsClassicDataset().
11411
 *
11412
 * @return a new array, or nullptr.
11413
 *
11414
 * @since GDAL 3.1
11415
 */
11416
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11417
0
{
11418
0
    if (!poDS)
11419
0
    {
11420
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11421
0
        return nullptr;
11422
0
    }
11423
0
    if (!poDS->GetShared())
11424
0
    {
11425
0
        poDS->MarkAsShared();
11426
0
    }
11427
0
    return GDALMDArrayFromRasterBand::Create(
11428
0
        poDS, const_cast<GDALRasterBand *>(this));
11429
0
}
11430
11431
/************************************************************************/
11432
/*                         InterpolateAtPoint()                         */
11433
/************************************************************************/
11434
11435
/**
11436
 * \brief Interpolates the value between pixels using a resampling algorithm,
11437
 * taking pixel/line coordinates as input.
11438
 *
11439
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11440
 * @param dfLine line coordinate as a double, where interpolation should be done.
11441
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11442
 * @param pdfRealValue pointer to real part of interpolated value
11443
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11444
 *
11445
 * @return CE_None on success, or an error code on failure.
11446
 * @since GDAL 3.10
11447
 */
11448
11449
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11450
                                          GDALRIOResampleAlg eInterpolation,
11451
                                          double *pdfRealValue,
11452
                                          double *pdfImagValue) const
11453
0
{
11454
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
11455
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11456
0
        eInterpolation != GRIORA_CubicSpline)
11457
0
    {
11458
0
        CPLError(CE_Failure, CPLE_AppDefined,
11459
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
11460
0
                 "methods "
11461
0
                 "allowed");
11462
11463
0
        return CE_Failure;
11464
0
    }
11465
11466
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11467
0
    if (!m_poPointsCache)
11468
0
        m_poPointsCache = new GDALDoublePointsCache();
11469
11470
0
    const bool res =
11471
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11472
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
11473
11474
0
    return res ? CE_None : CE_Failure;
11475
0
}
11476
11477
/************************************************************************/
11478
/*                    GDALRasterInterpolateAtPoint()                    */
11479
/************************************************************************/
11480
11481
/**
11482
 * \brief Interpolates the value between pixels using
11483
 * a resampling algorithm
11484
 *
11485
 * @see GDALRasterBand::InterpolateAtPoint()
11486
 * @since GDAL 3.10
11487
 */
11488
11489
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11490
                                    double dfLine,
11491
                                    GDALRIOResampleAlg eInterpolation,
11492
                                    double *pdfRealValue, double *pdfImagValue)
11493
0
{
11494
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11495
11496
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11497
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11498
0
                                      pdfRealValue, pdfImagValue);
11499
0
}
11500
11501
/************************************************************************/
11502
/*                      InterpolateAtGeolocation()                      */
11503
/************************************************************************/
11504
11505
/**
11506
 * \brief Interpolates the value between pixels using a resampling algorithm,
11507
 * taking georeferenced coordinates as input.
11508
 *
11509
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11510
 * must be in the "natural" SRS of the dataset, that is the one returned by
11511
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11512
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11513
 * array (generally WGS 84) if there is a geolocation array.
11514
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11515
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11516
 * be a easting, and dfGeolocY a northing.
11517
 *
11518
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11519
 * expressed in that CRS, and that tuple must be conformant with the
11520
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11521
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11522
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11523
 * before calling this method, and in that case, dfGeolocX must be a longitude
11524
 * or an easting value, and dfGeolocX a latitude or a northing value.
11525
 *
11526
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11527
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11528
 * it for details on how that transformation is done.
11529
 *
11530
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11531
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11532
 * where interpolation should be done.
11533
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11534
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11535
 * where interpolation should be done.
11536
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11537
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11538
 * @param pdfRealValue pointer to real part of interpolated value
11539
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11540
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11541
 *
11542
 * @return CE_None on success, or an error code on failure.
11543
 * @since GDAL 3.11
11544
 */
11545
11546
CPLErr GDALRasterBand::InterpolateAtGeolocation(
11547
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11548
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11549
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
11550
0
{
11551
0
    double dfPixel;
11552
0
    double dfLine;
11553
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11554
0
                                     &dfLine,
11555
0
                                     papszTransformerOptions) != CE_None)
11556
0
    {
11557
0
        return CE_Failure;
11558
0
    }
11559
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11560
0
                              pdfImagValue);
11561
0
}
11562
11563
/************************************************************************/
11564
/*                 GDALRasterInterpolateAtGeolocation()                 */
11565
/************************************************************************/
11566
11567
/**
11568
 * \brief Interpolates the value between pixels using a resampling algorithm,
11569
 * taking georeferenced coordinates as input.
11570
 *
11571
 * @see GDALRasterBand::InterpolateAtGeolocation()
11572
 * @since GDAL 3.11
11573
 */
11574
11575
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11576
                                          double dfGeolocX, double dfGeolocY,
11577
                                          OGRSpatialReferenceH hSRS,
11578
                                          GDALRIOResampleAlg eInterpolation,
11579
                                          double *pdfRealValue,
11580
                                          double *pdfImagValue,
11581
                                          CSLConstList papszTransformerOptions)
11582
0
{
11583
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11584
11585
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11586
0
    return poBand->InterpolateAtGeolocation(
11587
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11588
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11589
0
}
11590
11591
/************************************************************************/
11592
/*                   GDALRasterBand::SplitRasterIO()                    */
11593
/************************************************************************/
11594
11595
//! @cond Doxygen_Suppress
11596
11597
/** Implements IRasterIO() by dividing the request in 2.
11598
 *
11599
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11600
 *
11601
 * Return CE_Warning if the split could not be done, CE_None in case of
11602
 * success and CE_Failure in case of error.
11603
 *
11604
 * @since 3.12
11605
 */
11606
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11607
                                     [[maybe_unused]] int nXSize,
11608
                                     [[maybe_unused]] int nYSize, void *pData,
11609
                                     int nBufXSize, int nBufYSize,
11610
                                     GDALDataType eBufType,
11611
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
11612
                                     GDALRasterIOExtraArg *psExtraArg)
11613
0
{
11614
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11615
11616
0
    GByte *pabyData = static_cast<GByte *>(pData);
11617
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11618
0
    {
11619
0
        GDALRasterIOExtraArg sArg;
11620
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11621
0
        const int nHalfHeight = nBufYSize / 2;
11622
11623
0
        sArg.pfnProgress = GDALScaledProgress;
11624
0
        sArg.pProgressData = GDALCreateScaledProgress(
11625
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11626
0
        if (sArg.pProgressData == nullptr)
11627
0
            sArg.pfnProgress = nullptr;
11628
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11629
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
11630
0
                                nPixelSpace, nLineSpace, &sArg);
11631
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11632
11633
0
        if (eErr == CE_None)
11634
0
        {
11635
0
            sArg.pfnProgress = GDALScaledProgress;
11636
0
            sArg.pProgressData = GDALCreateScaledProgress(
11637
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11638
0
            if (sArg.pProgressData == nullptr)
11639
0
                sArg.pfnProgress = nullptr;
11640
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11641
0
                             nBufYSize - nHalfHeight,
11642
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
11643
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11644
0
                             nLineSpace, &sArg);
11645
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11646
0
        }
11647
0
        return eErr;
11648
0
    }
11649
0
    else if (nBufXSize >= 2)
11650
0
    {
11651
0
        GDALRasterIOExtraArg sArg;
11652
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11653
0
        const int nHalfWidth = nBufXSize / 2;
11654
11655
0
        sArg.pfnProgress = GDALScaledProgress;
11656
0
        sArg.pProgressData = GDALCreateScaledProgress(
11657
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11658
0
        if (sArg.pProgressData == nullptr)
11659
0
            sArg.pfnProgress = nullptr;
11660
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11661
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
11662
0
                                nPixelSpace, nLineSpace, &sArg);
11663
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11664
11665
0
        if (eErr == CE_None)
11666
0
        {
11667
0
            sArg.pfnProgress = GDALScaledProgress;
11668
0
            sArg.pProgressData = GDALCreateScaledProgress(
11669
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11670
0
            if (sArg.pProgressData == nullptr)
11671
0
                sArg.pfnProgress = nullptr;
11672
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11673
0
                             nBufXSize - nHalfWidth, nBufYSize,
11674
0
                             pabyData + nHalfWidth * nPixelSpace,
11675
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
11676
0
                             nPixelSpace, nLineSpace, &sArg);
11677
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11678
0
        }
11679
0
        return eErr;
11680
0
    }
11681
11682
0
    return CE_Warning;
11683
0
}
11684
11685
//! @endcond
11686
11687
/************************************************************************/
11688
/*                      ThrowIfNotSameDimensions()                      */
11689
/************************************************************************/
11690
11691
//! @cond Doxygen_Suppress
11692
/* static */
11693
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11694
                                              const GDALRasterBand &second)
11695
0
{
11696
0
    if (first.GetXSize() != second.GetXSize() ||
11697
0
        first.GetYSize() != second.GetYSize())
11698
0
    {
11699
0
        throw std::runtime_error("Bands do not have the same dimensions");
11700
0
    }
11701
0
}
11702
11703
//! @endcond
11704
11705
/************************************************************************/
11706
/*                       GDALRasterBandUnaryOp()                        */
11707
/************************************************************************/
11708
11709
/** Apply a unary operation on this band.
11710
 *
11711
 * The resulting band is lazy evaluated. A reference is taken on the input
11712
 * dataset.
11713
 *
11714
 * @since 3.12
11715
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11716
 */
11717
GDALComputedRasterBandH
11718
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11719
                      GDALRasterAlgebraUnaryOperation eOp)
11720
0
{
11721
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11722
0
    GDALComputedRasterBand::Operation cppOp{};
11723
0
    switch (eOp)
11724
0
    {
11725
0
        case GRAUO_LOGICAL_NOT:
11726
0
            return new GDALComputedRasterBand(
11727
0
                GDALComputedRasterBand::Operation::OP_NE,
11728
0
                *(GDALRasterBand::FromHandle(hBand)), true);
11729
0
        case GRAUO_ABS:
11730
0
            cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11731
0
            break;
11732
0
        case GRAUO_SQRT:
11733
0
            cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11734
0
            break;
11735
0
        case GRAUO_LOG:
11736
0
#ifndef HAVE_MUPARSER
11737
0
            CPLError(
11738
0
                CE_Failure, CPLE_NotSupported,
11739
0
                "log(band) not available on a GDAL build without muparser");
11740
0
            return nullptr;
11741
#else
11742
            cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11743
            break;
11744
#endif
11745
0
        case GRAUO_LOG10:
11746
0
            cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11747
0
            break;
11748
0
    }
11749
0
    return new GDALComputedRasterBand(cppOp,
11750
0
                                      *(GDALRasterBand::FromHandle(hBand)));
11751
0
}
11752
11753
/************************************************************************/
11754
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
11755
/************************************************************************/
11756
11757
static GDALComputedRasterBand::Operation
11758
ConvertGDALRasterAlgebraBinaryOperationToCpp(
11759
    GDALRasterAlgebraBinaryOperation eOp)
11760
0
{
11761
0
    switch (eOp)
11762
0
    {
11763
0
        case GRABO_ADD:
11764
0
            return GDALComputedRasterBand::Operation::OP_ADD;
11765
0
        case GRABO_SUB:
11766
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11767
0
        case GRABO_MUL:
11768
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11769
0
        case GRABO_DIV:
11770
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
11771
0
        case GRABO_GT:
11772
0
            return GDALComputedRasterBand::Operation::OP_GT;
11773
0
        case GRABO_GE:
11774
0
            return GDALComputedRasterBand::Operation::OP_GE;
11775
0
        case GRABO_LT:
11776
0
            return GDALComputedRasterBand::Operation::OP_LT;
11777
0
        case GRABO_LE:
11778
0
            return GDALComputedRasterBand::Operation::OP_LE;
11779
0
        case GRABO_EQ:
11780
0
            return GDALComputedRasterBand::Operation::OP_EQ;
11781
0
        case GRABO_NE:
11782
0
            break;
11783
0
        case GRABO_LOGICAL_AND:
11784
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11785
0
        case GRABO_LOGICAL_OR:
11786
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11787
0
        case GRABO_POW:
11788
0
            return GDALComputedRasterBand::Operation::OP_POW;
11789
0
    }
11790
0
    return GDALComputedRasterBand::Operation::OP_NE;
11791
0
}
11792
11793
/************************************************************************/
11794
/*                     GDALRasterBandBinaryOpBand()                     */
11795
/************************************************************************/
11796
11797
/** Apply a binary operation on this band with another one.
11798
 *
11799
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11800
 * "hBand1 - hBand2".
11801
 *
11802
 * The resulting band is lazy evaluated. A reference is taken on both input
11803
 * datasets.
11804
 *
11805
 * @since 3.12
11806
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11807
 */
11808
GDALComputedRasterBandH
11809
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11810
                           GDALRasterAlgebraBinaryOperation eOp,
11811
                           GDALRasterBandH hOtherBand)
11812
0
{
11813
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11814
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11815
0
#ifndef HAVE_MUPARSER
11816
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11817
0
    {
11818
0
        CPLError(
11819
0
            CE_Failure, CPLE_NotSupported,
11820
0
            "Band comparison operators not available on a GDAL build without "
11821
0
            "muparser");
11822
0
        return nullptr;
11823
0
    }
11824
0
    else if (eOp == GRABO_POW)
11825
0
    {
11826
0
        CPLError(
11827
0
            CE_Failure, CPLE_NotSupported,
11828
0
            "pow(band, band) not available on a GDAL build without muparser");
11829
0
        return nullptr;
11830
0
    }
11831
0
#endif
11832
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11833
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11834
0
    try
11835
0
    {
11836
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11837
0
    }
11838
0
    catch (const std::exception &e)
11839
0
    {
11840
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11841
0
        return nullptr;
11842
0
    }
11843
0
    return new GDALComputedRasterBand(
11844
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11845
0
        secondBand);
11846
0
}
11847
11848
/************************************************************************/
11849
/*                    GDALRasterBandBinaryOpDouble()                    */
11850
/************************************************************************/
11851
11852
/** Apply a binary operation on this band with a constant
11853
 *
11854
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11855
 * "hBand - constant".
11856
 *
11857
 * The resulting band is lazy evaluated. A reference is taken on the input
11858
 * dataset.
11859
 *
11860
 * @since 3.12
11861
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11862
 */
11863
GDALComputedRasterBandH
11864
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11865
                             GDALRasterAlgebraBinaryOperation eOp,
11866
                             double constant)
11867
0
{
11868
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11869
0
#ifndef HAVE_MUPARSER
11870
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11871
0
    {
11872
0
        CPLError(
11873
0
            CE_Failure, CPLE_NotSupported,
11874
0
            "Band comparison operators not available on a GDAL build without "
11875
0
            "muparser");
11876
0
        return nullptr;
11877
0
    }
11878
0
#endif
11879
0
    return new GDALComputedRasterBand(
11880
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11881
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
11882
0
}
11883
11884
/************************************************************************/
11885
/*                 GDALRasterBandBinaryOpDoubleToBand()                 */
11886
/************************************************************************/
11887
11888
/** Apply a binary operation on the constant with this band
11889
 *
11890
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11891
 * "constant - hBand".
11892
 *
11893
 * The resulting band is lazy evaluated. A reference is taken on the input
11894
 * dataset.
11895
 *
11896
 * @since 3.12
11897
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11898
 */
11899
GDALComputedRasterBandH
11900
GDALRasterBandBinaryOpDoubleToBand(double constant,
11901
                                   GDALRasterAlgebraBinaryOperation eOp,
11902
                                   GDALRasterBandH hBand)
11903
0
{
11904
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11905
0
#ifndef HAVE_MUPARSER
11906
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11907
0
    {
11908
0
        CPLError(
11909
0
            CE_Failure, CPLE_NotSupported,
11910
0
            "Band comparison operators not available on a GDAL build without "
11911
0
            "muparser");
11912
0
        return nullptr;
11913
0
    }
11914
0
#endif
11915
0
    switch (eOp)
11916
0
    {
11917
0
        case GRABO_ADD:
11918
0
        case GRABO_MUL:
11919
0
        {
11920
0
            return new GDALComputedRasterBand(
11921
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11922
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
11923
0
        }
11924
11925
0
        case GRABO_DIV:
11926
0
        case GRABO_GT:
11927
0
        case GRABO_GE:
11928
0
        case GRABO_LT:
11929
0
        case GRABO_LE:
11930
0
        case GRABO_EQ:
11931
0
        case GRABO_NE:
11932
0
        case GRABO_LOGICAL_AND:
11933
0
        case GRABO_LOGICAL_OR:
11934
0
        case GRABO_POW:
11935
0
        {
11936
0
            return new GDALComputedRasterBand(
11937
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11938
0
                *(GDALRasterBand::FromHandle(hBand)));
11939
0
        }
11940
11941
0
        case GRABO_SUB:
11942
0
        {
11943
0
            break;
11944
0
        }
11945
0
    }
11946
11947
0
    return new GDALComputedRasterBand(
11948
0
        GDALComputedRasterBand::Operation::OP_ADD,
11949
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11950
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
11951
0
        constant);
11952
0
}
11953
11954
/************************************************************************/
11955
/*                             operator+()                              */
11956
/************************************************************************/
11957
11958
/** Add this band with another one.
11959
 *
11960
 * The resulting band is lazy evaluated. A reference is taken on both input
11961
 * datasets.
11962
 *
11963
 * @since 3.12
11964
 * @throw std::runtime_error if both bands do not have the same dimensions.
11965
 */
11966
GDALComputedRasterBand
11967
GDALRasterBand::operator+(const GDALRasterBand &other) const
11968
0
{
11969
0
    ThrowIfNotSameDimensions(*this, other);
11970
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11971
0
                                  *this, other);
11972
0
}
11973
11974
/************************************************************************/
11975
/*                             operator+()                              */
11976
/************************************************************************/
11977
11978
/** Add this band with a constant.
11979
 *
11980
 * The resulting band is lazy evaluated. A reference is taken on the input
11981
 * dataset.
11982
 *
11983
 * @since 3.12
11984
 */
11985
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11986
0
{
11987
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11988
0
                                  *this, constant);
11989
0
}
11990
11991
/************************************************************************/
11992
/*                             operator+()                              */
11993
/************************************************************************/
11994
11995
/** Add a band with a constant.
11996
 *
11997
 * The resulting band is lazy evaluated. A reference is taken on the input
11998
 * dataset.
11999
 *
12000
 * @since 3.12
12001
 */
12002
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
12003
0
{
12004
0
    return other + constant;
12005
0
}
12006
12007
/************************************************************************/
12008
/*                             operator-()                              */
12009
/************************************************************************/
12010
12011
/** Return a band whose value is the opposite value of the band for each
12012
 * pixel.
12013
 *
12014
 * The resulting band is lazy evaluated. A reference is taken on the input
12015
 * dataset.
12016
 *
12017
 * @since 3.12
12018
 */
12019
GDALComputedRasterBand GDALRasterBand::operator-() const
12020
0
{
12021
0
    return 0 - *this;
12022
0
}
12023
12024
/************************************************************************/
12025
/*                             operator-()                              */
12026
/************************************************************************/
12027
12028
/** Subtract this band with another one.
12029
 *
12030
 * The resulting band is lazy evaluated. A reference is taken on both input
12031
 * datasets.
12032
 *
12033
 * @since 3.12
12034
 * @throw std::runtime_error if both bands do not have the same dimensions.
12035
 */
12036
GDALComputedRasterBand
12037
GDALRasterBand::operator-(const GDALRasterBand &other) const
12038
0
{
12039
0
    ThrowIfNotSameDimensions(*this, other);
12040
0
    return GDALComputedRasterBand(
12041
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
12042
0
}
12043
12044
/************************************************************************/
12045
/*                             operator-()                              */
12046
/************************************************************************/
12047
12048
/** Subtract this band with a constant.
12049
 *
12050
 * The resulting band is lazy evaluated. A reference is taken on the input
12051
 * dataset.
12052
 *
12053
 * @since 3.12
12054
 */
12055
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
12056
0
{
12057
0
    return GDALComputedRasterBand(
12058
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
12059
0
}
12060
12061
/************************************************************************/
12062
/*                             operator-()                              */
12063
/************************************************************************/
12064
12065
/** Subtract a constant with a band.
12066
 *
12067
 * The resulting band is lazy evaluated. A reference is taken on the input
12068
 * dataset.
12069
 *
12070
 * @since 3.12
12071
 */
12072
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
12073
0
{
12074
0
    return other * (-1.0) + constant;
12075
0
}
12076
12077
/************************************************************************/
12078
/*                             operator*()                              */
12079
/************************************************************************/
12080
12081
/** Multiply this band with another one.
12082
 *
12083
 * The resulting band is lazy evaluated. A reference is taken on both input
12084
 * datasets.
12085
 *
12086
 * @since 3.12
12087
 * @throw std::runtime_error if both bands do not have the same dimensions.
12088
 */
12089
GDALComputedRasterBand
12090
GDALRasterBand::operator*(const GDALRasterBand &other) const
12091
0
{
12092
0
    ThrowIfNotSameDimensions(*this, other);
12093
0
    return GDALComputedRasterBand(
12094
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
12095
0
}
12096
12097
/************************************************************************/
12098
/*                             operator*()                              */
12099
/************************************************************************/
12100
12101
/** Multiply this band by a constant.
12102
 *
12103
 * The resulting band is lazy evaluated. A reference is taken on the input
12104
 * dataset.
12105
 *
12106
 * @since 3.12
12107
 */
12108
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
12109
0
{
12110
0
    return GDALComputedRasterBand(
12111
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
12112
0
}
12113
12114
/************************************************************************/
12115
/*                             operator*()                              */
12116
/************************************************************************/
12117
12118
/** Multiply a band with a constant.
12119
 *
12120
 * The resulting band is lazy evaluated. A reference is taken on the input
12121
 * dataset.
12122
 *
12123
 * @since 3.12
12124
 */
12125
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12126
0
{
12127
0
    return other * constant;
12128
0
}
12129
12130
/************************************************************************/
12131
/*                             operator/()                              */
12132
/************************************************************************/
12133
12134
/** Divide this band with another one.
12135
 *
12136
 * The resulting band is lazy evaluated. A reference is taken on both input
12137
 * datasets.
12138
 *
12139
 * @since 3.12
12140
 * @throw std::runtime_error if both bands do not have the same dimensions.
12141
 */
12142
GDALComputedRasterBand
12143
GDALRasterBand::operator/(const GDALRasterBand &other) const
12144
0
{
12145
0
    ThrowIfNotSameDimensions(*this, other);
12146
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12147
0
                                  *this, other);
12148
0
}
12149
12150
/************************************************************************/
12151
/*                             operator/()                              */
12152
/************************************************************************/
12153
12154
/** Divide this band by a constant.
12155
 *
12156
 * The resulting band is lazy evaluated. A reference is taken on the input
12157
 * dataset.
12158
 *
12159
 * @since 3.12
12160
 */
12161
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12162
0
{
12163
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12164
0
                                  *this, constant);
12165
0
}
12166
12167
/************************************************************************/
12168
/*                             operator/()                              */
12169
/************************************************************************/
12170
12171
/** Divide a constant by a band.
12172
 *
12173
 * The resulting band is lazy evaluated. A reference is taken on the input
12174
 * dataset.
12175
 *
12176
 * @since 3.12
12177
 */
12178
GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12179
0
{
12180
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12181
0
                                  constant, other);
12182
0
}
12183
12184
/************************************************************************/
12185
/*                         ThrowIfNotMuparser()                         */
12186
/************************************************************************/
12187
12188
#ifndef HAVE_MUPARSER
12189
static GDALComputedRasterBand ThrowIfNotMuparser()
12190
0
{
12191
0
    throw std::runtime_error("Operator not available on a "
12192
0
                             "GDAL build without muparser");
12193
0
}
12194
#endif
12195
12196
/************************************************************************/
12197
/*                             operator>()                              */
12198
/************************************************************************/
12199
12200
/** Return a band whose value is 1 if the pixel value of the left operand
12201
 * is greater than the pixel value of the right operand.
12202
 *
12203
 * The resulting band is lazy evaluated. A reference is taken on the input
12204
 * dataset.
12205
 *
12206
 * @since 3.12
12207
 */
12208
GDALComputedRasterBand
12209
GDALRasterBand::operator>(const GDALRasterBand &other) const
12210
0
{
12211
0
#ifndef HAVE_MUPARSER
12212
0
    (void)other;
12213
0
    return ThrowIfNotMuparser();
12214
#else
12215
    ThrowIfNotSameDimensions(*this, other);
12216
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12217
                                  *this, other);
12218
#endif
12219
0
}
12220
12221
/************************************************************************/
12222
/*                             operator>()                              */
12223
/************************************************************************/
12224
12225
/** Return a band whose value is 1 if the pixel value of the left operand
12226
 * is greater than the constant.
12227
 *
12228
 * The resulting band is lazy evaluated. A reference is taken on the input
12229
 * dataset.
12230
 *
12231
 * @since 3.12
12232
 */
12233
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12234
0
{
12235
0
#ifndef HAVE_MUPARSER
12236
0
    (void)constant;
12237
0
    return ThrowIfNotMuparser();
12238
#else
12239
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12240
                                  *this, constant);
12241
#endif
12242
0
}
12243
12244
/************************************************************************/
12245
/*                             operator>()                              */
12246
/************************************************************************/
12247
12248
/** Return a band whose value is 1 if the constant is greater than the pixel
12249
 * value of the right operand.
12250
 *
12251
 * The resulting band is lazy evaluated. A reference is taken on the input
12252
 * dataset.
12253
 *
12254
 * @since 3.12
12255
 */
12256
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12257
0
{
12258
0
#ifndef HAVE_MUPARSER
12259
0
    (void)constant;
12260
0
    (void)other;
12261
0
    return ThrowIfNotMuparser();
12262
#else
12263
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12264
                                  constant, other);
12265
#endif
12266
0
}
12267
12268
/************************************************************************/
12269
/*                             operator>=()                             */
12270
/************************************************************************/
12271
12272
/** Return a band whose value is 1 if the pixel value of the left operand
12273
 * is greater or equal to the pixel value of the right operand.
12274
 *
12275
 * The resulting band is lazy evaluated. A reference is taken on the input
12276
 * dataset.
12277
 *
12278
 * @since 3.12
12279
 */
12280
GDALComputedRasterBand
12281
GDALRasterBand::operator>=(const GDALRasterBand &other) const
12282
0
{
12283
0
#ifndef HAVE_MUPARSER
12284
0
    (void)other;
12285
0
    return ThrowIfNotMuparser();
12286
#else
12287
    ThrowIfNotSameDimensions(*this, other);
12288
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12289
                                  *this, other);
12290
#endif
12291
0
}
12292
12293
/************************************************************************/
12294
/*                             operator>=()                             */
12295
/************************************************************************/
12296
12297
/** Return a band whose value is 1 if the pixel value of the left operand
12298
 * is greater or equal to the constant.
12299
 *
12300
 * The resulting band is lazy evaluated. A reference is taken on the input
12301
 * dataset.
12302
 *
12303
 * @since 3.12
12304
 */
12305
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12306
0
{
12307
0
#ifndef HAVE_MUPARSER
12308
0
    (void)constant;
12309
0
    return ThrowIfNotMuparser();
12310
#else
12311
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12312
                                  *this, constant);
12313
#endif
12314
0
}
12315
12316
/************************************************************************/
12317
/*                             operator>=()                             */
12318
/************************************************************************/
12319
12320
/** Return a band whose value is 1 if the constant is greater or equal to
12321
 * the pixel value of the right operand.
12322
 *
12323
 * The resulting band is lazy evaluated. A reference is taken on the input
12324
 * dataset.
12325
 *
12326
 * @since 3.12
12327
 */
12328
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12329
0
{
12330
0
#ifndef HAVE_MUPARSER
12331
0
    (void)constant;
12332
0
    (void)other;
12333
0
    return ThrowIfNotMuparser();
12334
#else
12335
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12336
                                  constant, other);
12337
#endif
12338
0
}
12339
12340
/************************************************************************/
12341
/*                             operator<()                              */
12342
/************************************************************************/
12343
12344
/** Return a band whose value is 1 if the pixel value of the left operand
12345
 * is lesser than the pixel value of the right operand.
12346
 *
12347
 * The resulting band is lazy evaluated. A reference is taken on the input
12348
 * dataset.
12349
 *
12350
 * @since 3.12
12351
 */
12352
GDALComputedRasterBand
12353
GDALRasterBand::operator<(const GDALRasterBand &other) const
12354
0
{
12355
0
#ifndef HAVE_MUPARSER
12356
0
    (void)other;
12357
0
    return ThrowIfNotMuparser();
12358
#else
12359
    ThrowIfNotSameDimensions(*this, other);
12360
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12361
                                  *this, other);
12362
#endif
12363
0
}
12364
12365
/************************************************************************/
12366
/*                             operator<()                              */
12367
/************************************************************************/
12368
12369
/** Return a band whose value is 1 if the pixel value of the left operand
12370
 * is lesser than the constant.
12371
 *
12372
 * The resulting band is lazy evaluated. A reference is taken on the input
12373
 * dataset.
12374
 *
12375
 * @since 3.12
12376
 */
12377
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12378
0
{
12379
0
#ifndef HAVE_MUPARSER
12380
0
    (void)constant;
12381
0
    return ThrowIfNotMuparser();
12382
#else
12383
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12384
                                  *this, constant);
12385
#endif
12386
0
}
12387
12388
/************************************************************************/
12389
/*                             operator<()                              */
12390
/************************************************************************/
12391
12392
/** Return a band whose value is 1 if the constant is lesser than the pixel
12393
 * value of the right operand.
12394
 *
12395
 * The resulting band is lazy evaluated. A reference is taken on the input
12396
 * dataset.
12397
 *
12398
 * @since 3.12
12399
 */
12400
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12401
0
{
12402
0
#ifndef HAVE_MUPARSER
12403
0
    (void)constant;
12404
0
    (void)other;
12405
0
    return ThrowIfNotMuparser();
12406
#else
12407
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12408
                                  constant, other);
12409
#endif
12410
0
}
12411
12412
/************************************************************************/
12413
/*                             operator<=()                             */
12414
/************************************************************************/
12415
12416
/** Return a band whose value is 1 if the pixel value of the left operand
12417
 * is lesser or equal to the pixel value of the right operand.
12418
 *
12419
 * The resulting band is lazy evaluated. A reference is taken on the input
12420
 * dataset.
12421
 *
12422
 * @since 3.12
12423
 */
12424
GDALComputedRasterBand
12425
GDALRasterBand::operator<=(const GDALRasterBand &other) const
12426
0
{
12427
0
#ifndef HAVE_MUPARSER
12428
0
    (void)other;
12429
0
    return ThrowIfNotMuparser();
12430
#else
12431
    ThrowIfNotSameDimensions(*this, other);
12432
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12433
                                  *this, other);
12434
#endif
12435
0
}
12436
12437
/************************************************************************/
12438
/*                             operator<=()                             */
12439
/************************************************************************/
12440
12441
/** Return a band whose value is 1 if the pixel value of the left operand
12442
 * is lesser or equal to the constant.
12443
 *
12444
 * The resulting band is lazy evaluated. A reference is taken on the input
12445
 * dataset.
12446
 *
12447
 * @since 3.12
12448
 */
12449
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12450
0
{
12451
0
#ifndef HAVE_MUPARSER
12452
0
    (void)constant;
12453
0
    return ThrowIfNotMuparser();
12454
#else
12455
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12456
                                  *this, constant);
12457
#endif
12458
0
}
12459
12460
/************************************************************************/
12461
/*                             operator<=()                             */
12462
/************************************************************************/
12463
12464
/** Return a band whose value is 1 if the constant is lesser or equal to
12465
 * the pixel value of the right operand.
12466
 *
12467
 * The resulting band is lazy evaluated. A reference is taken on the input
12468
 * dataset.
12469
 *
12470
 * @since 3.12
12471
 */
12472
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12473
0
{
12474
0
#ifndef HAVE_MUPARSER
12475
0
    (void)constant;
12476
0
    (void)other;
12477
0
    return ThrowIfNotMuparser();
12478
#else
12479
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12480
                                  constant, other);
12481
#endif
12482
0
}
12483
12484
/************************************************************************/
12485
/*                             operator==()                             */
12486
/************************************************************************/
12487
12488
/** Return a band whose value is 1 if the pixel value of the left operand
12489
 * is equal to the pixel value of the right operand.
12490
 *
12491
 * The resulting band is lazy evaluated. A reference is taken on the input
12492
 * dataset.
12493
 *
12494
 * @since 3.12
12495
 */
12496
GDALComputedRasterBand
12497
GDALRasterBand::operator==(const GDALRasterBand &other) const
12498
0
{
12499
0
#ifndef HAVE_MUPARSER
12500
0
    (void)other;
12501
0
    return ThrowIfNotMuparser();
12502
#else
12503
    ThrowIfNotSameDimensions(*this, other);
12504
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12505
                                  *this, other);
12506
#endif
12507
0
}
12508
12509
/************************************************************************/
12510
/*                             operator==()                             */
12511
/************************************************************************/
12512
12513
/** Return a band whose value is 1 if the pixel value of the left operand
12514
 * is equal to the constant.
12515
 *
12516
 * The resulting band is lazy evaluated. A reference is taken on the input
12517
 * dataset.
12518
 *
12519
 * @since 3.12
12520
 */
12521
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12522
0
{
12523
0
#ifndef HAVE_MUPARSER
12524
0
    (void)constant;
12525
0
    return ThrowIfNotMuparser();
12526
#else
12527
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12528
                                  *this, constant);
12529
#endif
12530
0
}
12531
12532
/************************************************************************/
12533
/*                             operator==()                             */
12534
/************************************************************************/
12535
12536
/** Return a band whose value is 1 if the constant is equal to
12537
 * the pixel value of the right operand.
12538
 *
12539
 * The resulting band is lazy evaluated. A reference is taken on the input
12540
 * dataset.
12541
 *
12542
 * @since 3.12
12543
 */
12544
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12545
0
{
12546
0
#ifndef HAVE_MUPARSER
12547
0
    (void)constant;
12548
0
    (void)other;
12549
0
    return ThrowIfNotMuparser();
12550
#else
12551
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12552
                                  constant, other);
12553
#endif
12554
0
}
12555
12556
/************************************************************************/
12557
/*                             operator!=()                             */
12558
/************************************************************************/
12559
12560
/** Return a band whose value is 1 if the pixel value of the left operand
12561
 * is different from 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
12569
GDALRasterBand::operator!=(const GDALRasterBand &other) const
12570
0
{
12571
0
#ifndef HAVE_MUPARSER
12572
0
    (void)other;
12573
0
    return ThrowIfNotMuparser();
12574
#else
12575
    ThrowIfNotSameDimensions(*this, other);
12576
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12577
                                  *this, other);
12578
#endif
12579
0
}
12580
12581
/************************************************************************/
12582
/*                             operator!=()                             */
12583
/************************************************************************/
12584
12585
/** Return a band whose value is 1 if the pixel value of the left operand
12586
 * is different from the constant.
12587
 *
12588
 * The resulting band is lazy evaluated. A reference is taken on the input
12589
 * dataset.
12590
 *
12591
 * @since 3.12
12592
 */
12593
GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12594
0
{
12595
0
#ifndef HAVE_MUPARSER
12596
0
    (void)constant;
12597
0
    return ThrowIfNotMuparser();
12598
#else
12599
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12600
                                  *this, constant);
12601
#endif
12602
0
}
12603
12604
/************************************************************************/
12605
/*                             operator!=()                             */
12606
/************************************************************************/
12607
12608
/** Return a band whose value is 1 if the constant is different from
12609
 * the pixel value of the right operand.
12610
 *
12611
 * The resulting band is lazy evaluated. A reference is taken on the input
12612
 * dataset.
12613
 *
12614
 * @since 3.12
12615
 */
12616
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12617
0
{
12618
0
#ifndef HAVE_MUPARSER
12619
0
    (void)constant;
12620
0
    (void)other;
12621
0
    return ThrowIfNotMuparser();
12622
#else
12623
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12624
                                  constant, other);
12625
#endif
12626
0
}
12627
12628
#if defined(__GNUC__)
12629
#pragma GCC diagnostic push
12630
#pragma GCC diagnostic ignored "-Weffc++"
12631
#endif
12632
12633
/************************************************************************/
12634
/*                             operator&&()                             */
12635
/************************************************************************/
12636
12637
/** Return a band whose value is 1 if the pixel value of the left and right
12638
 * operands is true.
12639
 *
12640
 * The resulting band is lazy evaluated. A reference is taken on the input
12641
 * dataset.
12642
 *
12643
 * @since 3.12
12644
 */
12645
GDALComputedRasterBand
12646
GDALRasterBand::operator&&(const GDALRasterBand &other) const
12647
0
{
12648
0
#ifndef HAVE_MUPARSER
12649
0
    (void)other;
12650
0
    return ThrowIfNotMuparser();
12651
#else
12652
    ThrowIfNotSameDimensions(*this, other);
12653
    return GDALComputedRasterBand(
12654
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12655
#endif
12656
0
}
12657
12658
/************************************************************************/
12659
/*                             operator&&()                             */
12660
/************************************************************************/
12661
12662
/** Return a band whose value is 1 if the pixel value of the left operand
12663
 * is true, as well as the constant
12664
 *
12665
 * The resulting band is lazy evaluated. A reference is taken on the input
12666
 * dataset.
12667
 *
12668
 * @since 3.12
12669
 */
12670
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12671
0
{
12672
0
#ifndef HAVE_MUPARSER
12673
0
    (void)constant;
12674
0
    return ThrowIfNotMuparser();
12675
#else
12676
    return GDALComputedRasterBand(
12677
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12678
#endif
12679
0
}
12680
12681
/************************************************************************/
12682
/*                             operator&&()                             */
12683
/************************************************************************/
12684
12685
/** Return a band whose value is 1 if the constant is true, as well as
12686
 * the pixel value of the right operand.
12687
 *
12688
 * The resulting band is lazy evaluated. A reference is taken on the input
12689
 * dataset.
12690
 *
12691
 * @since 3.12
12692
 */
12693
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12694
0
{
12695
0
#ifndef HAVE_MUPARSER
12696
0
    (void)constant;
12697
0
    (void)other;
12698
0
    return ThrowIfNotMuparser();
12699
#else
12700
    return GDALComputedRasterBand(
12701
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12702
#endif
12703
0
}
12704
12705
/************************************************************************/
12706
/*                             operator||()                             */
12707
/************************************************************************/
12708
12709
/** Return a band whose value is 1 if the pixel value of the left or right
12710
 * operands is true.
12711
 *
12712
 * The resulting band is lazy evaluated. A reference is taken on the input
12713
 * dataset.
12714
 *
12715
 * @since 3.12
12716
 */
12717
GDALComputedRasterBand
12718
GDALRasterBand::operator||(const GDALRasterBand &other) const
12719
0
{
12720
0
#ifndef HAVE_MUPARSER
12721
0
    (void)other;
12722
0
    return ThrowIfNotMuparser();
12723
#else
12724
    ThrowIfNotSameDimensions(*this, other);
12725
    return GDALComputedRasterBand(
12726
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12727
#endif
12728
0
}
12729
12730
/************************************************************************/
12731
/*                             operator||()                             */
12732
/************************************************************************/
12733
12734
/** Return a band whose value is 1 if the pixel value of the left operand
12735
 * is true, or if the constant is true
12736
 *
12737
 * The resulting band is lazy evaluated. A reference is taken on the input
12738
 * dataset.
12739
 *
12740
 * @since 3.12
12741
 */
12742
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12743
0
{
12744
0
#ifndef HAVE_MUPARSER
12745
0
    (void)constant;
12746
0
    return ThrowIfNotMuparser();
12747
#else
12748
    return GDALComputedRasterBand(
12749
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12750
#endif
12751
0
}
12752
12753
/************************************************************************/
12754
/*                             operator||()                             */
12755
/************************************************************************/
12756
12757
/** Return a band whose value is 1 if the constant is true, or
12758
 * the pixel value of the right operand is true
12759
 *
12760
 * The resulting band is lazy evaluated. A reference is taken on the input
12761
 * dataset.
12762
 *
12763
 * @since 3.12
12764
 */
12765
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12766
0
{
12767
0
#ifndef HAVE_MUPARSER
12768
0
    (void)constant;
12769
0
    (void)other;
12770
0
    return ThrowIfNotMuparser();
12771
#else
12772
    return GDALComputedRasterBand(
12773
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12774
#endif
12775
0
}
12776
12777
#if defined(__GNUC__)
12778
#pragma GCC diagnostic pop
12779
#endif
12780
12781
/************************************************************************/
12782
/*                             operator!()                              */
12783
/************************************************************************/
12784
12785
/** Return a band whose value is the logical negation of the pixel value
12786
 *
12787
 * The resulting band is lazy evaluated. A reference is taken on the input
12788
 * dataset.
12789
 *
12790
 * @since 3.12
12791
 */
12792
GDALComputedRasterBand GDALRasterBand::operator!() const
12793
0
{
12794
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12795
0
                                  *this, true);
12796
0
}
12797
12798
namespace gdal
12799
{
12800
12801
/************************************************************************/
12802
/*                             IfThenElse()                             */
12803
/************************************************************************/
12804
12805
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12806
 * is not zero, or the one from elseBand otherwise.
12807
 *
12808
 * Variants of this method exits where thenBand and/or elseBand can be double
12809
 * values.
12810
 *
12811
 * The resulting band is lazy evaluated. A reference is taken on the input
12812
 * datasets.
12813
 *
12814
 * This method is the same as the C function GDALRasterBandIfThenElse()
12815
 *
12816
 * @since 3.12
12817
 */
12818
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12819
                                  const GDALRasterBand &thenBand,
12820
                                  const GDALRasterBand &elseBand)
12821
0
{
12822
0
#ifndef HAVE_MUPARSER
12823
0
    (void)condBand;
12824
0
    (void)thenBand;
12825
0
    (void)elseBand;
12826
0
    return ThrowIfNotMuparser();
12827
#else
12828
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12829
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12830
    return GDALComputedRasterBand(
12831
        GDALComputedRasterBand::Operation::OP_TERNARY,
12832
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12833
#endif
12834
0
}
12835
12836
//! @cond Doxygen_Suppress
12837
12838
/************************************************************************/
12839
/*                             IfThenElse()                             */
12840
/************************************************************************/
12841
12842
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12843
 * is not zero, or the one from elseBand otherwise.
12844
 *
12845
 * The resulting band is lazy evaluated. A reference is taken on the input
12846
 * datasets.
12847
 *
12848
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12849
 * with thenBand = (condBand * 0) + thenValue
12850
 *
12851
 * @since 3.12
12852
 */
12853
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12854
                                  double thenValue,
12855
                                  const GDALRasterBand &elseBand)
12856
0
{
12857
0
#ifndef HAVE_MUPARSER
12858
0
    (void)condBand;
12859
0
    (void)thenValue;
12860
0
    (void)elseBand;
12861
0
    return ThrowIfNotMuparser();
12862
#else
12863
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12864
    auto thenBand =
12865
        (condBand * 0)
12866
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12867
        thenValue;
12868
    return GDALComputedRasterBand(
12869
        GDALComputedRasterBand::Operation::OP_TERNARY,
12870
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12871
#endif
12872
0
}
12873
12874
/************************************************************************/
12875
/*                             IfThenElse()                             */
12876
/************************************************************************/
12877
12878
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12879
 * is not zero, or the one from elseValue otherwise.
12880
 *
12881
 * The resulting band is lazy evaluated. A reference is taken on the input
12882
 * datasets.
12883
 *
12884
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12885
 * with elseBand = (condBand * 0) + elseValue
12886
12887
 * @since 3.12
12888
 */
12889
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12890
                                  const GDALRasterBand &thenBand,
12891
                                  double elseValue)
12892
0
{
12893
0
#ifndef HAVE_MUPARSER
12894
0
    (void)condBand;
12895
0
    (void)thenBand;
12896
0
    (void)elseValue;
12897
0
    return ThrowIfNotMuparser();
12898
#else
12899
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12900
    auto elseBand =
12901
        (condBand * 0)
12902
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12903
        elseValue;
12904
    return GDALComputedRasterBand(
12905
        GDALComputedRasterBand::Operation::OP_TERNARY,
12906
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12907
#endif
12908
0
}
12909
12910
/************************************************************************/
12911
/*                             IfThenElse()                             */
12912
/************************************************************************/
12913
12914
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12915
 * is not zero, or the one from elseValue otherwise.
12916
 *
12917
 * The resulting band is lazy evaluated. A reference is taken on the input
12918
 * datasets.
12919
 *
12920
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12921
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12922
 *
12923
 * @since 3.12
12924
 */
12925
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12926
                                  double thenValue, double elseValue)
12927
0
{
12928
0
#ifndef HAVE_MUPARSER
12929
0
    (void)condBand;
12930
0
    (void)thenValue;
12931
0
    (void)elseValue;
12932
0
    return ThrowIfNotMuparser();
12933
#else
12934
    auto thenBand =
12935
        (condBand * 0)
12936
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12937
        thenValue;
12938
    auto elseBand =
12939
        (condBand * 0)
12940
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12941
        elseValue;
12942
    return GDALComputedRasterBand(
12943
        GDALComputedRasterBand::Operation::OP_TERNARY,
12944
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12945
#endif
12946
0
}
12947
12948
//! @endcond
12949
12950
}  // namespace gdal
12951
12952
/************************************************************************/
12953
/*                      GDALRasterBandIfThenElse()                      */
12954
/************************************************************************/
12955
12956
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12957
 * is not zero, or the one from hElseBand otherwise.
12958
 *
12959
 * The resulting band is lazy evaluated. A reference is taken on the input
12960
 * datasets.
12961
 *
12962
 * This function is the same as the C++ method gdal::IfThenElse()
12963
 *
12964
 * @since 3.12
12965
 */
12966
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12967
                                                 GDALRasterBandH hThenBand,
12968
                                                 GDALRasterBandH hElseBand)
12969
0
{
12970
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12971
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12972
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12973
0
#ifndef HAVE_MUPARSER
12974
0
    CPLError(CE_Failure, CPLE_NotSupported,
12975
0
             "Band comparison operators not available on a GDAL build without "
12976
0
             "muparser");
12977
0
    return nullptr;
12978
#else
12979
12980
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12981
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12982
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12983
    try
12984
    {
12985
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12986
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12987
    }
12988
    catch (const std::exception &e)
12989
    {
12990
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12991
        return nullptr;
12992
    }
12993
    return new GDALComputedRasterBand(
12994
        GDALComputedRasterBand::Operation::OP_TERNARY,
12995
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12996
#endif
12997
0
}
12998
12999
/************************************************************************/
13000
/*                       GDALRasterBand::AsType()                       */
13001
/************************************************************************/
13002
13003
/** Cast this band to another type.
13004
 *
13005
 * The resulting band is lazy evaluated. A reference is taken on the input
13006
 * dataset.
13007
 *
13008
 * This method is the same as the C function GDALRasterBandAsDataType()
13009
 *
13010
 * @since 3.12
13011
 */
13012
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
13013
0
{
13014
0
    if (dt == GDT_Unknown)
13015
0
    {
13016
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
13017
0
    }
13018
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
13019
0
                                  *this, dt);
13020
0
}
13021
13022
/************************************************************************/
13023
/*                      GDALRasterBandAsDataType()                      */
13024
/************************************************************************/
13025
13026
/** Cast this band to another type.
13027
 *
13028
 * The resulting band is lazy evaluated. A reference is taken on the input
13029
 * dataset.
13030
 *
13031
 * This function is the same as the C++ method GDALRasterBand::AsType()
13032
 *
13033
 * @since 3.12
13034
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13035
 */
13036
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
13037
                                                 GDALDataType eDT)
13038
0
{
13039
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
13040
0
    if (eDT == GDT_Unknown)
13041
0
    {
13042
0
        CPLError(CE_Failure, CPLE_NotSupported,
13043
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
13044
0
        return nullptr;
13045
0
    }
13046
0
    return new GDALComputedRasterBand(
13047
0
        GDALComputedRasterBand::Operation::OP_CAST,
13048
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
13049
0
}
13050
13051
/************************************************************************/
13052
/*                           GetBandVector()                            */
13053
/************************************************************************/
13054
13055
static std::vector<const GDALRasterBand *>
13056
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
13057
0
{
13058
0
    std::vector<const GDALRasterBand *> bands;
13059
0
    for (size_t i = 0; i < nBandCount; ++i)
13060
0
    {
13061
0
        if (i > 0)
13062
0
        {
13063
0
            GDALRasterBand::ThrowIfNotSameDimensions(
13064
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
13065
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
13066
0
        }
13067
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
13068
0
    }
13069
0
    return bands;
13070
0
}
13071
13072
/************************************************************************/
13073
/*                       GDALOperationOnNBands()                        */
13074
/************************************************************************/
13075
13076
static GDALComputedRasterBandH
13077
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
13078
                      GDALRasterBandH *pahBands)
13079
0
{
13080
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
13081
0
    if (nBandCount == 0)
13082
0
    {
13083
0
        CPLError(CE_Failure, CPLE_AppDefined,
13084
0
                 "At least one band should be passed");
13085
0
        return nullptr;
13086
0
    }
13087
13088
0
    std::vector<const GDALRasterBand *> bands;
13089
0
    try
13090
0
    {
13091
0
        bands = GetBandVector(nBandCount, pahBands);
13092
0
    }
13093
0
    catch (const std::exception &e)
13094
0
    {
13095
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
13096
0
        return nullptr;
13097
0
    }
13098
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
13099
0
}
13100
13101
/************************************************************************/
13102
/*                        GDALMaximumOfNBands()                         */
13103
/************************************************************************/
13104
13105
/** Return a band whose each pixel value is the maximum of the corresponding
13106
 * pixel values in the input bands.
13107
 *
13108
 * The resulting band is lazy evaluated. A reference is taken on input
13109
 * datasets.
13110
 *
13111
 * This function is the same as the C ++ method gdal::max()
13112
 *
13113
 * @since 3.12
13114
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13115
 */
13116
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
13117
                                            GDALRasterBandH *pahBands)
13118
0
{
13119
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
13120
0
                                 nBandCount, pahBands);
13121
0
}
13122
13123
/************************************************************************/
13124
/*                             gdal::max()                              */
13125
/************************************************************************/
13126
13127
namespace gdal
13128
{
13129
/** Return a band whose each pixel value is the maximum of the corresponding
13130
 * pixel values in the inputs (bands or constants)
13131
 *
13132
 * The resulting band is lazy evaluated. A reference is taken on input
13133
 * datasets.
13134
 *
13135
 * Two or more bands can be passed.
13136
 *
13137
 * This method is the same as the C function GDALMaximumOfNBands()
13138
 *
13139
 * @since 3.12
13140
 * @throw std::runtime_error if bands do not have the same dimensions.
13141
 */
13142
GDALComputedRasterBand max(const GDALRasterBand &first,
13143
                           const GDALRasterBand &second)
13144
0
{
13145
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13146
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13147
0
                                  first, second);
13148
0
}
13149
}  // namespace gdal
13150
13151
/************************************************************************/
13152
/*                     GDALRasterBandMaxConstant()                      */
13153
/************************************************************************/
13154
13155
/** Return a band whose each pixel value is the maximum of the corresponding
13156
 * pixel values in the input band and the constant.
13157
 *
13158
 * The resulting band is lazy evaluated. A reference is taken on the input
13159
 * dataset.
13160
 *
13161
 * This function is the same as the C ++ method gdal::max()
13162
 *
13163
 * @since 3.12
13164
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13165
 */
13166
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13167
                                                  double dfConstant)
13168
0
{
13169
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13170
0
        GDALComputedRasterBand::Operation::OP_MAX,
13171
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13172
0
        dfConstant));
13173
0
}
13174
13175
/************************************************************************/
13176
/*                        GDALMinimumOfNBands()                         */
13177
/************************************************************************/
13178
13179
/** Return a band whose each pixel value is the minimum of the corresponding
13180
 * pixel values in the input bands.
13181
 *
13182
 * The resulting band is lazy evaluated. A reference is taken on input
13183
 * datasets.
13184
 *
13185
 * This function is the same as the C ++ method gdal::min()
13186
 *
13187
 * @since 3.12
13188
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13189
 */
13190
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13191
                                            GDALRasterBandH *pahBands)
13192
0
{
13193
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13194
0
                                 nBandCount, pahBands);
13195
0
}
13196
13197
/************************************************************************/
13198
/*                             gdal::min()                              */
13199
/************************************************************************/
13200
13201
namespace gdal
13202
{
13203
/** Return a band whose each pixel value is the minimum of the corresponding
13204
 * pixel values in the inputs (bands or constants)
13205
 *
13206
 * The resulting band is lazy evaluated. A reference is taken on input
13207
 * datasets.
13208
 *
13209
 * Two or more bands can be passed.
13210
 *
13211
 * This method is the same as the C function GDALMinimumOfNBands()
13212
 *
13213
 * @since 3.12
13214
 * @throw std::runtime_error if bands do not have the same dimensions.
13215
 */
13216
GDALComputedRasterBand min(const GDALRasterBand &first,
13217
                           const GDALRasterBand &second)
13218
0
{
13219
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13220
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13221
0
                                  first, second);
13222
0
}
13223
}  // namespace gdal
13224
13225
/************************************************************************/
13226
/*                     GDALRasterBandMinConstant()                      */
13227
/************************************************************************/
13228
13229
/** Return a band whose each pixel value is the minimum of the corresponding
13230
 * pixel values in the input band and the constant.
13231
 *
13232
 * The resulting band is lazy evaluated. A reference is taken on the input
13233
 * dataset.
13234
 *
13235
 * This function is the same as the C ++ method gdal::min()
13236
 *
13237
 * @since 3.12
13238
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13239
 */
13240
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13241
                                                  double dfConstant)
13242
0
{
13243
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13244
0
        GDALComputedRasterBand::Operation::OP_MIN,
13245
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13246
0
        dfConstant));
13247
0
}
13248
13249
/************************************************************************/
13250
/*                          GDALMeanOfNBands()                          */
13251
/************************************************************************/
13252
13253
/** Return a band whose each pixel value is the arithmetic mean of the
13254
 * corresponding pixel values in the input bands.
13255
 *
13256
 * The resulting band is lazy evaluated. A reference is taken on input
13257
 * datasets.
13258
 *
13259
 * This function is the same as the C ++ method gdal::mean()
13260
 *
13261
 * @since 3.12
13262
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13263
 */
13264
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13265
                                         GDALRasterBandH *pahBands)
13266
0
{
13267
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13268
0
                                 nBandCount, pahBands);
13269
0
}
13270
13271
/************************************************************************/
13272
/*                             gdal::mean()                             */
13273
/************************************************************************/
13274
13275
namespace gdal
13276
{
13277
13278
/** Return a band whose each pixel value is the arithmetic mean of the
13279
 * corresponding pixel values in the input bands.
13280
 *
13281
 * The resulting band is lazy evaluated. A reference is taken on input
13282
 * datasets.
13283
 *
13284
 * Two or more bands can be passed.
13285
 *
13286
 * This method is the same as the C function GDALMeanOfNBands()
13287
 *
13288
 * @since 3.12
13289
 * @throw std::runtime_error if bands do not have the same dimensions.
13290
 */
13291
GDALComputedRasterBand mean(const GDALRasterBand &first,
13292
                            const GDALRasterBand &second)
13293
0
{
13294
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13295
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13296
0
                                  first, second);
13297
0
}
13298
}  // namespace gdal
13299
13300
/************************************************************************/
13301
/*                             gdal::abs()                              */
13302
/************************************************************************/
13303
13304
namespace gdal
13305
{
13306
13307
/** Return a band whose each pixel value is the absolute value (or module
13308
 * for complex data type) of the corresponding pixel value in the input band.
13309
 *
13310
 * The resulting band is lazy evaluated. A reference is taken on input
13311
 * datasets.
13312
 *
13313
 * @since 3.12
13314
 */
13315
GDALComputedRasterBand abs(const GDALRasterBand &band)
13316
0
{
13317
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13318
0
                                  band);
13319
0
}
13320
}  // namespace gdal
13321
13322
/************************************************************************/
13323
/*                             gdal::fabs()                             */
13324
/************************************************************************/
13325
13326
namespace gdal
13327
{
13328
13329
/** Return a band whose each pixel value is the absolute value (or module
13330
 * for complex data type) of the corresponding pixel value in the input band.
13331
 *
13332
 * The resulting band is lazy evaluated. A reference is taken on input
13333
 * datasets.
13334
 *
13335
 * @since 3.12
13336
 */
13337
GDALComputedRasterBand fabs(const GDALRasterBand &band)
13338
0
{
13339
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13340
0
                                  band);
13341
0
}
13342
}  // namespace gdal
13343
13344
/************************************************************************/
13345
/*                             gdal::sqrt()                             */
13346
/************************************************************************/
13347
13348
namespace gdal
13349
{
13350
13351
/** Return a band whose each pixel value is the square root of the
13352
 * corresponding pixel value in the input band.
13353
 *
13354
 * The resulting band is lazy evaluated. A reference is taken on input
13355
 * datasets.
13356
 *
13357
 * @since 3.12
13358
 */
13359
GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13360
0
{
13361
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13362
0
                                  band);
13363
0
}
13364
}  // namespace gdal
13365
13366
/************************************************************************/
13367
/*                             gdal::log()                              */
13368
/************************************************************************/
13369
13370
namespace gdal
13371
{
13372
13373
/** Return a band whose each pixel value is the natural logarithm of the
13374
 * corresponding pixel value in the input band.
13375
 *
13376
 * The resulting band is lazy evaluated. A reference is taken on input
13377
 * datasets.
13378
 *
13379
 * @since 3.12
13380
 */
13381
GDALComputedRasterBand log(const GDALRasterBand &band)
13382
0
{
13383
0
#ifndef HAVE_MUPARSER
13384
0
    (void)band;
13385
0
    return ThrowIfNotMuparser();
13386
#else
13387
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13388
                                  band);
13389
#endif
13390
0
}
13391
}  // namespace gdal
13392
13393
/************************************************************************/
13394
/*                            gdal::log10()                             */
13395
/************************************************************************/
13396
13397
namespace gdal
13398
{
13399
13400
/** Return a band whose each pixel value is the logarithm base 10 of the
13401
 * corresponding pixel value in the input band.
13402
 *
13403
 * The resulting band is lazy evaluated. A reference is taken on input
13404
 * datasets.
13405
 *
13406
 * @since 3.12
13407
 */
13408
GDALComputedRasterBand log10(const GDALRasterBand &band)
13409
0
{
13410
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13411
0
                                  band);
13412
0
}
13413
}  // namespace gdal
13414
13415
/************************************************************************/
13416
/*                             gdal::pow()                              */
13417
/************************************************************************/
13418
13419
namespace gdal
13420
{
13421
13422
#ifndef DOXYGEN_SKIP
13423
/** Return a band whose each pixel value is the constant raised to the power of
13424
 * the corresponding pixel value in the input band.
13425
 *
13426
 * The resulting band is lazy evaluated. A reference is taken on input
13427
 * datasets.
13428
 *
13429
 * @since 3.12
13430
 */
13431
GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13432
0
{
13433
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13434
0
                                  constant, band);
13435
0
}
13436
#endif
13437
13438
}  // namespace gdal
13439
13440
/************************************************************************/
13441
/*                             gdal::pow()                              */
13442
/************************************************************************/
13443
13444
namespace gdal
13445
{
13446
13447
/** Return a band whose each pixel value is the the corresponding pixel value
13448
 * in the input band raised to the power of the constant.
13449
 *
13450
 * The resulting band is lazy evaluated. A reference is taken on input
13451
 * datasets.
13452
 *
13453
 * @since 3.12
13454
 */
13455
GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13456
0
{
13457
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13458
0
                                  band, constant);
13459
0
}
13460
}  // namespace gdal
13461
13462
/************************************************************************/
13463
/*                             gdal::pow()                              */
13464
/************************************************************************/
13465
13466
namespace gdal
13467
{
13468
13469
#ifndef DOXYGEN_SKIP
13470
/** Return a band whose each pixel value is the the corresponding pixel value
13471
 * in the input band1 raised to the power of the corresponding pixel value
13472
 * in the input band2
13473
 *
13474
 * The resulting band is lazy evaluated. A reference is taken on input
13475
 * datasets.
13476
 *
13477
 * @since 3.12
13478
 * @throw std::runtime_error if bands do not have the same dimensions.
13479
 */
13480
GDALComputedRasterBand pow(const GDALRasterBand &band1,
13481
                           const GDALRasterBand &band2)
13482
0
{
13483
0
#ifndef HAVE_MUPARSER
13484
0
    (void)band1;
13485
0
    (void)band2;
13486
0
    return ThrowIfNotMuparser();
13487
#else
13488
    GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13489
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13490
                                  band1, band2);
13491
#endif
13492
0
}
13493
#endif
13494
}  // namespace gdal