Coverage Report

Created: 2025-12-31 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdalrasterband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Base class for format specific band class implementation.  This
5
 *           base class provides default implementation for many methods.
6
 * Author:   Frank Warmerdam, warmerdam@pobox.com
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 1998, Frank Warmerdam
10
 * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14
15
#include "cpl_port.h"
16
#include "cpl_float.h"
17
18
#include <cassert>
19
#include <climits>
20
#include <cmath>
21
#include <cstdarg>
22
#include <cstddef>
23
#include <cstdio>
24
#include <cstdlib>
25
#include <cstring>
26
#include <algorithm>
27
#include <limits>
28
#include <memory>
29
#include <new>
30
#include <type_traits>
31
32
#include "cpl_conv.h"
33
#include "cpl_error.h"
34
#include "cpl_float.h"
35
#include "cpl_progress.h"
36
#include "cpl_string.h"
37
#include "cpl_virtualmem.h"
38
#include "cpl_vsi.h"
39
#include "gdal.h"
40
#include "gdal_abstractbandblockcache.h"
41
#include "gdalantirecursion.h"
42
#include "gdal_rat.h"
43
#include "gdal_rasterband.h"
44
#include "gdal_priv_templates.hpp"
45
#include "gdal_interpolateatpoint.h"
46
#include "gdal_minmax_element.hpp"
47
#include "gdalmultidim_priv.h"
48
49
#if defined(__AVX2__) || defined(__FMA__)
50
#include <immintrin.h>
51
#endif
52
53
/************************************************************************/
54
/*                           GDALRasterBand()                           */
55
/************************************************************************/
56
57
/*! Constructor. Applications should never create GDALRasterBands directly. */
58
59
GDALRasterBand::GDALRasterBand()
60
0
    : GDALRasterBand(
61
0
          CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
62
0
{
63
0
}
64
65
/** Constructor. Applications should never create GDALRasterBands directly.
66
 * @param bForceCachedIOIn Whether cached IO should be forced.
67
 */
68
GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
69
0
    : bForceCachedIO(bForceCachedIOIn)
70
71
0
{
72
0
}
73
74
/************************************************************************/
75
/*                          ~GDALRasterBand()                           */
76
/************************************************************************/
77
78
/*! Destructor. Applications should never destroy GDALRasterBands directly,
79
    instead destroy the GDALDataset. */
80
81
GDALRasterBand::~GDALRasterBand()
82
83
0
{
84
0
    if (poDS && poDS->IsMarkedSuppressOnClose())
85
0
    {
86
0
        if (poBandBlockCache)
87
0
            poBandBlockCache->DisableDirtyBlockWriting();
88
0
    }
89
0
    GDALRasterBand::FlushCache(true);
90
91
0
    delete poBandBlockCache;
92
93
0
    if (static_cast<GIntBig>(nBlockReads) >
94
0
            static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
95
0
        nBand == 1 && poDS != nullptr)
96
0
    {
97
0
        CPLDebug(
98
0
            "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
99
0
            nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
100
0
            poDS->GetDescription());
101
0
    }
102
103
0
    InvalidateMaskBand();
104
0
    nBand = -nBand;
105
106
0
    delete m_poPointsCache;
107
0
}
108
109
/************************************************************************/
110
/*                              RasterIO()                              */
111
/************************************************************************/
112
113
/**
114
 * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
115
 *                                int nXOff, int nYOff, int nXSize, int nYSize,
116
 *                                void * pData, int nBufXSize, int nBufYSize,
117
 *                                GDALDataType eBufType,
118
 *                                GSpacing nPixelSpace,
119
 *                                GSpacing nLineSpace,
120
 *                                GDALRasterIOExtraArg* psExtraArg )
121
 * \brief Read/write a region of image data for this band.
122
 *
123
 * This method allows reading a region of a GDALRasterBand into a buffer,
124
 * or writing data from a buffer into a region of a GDALRasterBand. It
125
 * automatically takes care of data type translation if the data type
126
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
127
 * The method also takes care of image decimation / replication if the
128
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
129
 * region being accessed (nXSize x nYSize).
130
 *
131
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
132
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
133
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
134
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
135
 * Or use nLineSpace and a possibly shifted pData value.
136
 *
137
 * The nPixelSpace and nLineSpace parameters allow reading into or
138
 * writing from unusually organized buffers. This is primarily used
139
 * for buffers containing more than one bands raster data in interleaved
140
 * format.
141
 *
142
 * Some formats may efficiently implement decimation into a buffer by
143
 * reading from lower resolution overview images. The logic of the default
144
 * implementation in the base class GDALRasterBand is the following one. It
145
 * computes a target_downscaling_factor from the window of interest and buffer
146
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
147
 * It then walks through overviews and will select the first one whose
148
 * downscaling factor is greater than target_downscaling_factor / 1.2.
149
 *
150
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
151
 * The relationship between target_downscaling_factor and the select overview
152
 * level is the following one:
153
 *
154
 * target_downscaling_factor  | selected_overview
155
 * -------------------------  | -----------------
156
 * ]0,       2 / 1.2]         | full resolution band
157
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
158
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
159
 * ]8 / 1.2, infinity[        | 8x downsampled band
160
 *
161
 * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
162
 * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
163
 * option. Also note that starting with GDAL 3.9, when the resampling algorithm
164
 * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
165
 * this oversampling threshold defaults to 1. Consequently if there are overviews
166
 * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
167
 * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
168
 *
169
 * For highest performance full resolution data access, read and write
170
 * on "block boundaries" as returned by GetBlockSize(), or use the
171
 * ReadBlock() and WriteBlock() methods.
172
 *
173
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
174
 * functions.
175
 *
176
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
177
 * write a region of data.
178
 *
179
 * @param nXOff The pixel offset to the top left corner of the region
180
 * of the band to be accessed. This would be zero to start from the left side.
181
 *
182
 * @param nYOff The line offset to the top left corner of the region
183
 * of the band to be accessed. This would be zero to start from the top.
184
 *
185
 * @param nXSize The width of the region of the band to be accessed in pixels.
186
 *
187
 * @param nYSize The height of the region of the band to be accessed in lines.
188
 *
189
 * @param pData The buffer into which the data should be read, or from which
190
 * it should be written. This buffer must contain at least nBufXSize *
191
 * nBufYSize words of type eBufType. It is organized in left to right,
192
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
193
 * and nLineSpace parameters.
194
 * Note that even with eRWFlag==GF_Write, the content of the buffer might be
195
 * temporarily modified during the execution of this method (and eventually
196
 * restored back to its original content), so it is not safe to use a buffer
197
 * stored in a read-only section of the calling program.
198
 *
199
 * @param nBufXSize the width of the buffer image into which the desired region
200
 * is to be read, or from which it is to be written.
201
 *
202
 * @param nBufYSize the height of the buffer image into which the desired region
203
 * is to be read, or from which it is to be written.
204
 *
205
 * @param eBufType the type of the pixel values in the pData data buffer. The
206
 * pixel values will automatically be translated to/from the GDALRasterBand
207
 * data type as needed. Most driver implementations will use GDALCopyWords64()
208
 * to perform data type translation.
209
 *
210
 * @param nPixelSpace The byte offset from the start of one pixel value in
211
 * pData to the start of the next pixel value within a scanline. If defaulted
212
 * (0) the size of the datatype eBufType is used.
213
 *
214
 * @param nLineSpace The byte offset from the start of one scanline in
215
 * pData to the start of the next. If defaulted (0) the size of the datatype
216
 * eBufType * nBufXSize is used.
217
 *
218
 * @param psExtraArg Pointer to a GDALRasterIOExtraArg
219
 * structure with additional arguments to specify resampling and progress
220
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
221
 * configuration option can also be defined to override the default resampling
222
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
223
 *
224
 * @return CE_Failure if the access fails, otherwise CE_None.
225
 */
226
227
/**
228
 * \brief Read/write a region of image data for this band.
229
 *
230
 * This method allows reading a region of a GDALRasterBand into a buffer,
231
 * or writing data from a buffer into a region of a GDALRasterBand. It
232
 * automatically takes care of data type translation if the data type
233
 * (eBufType) of the buffer is different than that of the GDALRasterBand.
234
 * The method also takes care of image decimation / replication if the
235
 * buffer size (nBufXSize x nBufYSize) is different than the size of the
236
 * region being accessed (nXSize x nYSize).
237
 *
238
 * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
239
 * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
240
 * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
241
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
242
 * Or use nLineSpace and a possibly shifted pData value.
243
 *
244
 * The nPixelSpace and nLineSpace parameters allow reading into or
245
 * writing from unusually organized buffers. This is primarily used
246
 * for buffers containing more than one bands raster data in interleaved
247
 * format.
248
 *
249
 * Some formats may efficiently implement decimation into a buffer by
250
 * reading from lower resolution overview images. The logic of the default
251
 * implementation in the base class GDALRasterBand is the following one. It
252
 * computes a target_downscaling_factor from the window of interest and buffer
253
 * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
254
 * It then walks through overviews and will select the first one whose
255
 * downscaling factor is greater than target_downscaling_factor / 1.2.
256
 *
257
 * Let's assume we have overviews at downscaling factors 2, 4 and 8.
258
 * The relationship between target_downscaling_factor and the select overview
259
 * level is the following one:
260
 *
261
 * target_downscaling_factor  | selected_overview
262
 * -------------------------  | -----------------
263
 * ]0,       2 / 1.2]         | full resolution band
264
 * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
265
 * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
266
 * ]8 / 1.2, infinity[        | 8x downsampled band
267
 *
268
 * For highest performance full resolution data access, read and write
269
 * on "block boundaries" as returned by GetBlockSize(), or use the
270
 * ReadBlock() and WriteBlock() methods.
271
 *
272
 * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
273
 * functions.
274
 *
275
 * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
276
 * more convenient to use for most common use cases.
277
 *
278
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
279
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
280
 * instance of this dataset) concurrently from several threads.
281
 *
282
 * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
283
 * write a region of data.
284
 *
285
 * @param nXOff The pixel offset to the top left corner of the region
286
 * of the band to be accessed. This would be zero to start from the left side.
287
 *
288
 * @param nYOff The line offset to the top left corner of the region
289
 * of the band to be accessed. This would be zero to start from the top.
290
 *
291
 * @param nXSize The width of the region of the band to be accessed in pixels.
292
 *
293
 * @param nYSize The height of the region of the band to be accessed in lines.
294
 *
295
 * @param[in,out] pData The buffer into which the data should be read, or from
296
 * which it should be written. This buffer must contain at least nBufXSize *
297
 * nBufYSize words of type eBufType. It is organized in left to right,
298
 * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
299
 * and nLineSpace parameters.
300
 *
301
 * @param nBufXSize the width of the buffer image into which the desired region
302
 * is to be read, or from which it is to be written.
303
 *
304
 * @param nBufYSize the height of the buffer image into which the desired region
305
 * is to be read, or from which it is to be written.
306
 *
307
 * @param eBufType the type of the pixel values in the pData data buffer. The
308
 * pixel values will automatically be translated to/from the GDALRasterBand
309
 * data type as needed.
310
 *
311
 * @param nPixelSpace The byte offset from the start of one pixel value in
312
 * pData to the start of the next pixel value within a scanline. If defaulted
313
 * (0) the size of the datatype eBufType is used.
314
 *
315
 * @param nLineSpace The byte offset from the start of one scanline in
316
 * pData to the start of the next. If defaulted (0) the size of the datatype
317
 * eBufType * nBufXSize is used.
318
 *
319
 * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
320
 * structure with additional arguments to specify resampling and progress
321
 * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
322
 * configuration option can also be defined to override the default resampling
323
 * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
324
 *
325
 * @return CE_Failure if the access fails, otherwise CE_None.
326
 *
327
 * @see GDALRasterBand::ReadRaster()
328
 */
329
330
CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
331
                                int nXSize, int nYSize, void *pData,
332
                                int nBufXSize, int nBufYSize,
333
                                GDALDataType eBufType, GSpacing nPixelSpace,
334
                                GSpacing nLineSpace,
335
                                GDALRasterIOExtraArg *psExtraArg)
336
337
0
{
338
0
    GDALRasterIOExtraArg sExtraArg;
339
0
    if (psExtraArg == nullptr)
340
0
    {
341
0
        INIT_RASTERIO_EXTRA_ARG(sExtraArg);
342
0
        psExtraArg = &sExtraArg;
343
0
    }
344
0
    else if (CPL_UNLIKELY(psExtraArg->nVersion >
345
0
                          RASTERIO_EXTRA_ARG_CURRENT_VERSION))
346
0
    {
347
0
        ReportError(CE_Failure, CPLE_AppDefined,
348
0
                    "Unhandled version of GDALRasterIOExtraArg");
349
0
        return CE_Failure;
350
0
    }
351
352
0
    GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
353
0
                                       nBufYSize);
354
355
0
    if (CPL_UNLIKELY(nullptr == pData))
356
0
    {
357
0
        ReportError(CE_Failure, CPLE_AppDefined,
358
0
                    "The buffer into which the data should be read is null");
359
0
        return CE_Failure;
360
0
    }
361
362
    /* -------------------------------------------------------------------- */
363
    /*      Some size values are "noop".  Lets just return to avoid         */
364
    /*      stressing lower level functions.                                */
365
    /* -------------------------------------------------------------------- */
366
0
    if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
367
0
                     nBufYSize < 1))
368
0
    {
369
0
        CPLDebug("GDAL",
370
0
                 "RasterIO() skipped for odd window or buffer size.\n"
371
0
                 "  Window = (%d,%d)x%dx%d\n"
372
0
                 "  Buffer = %dx%d\n",
373
0
                 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
374
375
0
        return CE_None;
376
0
    }
377
378
0
    if (eRWFlag == GF_Write)
379
0
    {
380
0
        if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
381
0
        {
382
0
            ReportError(eFlushBlockErr, CPLE_AppDefined,
383
0
                        "An error occurred while writing a dirty block "
384
0
                        "from GDALRasterBand::RasterIO");
385
0
            CPLErr eErr = eFlushBlockErr;
386
0
            eFlushBlockErr = CE_None;
387
0
            return eErr;
388
0
        }
389
0
        if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
390
0
        {
391
0
            return CE_Failure;
392
0
        }
393
0
    }
394
395
    /* -------------------------------------------------------------------- */
396
    /*      If pixel and line spacing are defaulted assign reasonable      */
397
    /*      value assuming a packed buffer.                                 */
398
    /* -------------------------------------------------------------------- */
399
0
    if (nPixelSpace == 0)
400
0
    {
401
0
        nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
402
0
    }
403
404
0
    if (nLineSpace == 0)
405
0
    {
406
0
        nLineSpace = nPixelSpace * nBufXSize;
407
0
    }
408
409
    /* -------------------------------------------------------------------- */
410
    /*      Do some validation of parameters.                               */
411
    /* -------------------------------------------------------------------- */
412
0
    if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
413
0
                     nXOff + nXSize > nRasterXSize || nYOff < 0 ||
414
0
                     nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
415
0
    {
416
0
        ReportError(CE_Failure, CPLE_IllegalArg,
417
0
                    "Access window out of range in RasterIO().  Requested\n"
418
0
                    "(%d,%d) of size %dx%d on raster of %dx%d.",
419
0
                    nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
420
0
        return CE_Failure;
421
0
    }
422
423
0
    if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
424
0
    {
425
0
        ReportError(
426
0
            CE_Failure, CPLE_IllegalArg,
427
0
            "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
428
0
            eRWFlag);
429
0
        return CE_Failure;
430
0
    }
431
0
    if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
432
0
    {
433
0
        ReportError(CE_Failure, CPLE_IllegalArg,
434
0
                    "Illegal GDT_Unknown/GDT_TypeCount argument");
435
0
        return CE_Failure;
436
0
    }
437
438
0
    return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
439
0
                            nBufXSize, nBufYSize, eBufType, nPixelSpace,
440
0
                            nLineSpace, psExtraArg);
441
0
}
442
443
/************************************************************************/
444
/*                         RasterIOInternal()                           */
445
/************************************************************************/
446
447
CPLErr GDALRasterBand::RasterIOInternal(
448
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
449
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
450
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
451
0
{
452
    /* -------------------------------------------------------------------- */
453
    /*      Call the format specific function.                              */
454
    /* -------------------------------------------------------------------- */
455
456
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
457
458
0
    CPLErr eErr;
459
0
    if (bForceCachedIO)
460
0
        eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
461
0
                                         pData, nBufXSize, nBufYSize, eBufType,
462
0
                                         nPixelSpace, nLineSpace, psExtraArg);
463
0
    else
464
0
        eErr =
465
0
            IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
466
0
                      nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
467
468
0
    if (bCallLeaveReadWrite)
469
0
        LeaveReadWrite();
470
471
0
    return eErr;
472
0
}
473
474
/************************************************************************/
475
/*                            GDALRasterIO()                            */
476
/************************************************************************/
477
478
/**
479
 * \brief Read/write a region of image data for this band.
480
 *
481
 * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
482
 * resolution, progress callback, etc. are needed)
483
 *
484
 * @see GDALRasterBand::RasterIO()
485
 */
486
487
CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
488
                                int nXOff, int nYOff, int nXSize, int nYSize,
489
                                void *pData, int nBufXSize, int nBufYSize,
490
                                GDALDataType eBufType, int nPixelSpace,
491
                                int nLineSpace)
492
493
0
{
494
0
    VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
495
496
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
497
498
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
499
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
500
0
                             nLineSpace, nullptr));
501
0
}
502
503
/************************************************************************/
504
/*                            GDALRasterIOEx()                          */
505
/************************************************************************/
506
507
/**
508
 * \brief Read/write a region of image data for this band.
509
 *
510
 * @see GDALRasterBand::RasterIO()
511
 */
512
513
CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
514
                                  int nXOff, int nYOff, int nXSize, int nYSize,
515
                                  void *pData, int nBufXSize, int nBufYSize,
516
                                  GDALDataType eBufType, GSpacing nPixelSpace,
517
                                  GSpacing nLineSpace,
518
                                  GDALRasterIOExtraArg *psExtraArg)
519
520
0
{
521
0
    VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
522
523
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
524
525
0
    return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
526
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
527
0
                             nLineSpace, psExtraArg));
528
0
}
529
530
/************************************************************************/
531
/*                           GetGDTFromCppType()                        */
532
/************************************************************************/
533
534
namespace
535
{
536
template <class T> struct GetGDTFromCppType;
537
538
#define DEFINE_GetGDTFromCppType(T, eDT)                                       \
539
    template <> struct GetGDTFromCppType<T>                                    \
540
    {                                                                          \
541
        static constexpr GDALDataType GDT = eDT;                               \
542
    }
543
544
DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
545
DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
546
DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
547
DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
548
DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
549
DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
550
DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
551
DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
552
DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
553
DEFINE_GetGDTFromCppType(float, GDT_Float32);
554
DEFINE_GetGDTFromCppType(double, GDT_Float64);
555
// Not allowed by C++ standard
556
//DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
557
//DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
558
DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
559
DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
560
}  // namespace
561
562
/************************************************************************/
563
/*                           ReadRaster()                               */
564
/************************************************************************/
565
566
// clang-format off
567
/** Read a region of image data for this band.
568
 *
569
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
570
 * for common use cases, like reading a whole band.
571
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
572
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
573
 * float, double, std::complex<float|double>.
574
 *
575
 * 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>&,
576
 * and can allocate memory automatically.
577
 *
578
 * To read a whole band (assuming it fits into memory), as an array of double:
579
 *
580
\code{.cpp}
581
 double* myArray = static_cast<double*>(
582
     VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
583
 // TODO: check here that myArray != nullptr
584
 const size_t nArrayEltCount =
585
     static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
586
 if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
587
 {
588
     // do something
589
 }
590
 VSIFree(myArray)
591
\endcode
592
 *
593
 * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
594
 *
595
\code{.cpp}
596
 double* myArray = static_cast<double*>(
597
     VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
598
 // TODO: check here that myArray != nullptr
599
 const size_t nArrayEltCount = 128 * 128;
600
 if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
601
 {
602
     // do something
603
 }
604
 VSIFree(myArray)
605
\endcode
606
 *
607
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
608
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
609
 * instance of this dataset) concurrently from several threads.
610
 *
611
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
612
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
613
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
614
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
615
 * Or use nLineSpace and a possibly shifted pData value.
616
 *
617
 * @param[out] pData The buffer into which the data should be written.
618
 * This buffer must contain at least nBufXSize *
619
 * nBufYSize words of type T. It is organized in left to right,
620
 * top to bottom pixel order, and fully packed.
621
 * The type of the buffer does not need to be the one of GetDataType(). The
622
 * method will perform data type translation (with potential rounding, clamping)
623
 * if needed.
624
 *
625
 * @param nArrayEltCount Number of values of pData. If non zero, the method will
626
 * check that it is at least greater or equal to nBufXSize * nBufYSize, and
627
 * return in error if it is not. If set to zero, then pData is trusted to be
628
 * large enough.
629
 *
630
 * @param dfXOff The pixel offset to the top left corner of the region
631
 * of the band to be accessed. This would be zero to start from the left side.
632
 * Defaults to 0.
633
 *
634
 * @param dfYOff The line offset to the top left corner of the region
635
 * of the band to be accessed. This would be zero to start from the top.
636
 * Defaults to 0.
637
 *
638
 * @param dfXSize The width of the region of the band to be accessed in pixels.
639
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
640
 * dfXSize is set to the band width.
641
 *
642
 * @param dfYSize The height of the region of the band to be accessed in lines.
643
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
644
 * dfYSize is set to the band height.
645
 *
646
 * @param nBufXSize the width of the buffer image into which the desired region
647
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
648
 * then nBufXSize is initialized with dfXSize.
649
 *
650
 * @param nBufYSize the height of the buffer image into which the desired region
651
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
652
 * then nBufYSize is initialized with dfYSize.
653
 *
654
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
655
 *
656
 * @param pfnProgress Progress function. May be nullptr.
657
 *
658
 * @param pProgressData User data of pfnProgress. May be nullptr.
659
 *
660
 * @return CE_Failure if the access fails, otherwise CE_None.
661
 *
662
 * @see GDALRasterBand::RasterIO()
663
 * @since GDAL 3.10
664
 */
665
// clang-format on
666
667
template <class T>
668
CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
669
                                  double dfXOff, double dfYOff, double dfXSize,
670
                                  double dfYSize, size_t nBufXSize,
671
                                  size_t nBufYSize,
672
                                  GDALRIOResampleAlg eResampleAlg,
673
                                  GDALProgressFunc pfnProgress,
674
                                  void *pProgressData) const
675
0
{
676
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
677
0
    {
678
0
        return CE_Failure;
679
0
    }
680
681
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
682
0
    {
683
0
        dfXSize = nRasterXSize;
684
0
        dfYSize = nRasterYSize;
685
0
    }
686
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
687
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
688
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
689
0
             dfYOff + dfYSize > INT_MAX)
690
0
    {
691
0
        return CE_Failure;
692
0
    }
693
694
0
    GDALRasterIOExtraArg sExtraArg;
695
0
    sExtraArg.nVersion = 1;
696
0
    sExtraArg.eResampleAlg = eResampleAlg;
697
0
    sExtraArg.pfnProgress = pfnProgress;
698
0
    sExtraArg.pProgressData = pProgressData;
699
0
    sExtraArg.bFloatingPointWindowValidity = true;
700
0
    sExtraArg.dfXOff = dfXOff;
701
0
    sExtraArg.dfYOff = dfYOff;
702
0
    sExtraArg.dfXSize = dfXSize;
703
0
    sExtraArg.dfYSize = dfYSize;
704
0
    const int nXOff = static_cast<int>(dfXOff);
705
0
    const int nYOff = static_cast<int>(dfYOff);
706
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
707
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
708
0
    if (nBufXSize == 0 && nBufYSize == 0)
709
0
    {
710
0
        if (static_cast<int>(dfXSize) == dfXSize &&
711
0
            static_cast<int>(dfYSize) == dfYSize)
712
0
        {
713
0
            nBufXSize = static_cast<int>(dfXSize);
714
0
            nBufYSize = static_cast<int>(dfYSize);
715
0
        }
716
0
        else
717
0
        {
718
0
            CPLError(CE_Failure, CPLE_AppDefined,
719
0
                     "nBufXSize and nBufYSize must be provided if dfXSize or "
720
0
                     "dfYSize is not an integer value");
721
0
            return CE_Failure;
722
0
        }
723
0
    }
724
0
    if (nBufXSize == 0 || nBufYSize == 0)
725
0
    {
726
0
        CPLDebug("GDAL",
727
0
                 "RasterIO() skipped for odd window or buffer size.\n"
728
0
                 "  Window = (%d,%d)x%dx%d\n"
729
0
                 "  Buffer = %dx%d\n",
730
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
731
0
                 static_cast<int>(nBufYSize));
732
733
0
        return CE_None;
734
0
    }
735
736
0
    if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
737
0
    {
738
0
        CPLError(CE_Failure, CPLE_AppDefined,
739
0
                 "Provided array is not large enough");
740
0
        return CE_Failure;
741
0
    }
742
743
0
    constexpr GSpacing nPixelSpace = sizeof(T);
744
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
745
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
746
747
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
748
749
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
750
0
                                   static_cast<int>(nBufXSize),
751
0
                                   static_cast<int>(nBufYSize), eBufType,
752
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
753
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
754
755
//! @cond Doxygen_Suppress
756
757
#define INSTANTIATE_READ_RASTER(T)                                             \
758
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
759
        T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
760
        double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
761
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
762
        void *pProgressData) const;
763
764
INSTANTIATE_READ_RASTER(uint8_t)
765
INSTANTIATE_READ_RASTER(int8_t)
766
INSTANTIATE_READ_RASTER(uint16_t)
767
INSTANTIATE_READ_RASTER(int16_t)
768
INSTANTIATE_READ_RASTER(uint32_t)
769
INSTANTIATE_READ_RASTER(int32_t)
770
INSTANTIATE_READ_RASTER(uint64_t)
771
INSTANTIATE_READ_RASTER(int64_t)
772
INSTANTIATE_READ_RASTER(GFloat16)
773
INSTANTIATE_READ_RASTER(float)
774
INSTANTIATE_READ_RASTER(double)
775
// Not allowed by C++ standard
776
// INSTANTIATE_READ_RASTER(std::complex<int16_t>)
777
// INSTANTIATE_READ_RASTER(std::complex<int32_t>)
778
INSTANTIATE_READ_RASTER(std::complex<float>)
779
INSTANTIATE_READ_RASTER(std::complex<double>)
780
781
//! @endcond
782
783
/************************************************************************/
784
/*                           ReadRaster()                               */
785
/************************************************************************/
786
787
/** Read a region of image data for this band.
788
 *
789
 * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
790
 * for common use cases, like reading a whole band.
791
 * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
792
 * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
793
 * float, double, std::complex<float|double>.
794
 *
795
 * To read a whole band (assuming it fits into memory), as a vector of double:
796
 *
797
\code
798
 std::vector<double> myArray;
799
 if (poBand->ReadRaster(myArray) == CE_None)
800
 {
801
     // do something
802
 }
803
\endcode
804
 *
805
 * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
806
 *
807
\code{.cpp}
808
 std::vector<double> myArray;
809
 if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
810
 {
811
     // do something
812
 }
813
\endcode
814
 *
815
 * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
816
 * be called on the same GDALRasterBand instance (or another GDALRasterBand
817
 * instance of this dataset) concurrently from several threads.
818
 *
819
 * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
820
 * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
821
 * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
822
 * If reads larger than the raster space are wished, GDALTranslate() might be used.
823
 * Or use nLineSpace and a possibly shifted pData value.
824
 *
825
 * @param[out] vData The vector into which the data should be written.
826
 * The vector will be resized, if needed, to contain at least nBufXSize *
827
 * nBufYSize values. The values in the vector are organized in left to right,
828
 * top to bottom pixel order, and fully packed.
829
 * The type of the vector does not need to be the one of GetDataType(). The
830
 * method will perform data type translation (with potential rounding, clamping)
831
 * if needed.
832
 *
833
 * @param dfXOff The pixel offset to the top left corner of the region
834
 * of the band to be accessed. This would be zero to start from the left side.
835
 * Defaults to 0.
836
 *
837
 * @param dfYOff The line offset to the top left corner of the region
838
 * of the band to be accessed. This would be zero to start from the top.
839
 * Defaults to 0.
840
 *
841
 * @param dfXSize The width of the region of the band to be accessed in pixels.
842
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
843
 * dfXSize is set to the band width.
844
 *
845
 * @param dfYSize The height of the region of the band to be accessed in lines.
846
 * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
847
 * dfYSize is set to the band height.
848
 *
849
 * @param nBufXSize the width of the buffer image into which the desired region
850
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
851
 * then nBufXSize is initialized with dfXSize.
852
 *
853
 * @param nBufYSize the height of the buffer image into which the desired region
854
 * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
855
 * then nBufYSize is initialized with dfYSize.
856
 *
857
 * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
858
 *
859
 * @param pfnProgress Progress function. May be nullptr.
860
 *
861
 * @param pProgressData User data of pfnProgress. May be nullptr.
862
 *
863
 * @return CE_Failure if the access fails, otherwise CE_None.
864
 *
865
 * @see GDALRasterBand::RasterIO()
866
 * @since GDAL 3.10
867
 */
868
template <class T>
869
CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
870
                                  double dfYOff, double dfXSize, double dfYSize,
871
                                  size_t nBufXSize, size_t nBufYSize,
872
                                  GDALRIOResampleAlg eResampleAlg,
873
                                  GDALProgressFunc pfnProgress,
874
                                  void *pProgressData) const
875
0
{
876
0
    if (((nBufXSize | nBufYSize) >> 31) != 0)
877
0
    {
878
0
        return CE_Failure;
879
0
    }
880
881
0
    if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
882
0
    {
883
0
        dfXSize = nRasterXSize;
884
0
        dfYSize = nRasterYSize;
885
0
    }
886
0
    else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
887
0
             !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
888
0
             !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
889
0
             dfYOff + dfYSize > INT_MAX)
890
0
    {
891
0
        return CE_Failure;
892
0
    }
893
894
0
    GDALRasterIOExtraArg sExtraArg;
895
0
    sExtraArg.nVersion = 1;
896
0
    sExtraArg.eResampleAlg = eResampleAlg;
897
0
    sExtraArg.pfnProgress = pfnProgress;
898
0
    sExtraArg.pProgressData = pProgressData;
899
0
    sExtraArg.bFloatingPointWindowValidity = true;
900
0
    sExtraArg.dfXOff = dfXOff;
901
0
    sExtraArg.dfYOff = dfYOff;
902
0
    sExtraArg.dfXSize = dfXSize;
903
0
    sExtraArg.dfYSize = dfYSize;
904
0
    const int nXOff = static_cast<int>(dfXOff);
905
0
    const int nYOff = static_cast<int>(dfYOff);
906
0
    const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
907
0
    const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
908
0
    if (nBufXSize == 0 && nBufYSize == 0)
909
0
    {
910
0
        if (static_cast<int>(dfXSize) == dfXSize &&
911
0
            static_cast<int>(dfYSize) == dfYSize)
912
0
        {
913
0
            nBufXSize = static_cast<int>(dfXSize);
914
0
            nBufYSize = static_cast<int>(dfYSize);
915
0
        }
916
0
        else
917
0
        {
918
0
            CPLError(CE_Failure, CPLE_AppDefined,
919
0
                     "nBufXSize and nBufYSize must be provided if "
920
0
                     "dfXSize or dfYSize is not an integer value");
921
0
            return CE_Failure;
922
0
        }
923
0
    }
924
0
    if (nBufXSize == 0 || nBufYSize == 0)
925
0
    {
926
0
        CPLDebug("GDAL",
927
0
                 "RasterIO() skipped for odd window or buffer size.\n"
928
0
                 "  Window = (%d,%d)x%dx%d\n"
929
0
                 "  Buffer = %dx%d\n",
930
0
                 nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
931
0
                 static_cast<int>(nBufYSize));
932
933
0
        return CE_None;
934
0
    }
935
936
    if constexpr (SIZEOF_VOIDP < 8)
937
    {
938
        if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
939
        {
940
            CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
941
            return CE_Failure;
942
        }
943
    }
944
945
0
    if (vData.size() < nBufXSize * nBufYSize)
946
0
    {
947
0
        try
948
0
        {
949
0
            vData.resize(nBufXSize * nBufYSize);
950
0
        }
951
0
        catch (const std::exception &)
952
0
        {
953
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
954
0
            return CE_Failure;
955
0
        }
956
0
    }
957
958
0
    constexpr GSpacing nPixelSpace = sizeof(T);
959
0
    const GSpacing nLineSpace = nPixelSpace * nBufXSize;
960
0
    constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
961
962
0
    GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
963
964
0
    return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
965
0
                                   vData.data(), static_cast<int>(nBufXSize),
966
0
                                   static_cast<int>(nBufYSize), eBufType,
967
0
                                   nPixelSpace, nLineSpace, &sExtraArg);
968
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
969
970
//! @cond Doxygen_Suppress
971
972
#define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
973
    template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
974
        std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
975
        double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
976
        GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
977
        void *pProgressData) const;
978
979
INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
980
INSTANTIATE_READ_RASTER_VECTOR(int8_t)
981
INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
982
INSTANTIATE_READ_RASTER_VECTOR(int16_t)
983
INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
984
INSTANTIATE_READ_RASTER_VECTOR(int32_t)
985
INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
986
INSTANTIATE_READ_RASTER_VECTOR(int64_t)
987
INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
988
INSTANTIATE_READ_RASTER_VECTOR(float)
989
INSTANTIATE_READ_RASTER_VECTOR(double)
990
// Not allowed by C++ standard
991
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
992
// INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
993
INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
994
INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
995
996
//! @endcond
997
998
/************************************************************************/
999
/*                             ReadBlock()                              */
1000
/************************************************************************/
1001
1002
/**
1003
 * \brief Read a block of image data efficiently.
1004
 *
1005
 * This method accesses a "natural" block from the raster band without
1006
 * resampling, or data type conversion.  For a more generalized, but
1007
 * potentially less efficient access use RasterIO().
1008
 *
1009
 * This method is the same as the C GDALReadBlock() function.
1010
 *
1011
 * See the GetLockedBlockRef() method for a way of accessing internally cached
1012
 * block oriented data without an extra copy into an application buffer.
1013
 *
1014
 * The following code would efficiently compute a histogram of eight bit
1015
 * raster data.  Note that the final block may be partial ... data beyond
1016
 * the edge of the underlying raster band in these edge blocks is of an
1017
 * undetermined value.
1018
 *
1019
\code{.cpp}
1020
 CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1021
1022
 {
1023
     memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1024
1025
     CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1026
1027
     int nXBlockSize, nYBlockSize;
1028
1029
     poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1030
     int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1031
     int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1032
1033
     GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1034
1035
     for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1036
     {
1037
         for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1038
         {
1039
             int        nXValid, nYValid;
1040
1041
             poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1042
1043
             // Compute the portion of the block that is valid
1044
             // for partial edge blocks.
1045
             poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1046
1047
             // Collect the histogram counts.
1048
             for( int iY = 0; iY < nYValid; iY++ )
1049
             {
1050
                 for( int iX = 0; iX < nXValid; iX++ )
1051
                 {
1052
                     panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1053
                 }
1054
             }
1055
         }
1056
     }
1057
 }
1058
\endcode
1059
 *
1060
 * @param nXBlockOff the horizontal block offset, with zero indicating
1061
 * the left most block, 1 the next block and so forth.
1062
 *
1063
 * @param nYBlockOff the vertical block offset, with zero indicating
1064
 * the top most block, 1 the next block and so forth.
1065
 *
1066
 * @param pImage the buffer into which the data will be read.  The buffer
1067
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1068
 * of type GetRasterDataType().
1069
 *
1070
 * @return CE_None on success or CE_Failure on an error.
1071
 */
1072
1073
CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1074
1075
0
{
1076
    /* -------------------------------------------------------------------- */
1077
    /*      Validate arguments.                                             */
1078
    /* -------------------------------------------------------------------- */
1079
0
    CPLAssert(pImage != nullptr);
1080
1081
0
    if (!InitBlockInfo())
1082
0
        return CE_Failure;
1083
1084
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1085
0
    {
1086
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1087
0
                    "Illegal nXBlockOff value (%d) in "
1088
0
                    "GDALRasterBand::ReadBlock()\n",
1089
0
                    nXBlockOff);
1090
1091
0
        return (CE_Failure);
1092
0
    }
1093
1094
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1095
0
    {
1096
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1097
0
                    "Illegal nYBlockOff value (%d) in "
1098
0
                    "GDALRasterBand::ReadBlock()\n",
1099
0
                    nYBlockOff);
1100
1101
0
        return (CE_Failure);
1102
0
    }
1103
1104
    /* -------------------------------------------------------------------- */
1105
    /*      Invoke underlying implementation method.                        */
1106
    /* -------------------------------------------------------------------- */
1107
1108
0
    int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1109
0
    CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1110
0
    if (bCallLeaveReadWrite)
1111
0
        LeaveReadWrite();
1112
0
    return eErr;
1113
0
}
1114
1115
/************************************************************************/
1116
/*                           GDALReadBlock()                            */
1117
/************************************************************************/
1118
1119
/**
1120
 * \brief Read a block of image data efficiently.
1121
 *
1122
 * @see GDALRasterBand::ReadBlock()
1123
 */
1124
1125
CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1126
                                 void *pData)
1127
1128
0
{
1129
0
    VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1130
1131
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1132
0
    return (poBand->ReadBlock(nXOff, nYOff, pData));
1133
0
}
1134
1135
/************************************************************************/
1136
/*                            IReadBlock()                             */
1137
/************************************************************************/
1138
1139
/** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1140
 * ) \brief Read a block of data.
1141
 *
1142
 * Default internal implementation ... to be overridden by
1143
 * subclasses that support reading.
1144
 * @param nBlockXOff Block X Offset
1145
 * @param nBlockYOff Block Y Offset
1146
 * @param pData Pixel buffer into which to place read data.
1147
 * @return CE_None on success or CE_Failure on an error.
1148
 */
1149
1150
/************************************************************************/
1151
/*                            IWriteBlock()                             */
1152
/************************************************************************/
1153
1154
/**
1155
 * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1156
 * Write a block of data.
1157
 *
1158
 * Default internal implementation ... to be overridden by
1159
 * subclasses that support writing.
1160
 * @param nBlockXOff Block X Offset
1161
 * @param nBlockYOff Block Y Offset
1162
 * @param pData Pixel buffer to write
1163
 * @return CE_None on success or CE_Failure on an error.
1164
 */
1165
1166
/**/
1167
/**/
1168
1169
CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1170
                                   void * /*pData*/)
1171
1172
0
{
1173
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1174
0
        ReportError(CE_Failure, CPLE_NotSupported,
1175
0
                    "WriteBlock() not supported for this dataset.");
1176
1177
0
    return (CE_Failure);
1178
0
}
1179
1180
/************************************************************************/
1181
/*                             WriteBlock()                             */
1182
/************************************************************************/
1183
1184
/**
1185
 * \brief Write a block of image data efficiently.
1186
 *
1187
 * This method accesses a "natural" block from the raster band without
1188
 * resampling, or data type conversion.  For a more generalized, but
1189
 * potentially less efficient access use RasterIO().
1190
 *
1191
 * This method is the same as the C GDALWriteBlock() function.
1192
 *
1193
 * See ReadBlock() for an example of block oriented data access.
1194
 *
1195
 * @param nXBlockOff the horizontal block offset, with zero indicating
1196
 * the left most block, 1 the next block and so forth.
1197
 *
1198
 * @param nYBlockOff the vertical block offset, with zero indicating
1199
 * the left most block, 1 the next block and so forth.
1200
 *
1201
 * @param pImage the buffer from which the data will be written.  The buffer
1202
 * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1203
 * of type GetRasterDataType(). Note that the content of the buffer might be
1204
 * temporarily modified during the execution of this method (and eventually
1205
 * restored back to its original content), so it is not safe to use a buffer
1206
 * stored in a read-only section of the calling program.
1207
 *
1208
 * @return CE_None on success or CE_Failure on an error.
1209
 */
1210
1211
CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1212
1213
0
{
1214
    /* -------------------------------------------------------------------- */
1215
    /*      Validate arguments.                                             */
1216
    /* -------------------------------------------------------------------- */
1217
0
    CPLAssert(pImage != nullptr);
1218
1219
0
    if (!InitBlockInfo())
1220
0
        return CE_Failure;
1221
1222
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1223
0
    {
1224
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1225
0
                    "Illegal nXBlockOff value (%d) in "
1226
0
                    "GDALRasterBand::WriteBlock()\n",
1227
0
                    nXBlockOff);
1228
1229
0
        return (CE_Failure);
1230
0
    }
1231
1232
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1233
0
    {
1234
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1235
0
                    "Illegal nYBlockOff value (%d) in "
1236
0
                    "GDALRasterBand::WriteBlock()\n",
1237
0
                    nYBlockOff);
1238
1239
0
        return (CE_Failure);
1240
0
    }
1241
1242
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1243
0
    {
1244
0
        return CE_Failure;
1245
0
    }
1246
1247
0
    if (eFlushBlockErr != CE_None)
1248
0
    {
1249
0
        ReportError(eFlushBlockErr, CPLE_AppDefined,
1250
0
                    "An error occurred while writing a dirty block "
1251
0
                    "from GDALRasterBand::WriteBlock");
1252
0
        CPLErr eErr = eFlushBlockErr;
1253
0
        eFlushBlockErr = CE_None;
1254
0
        return eErr;
1255
0
    }
1256
1257
    /* -------------------------------------------------------------------- */
1258
    /*      Invoke underlying implementation method.                        */
1259
    /* -------------------------------------------------------------------- */
1260
1261
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1262
0
    CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1263
0
    if (bCallLeaveReadWrite)
1264
0
        LeaveReadWrite();
1265
1266
0
    return eErr;
1267
0
}
1268
1269
/************************************************************************/
1270
/*                           GDALWriteBlock()                           */
1271
/************************************************************************/
1272
1273
/**
1274
 * \brief Write a block of image data efficiently.
1275
 *
1276
 * @see GDALRasterBand::WriteBlock()
1277
 */
1278
1279
CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1280
                                  void *pData)
1281
1282
0
{
1283
0
    VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1284
1285
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1286
0
    return (poBand->WriteBlock(nXOff, nYOff, pData));
1287
0
}
1288
1289
/************************************************************************/
1290
/*                   EmitErrorMessageIfWriteNotSupported()              */
1291
/************************************************************************/
1292
1293
/**
1294
 * Emit an error message if a write operation to this band is not supported.
1295
 *
1296
 * The base implementation will emit an error message if the access mode is
1297
 * read-only. Derived classes may implement it to provide a custom message.
1298
 *
1299
 * @param pszCaller Calling function.
1300
 * @return true if an error message has been emitted.
1301
 */
1302
bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1303
    const char *pszCaller) const
1304
0
{
1305
0
    if (eAccess == GA_ReadOnly)
1306
0
    {
1307
0
        ReportError(CE_Failure, CPLE_NoWriteAccess,
1308
0
                    "%s: attempt to write to dataset opened in read-only mode.",
1309
0
                    pszCaller);
1310
1311
0
        return true;
1312
0
    }
1313
0
    return false;
1314
0
}
1315
1316
/************************************************************************/
1317
/*                         GetActualBlockSize()                         */
1318
/************************************************************************/
1319
/**
1320
 * \brief Fetch the actual block size for a given block offset.
1321
 *
1322
 * Handles partial blocks at the edges of the raster and returns the true
1323
 * number of pixels
1324
 *
1325
 * @param nXBlockOff the horizontal block offset for which to calculate the
1326
 * number of valid pixels, with zero indicating the left most block, 1 the next
1327
 * block and so forth.
1328
 *
1329
 * @param nYBlockOff the vertical block offset, with zero indicating
1330
 * the top most block, 1 the next block and so forth.
1331
 *
1332
 * @param pnXValid pointer to an integer in which the number of valid pixels in
1333
 * the x direction will be stored
1334
 *
1335
 * @param pnYValid pointer to an integer in which the number of valid pixels in
1336
 * the y direction will be stored
1337
 *
1338
 * @return CE_None if the input parameters are valid, CE_Failure otherwise
1339
 *
1340
 */
1341
CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1342
                                          int *pnXValid, int *pnYValid) const
1343
0
{
1344
0
    if (nXBlockOff < 0 || nBlockXSize == 0 ||
1345
0
        nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1346
0
        nYBlockOff < 0 || nBlockYSize == 0 ||
1347
0
        nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1348
0
    {
1349
0
        return CE_Failure;
1350
0
    }
1351
1352
0
    const int nXPixelOff = nXBlockOff * nBlockXSize;
1353
0
    const int nYPixelOff = nYBlockOff * nBlockYSize;
1354
1355
0
    *pnXValid = nBlockXSize;
1356
0
    *pnYValid = nBlockYSize;
1357
1358
0
    if (nXPixelOff >= nRasterXSize - nBlockXSize)
1359
0
    {
1360
0
        *pnXValid = nRasterXSize - nXPixelOff;
1361
0
    }
1362
1363
0
    if (nYPixelOff >= nRasterYSize - nBlockYSize)
1364
0
    {
1365
0
        *pnYValid = nRasterYSize - nYPixelOff;
1366
0
    }
1367
1368
0
    return CE_None;
1369
0
}
1370
1371
/************************************************************************/
1372
/*                           GDALGetActualBlockSize()                   */
1373
/************************************************************************/
1374
1375
/**
1376
 * \brief Retrieve the actual block size for a given block offset.
1377
 *
1378
 * @see GDALRasterBand::GetActualBlockSize()
1379
 */
1380
1381
CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1382
                                          int nYBlockOff, int *pnXValid,
1383
                                          int *pnYValid)
1384
1385
0
{
1386
0
    VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1387
1388
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1389
0
    return (
1390
0
        poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1391
0
}
1392
1393
/************************************************************************/
1394
/*                     GetSuggestedBlockAccessPattern()                 */
1395
/************************************************************************/
1396
1397
/**
1398
 * \brief Return the suggested/most efficient access pattern to blocks
1399
 *        (for read operations).
1400
 *
1401
 * While all GDAL drivers have to expose a block size, not all can guarantee
1402
 * efficient random access (GSBAP_RANDOM) to any block.
1403
 * Some drivers for example decompress sequentially a compressed stream from
1404
 * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1405
 * case best performance will be achieved while reading blocks in that order.
1406
 * (accessing blocks in random access in such rasters typically causes the
1407
 * decoding to be re-initialized from the start if accessing blocks in
1408
 * a non-sequential order)
1409
 *
1410
 * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1411
 * returned by drivers that expose a somewhat artificial block size, because
1412
 * they can extract any part of a raster, but in a rather inefficient way.
1413
 *
1414
 * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1415
 * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1416
 * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1417
 * most efficient strategy is to read as many pixels as possible in the less
1418
 * RasterIO() operations.
1419
 *
1420
 * The return of this method is for example used to determine the swath size
1421
 * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1422
 *
1423
 * @since GDAL 3.6
1424
 */
1425
1426
GDALSuggestedBlockAccessPattern
1427
GDALRasterBand::GetSuggestedBlockAccessPattern() const
1428
0
{
1429
0
    return GSBAP_UNKNOWN;
1430
0
}
1431
1432
/************************************************************************/
1433
/*                         GetRasterDataType()                          */
1434
/************************************************************************/
1435
1436
/**
1437
 * \brief Fetch the pixel data type for this band.
1438
 *
1439
 * This method is the same as the C function GDALGetRasterDataType().
1440
 *
1441
 * @return the data type of pixels for this band.
1442
 */
1443
1444
GDALDataType GDALRasterBand::GetRasterDataType() const
1445
1446
0
{
1447
0
    return eDataType;
1448
0
}
1449
1450
/************************************************************************/
1451
/*                       GDALGetRasterDataType()                        */
1452
/************************************************************************/
1453
1454
/**
1455
 * \brief Fetch the pixel data type for this band.
1456
 *
1457
 * @see GDALRasterBand::GetRasterDataType()
1458
 */
1459
1460
GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1461
1462
0
{
1463
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1464
1465
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1466
0
    return poBand->GetRasterDataType();
1467
0
}
1468
1469
/************************************************************************/
1470
/*                            GetBlockSize()                            */
1471
/************************************************************************/
1472
1473
/**
1474
 * \brief Fetch the "natural" block size of this band.
1475
 *
1476
 * GDAL contains a concept of the natural block size of rasters so that
1477
 * applications can organized data access efficiently for some file formats.
1478
 * The natural block size is the block size that is most efficient for
1479
 * accessing the format.  For many formats this is simple a whole scanline
1480
 * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1481
 *
1482
 * However, for tiled images this will typically be the tile size.
1483
 *
1484
 * Note that the X and Y block sizes don't have to divide the image size
1485
 * evenly, meaning that right and bottom edge blocks may be incomplete.
1486
 * See ReadBlock() for an example of code dealing with these issues.
1487
 *
1488
 * This method is the same as the C function GDALGetBlockSize().
1489
 *
1490
 * @param pnXSize integer to put the X block size into or NULL.
1491
 *
1492
 * @param pnYSize integer to put the Y block size into or NULL.
1493
 */
1494
1495
void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1496
1497
0
{
1498
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1499
0
    {
1500
0
        ReportError(CE_Failure, CPLE_AppDefined,
1501
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1502
0
                    nBlockYSize);
1503
0
        if (pnXSize != nullptr)
1504
0
            *pnXSize = 0;
1505
0
        if (pnYSize != nullptr)
1506
0
            *pnYSize = 0;
1507
0
    }
1508
0
    else
1509
0
    {
1510
0
        if (pnXSize != nullptr)
1511
0
            *pnXSize = nBlockXSize;
1512
0
        if (pnYSize != nullptr)
1513
0
            *pnYSize = nBlockYSize;
1514
0
    }
1515
0
}
1516
1517
/************************************************************************/
1518
/*                          GDALGetBlockSize()                          */
1519
/************************************************************************/
1520
1521
/**
1522
 * \brief Fetch the "natural" block size of this band.
1523
 *
1524
 * @see GDALRasterBand::GetBlockSize()
1525
 */
1526
1527
void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1528
                                  int *pnYSize)
1529
1530
0
{
1531
0
    VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1532
1533
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1534
0
    poBand->GetBlockSize(pnXSize, pnYSize);
1535
0
}
1536
1537
/************************************************************************/
1538
/*                           InitBlockInfo()                            */
1539
/************************************************************************/
1540
1541
//! @cond Doxygen_Suppress
1542
int GDALRasterBand::InitBlockInfo()
1543
1544
0
{
1545
0
    if (poBandBlockCache != nullptr)
1546
0
        return poBandBlockCache->IsInitOK();
1547
1548
    /* Do some validation of raster and block dimensions in case the driver */
1549
    /* would have neglected to do it itself */
1550
0
    if (nBlockXSize <= 0 || nBlockYSize <= 0)
1551
0
    {
1552
0
        ReportError(CE_Failure, CPLE_AppDefined,
1553
0
                    "Invalid block dimension : %d * %d", nBlockXSize,
1554
0
                    nBlockYSize);
1555
0
        return FALSE;
1556
0
    }
1557
1558
0
    if (nRasterXSize <= 0 || nRasterYSize <= 0)
1559
0
    {
1560
0
        ReportError(CE_Failure, CPLE_AppDefined,
1561
0
                    "Invalid raster dimension : %d * %d", nRasterXSize,
1562
0
                    nRasterYSize);
1563
0
        return FALSE;
1564
0
    }
1565
1566
0
    const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1567
0
    if (nDataTypeSize == 0)
1568
0
    {
1569
0
        ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1570
0
        return FALSE;
1571
0
    }
1572
1573
#if SIZEOF_VOIDP == 4
1574
    if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1575
    {
1576
        /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1577
         * multiplication in other cases */
1578
        if (nBlockXSize > INT_MAX / nDataTypeSize ||
1579
            nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1580
        {
1581
            ReportError(CE_Failure, CPLE_NotSupported,
1582
                        "Too big block : %d * %d for 32-bit build", nBlockXSize,
1583
                        nBlockYSize);
1584
            return FALSE;
1585
        }
1586
    }
1587
#endif
1588
1589
0
    nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1590
0
    nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1591
1592
0
    const char *pszBlockStrategy =
1593
0
        CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1594
0
    bool bUseArray = true;
1595
0
    if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1596
0
    {
1597
0
        if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1598
0
                                   GDAL_OF_DEFAULT_BLOCK_ACCESS)
1599
0
        {
1600
0
            GUIntBig nBlockCount =
1601
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1602
0
            if (poDS != nullptr)
1603
0
                nBlockCount *= poDS->GetRasterCount();
1604
0
            bUseArray = (nBlockCount < 1024 * 1024);
1605
0
        }
1606
0
        else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1607
0
                 GDAL_OF_HASHSET_BLOCK_ACCESS)
1608
0
        {
1609
0
            bUseArray = false;
1610
0
        }
1611
0
    }
1612
0
    else if (EQUAL(pszBlockStrategy, "HASHSET"))
1613
0
        bUseArray = false;
1614
0
    else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1615
0
        CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1616
0
                 pszBlockStrategy);
1617
1618
0
    if (bUseArray)
1619
0
        poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1620
0
    else
1621
0
    {
1622
0
        if (nBand == 1)
1623
0
            CPLDebug("GDAL", "Use hashset band block cache");
1624
0
        poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1625
0
    }
1626
0
    if (poBandBlockCache == nullptr)
1627
0
        return FALSE;
1628
0
    return poBandBlockCache->Init();
1629
0
}
1630
1631
//! @endcond
1632
1633
/************************************************************************/
1634
/*                             FlushCache()                             */
1635
/************************************************************************/
1636
1637
/**
1638
 * \brief Flush raster data cache.
1639
 *
1640
 * This call will recover memory used to cache data blocks for this raster
1641
 * band, and ensure that new requests are referred to the underlying driver.
1642
 *
1643
 * This method is the same as the C function GDALFlushRasterCache().
1644
 *
1645
 * @param bAtClosing Whether this is called from a GDALDataset destructor
1646
 * @return CE_None on success.
1647
 */
1648
1649
CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1650
1651
0
{
1652
0
    if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1653
0
        poBandBlockCache)
1654
0
        poBandBlockCache->DisableDirtyBlockWriting();
1655
1656
0
    CPLErr eGlobalErr = eFlushBlockErr;
1657
1658
0
    if (eFlushBlockErr != CE_None)
1659
0
    {
1660
0
        ReportError(
1661
0
            eFlushBlockErr, CPLE_AppDefined,
1662
0
            "An error occurred while writing a dirty block from FlushCache");
1663
0
        eFlushBlockErr = CE_None;
1664
0
    }
1665
1666
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1667
0
        return eGlobalErr;
1668
1669
0
    return poBandBlockCache->FlushCache();
1670
0
}
1671
1672
/************************************************************************/
1673
/*                        GDALFlushRasterCache()                        */
1674
/************************************************************************/
1675
1676
/**
1677
 * \brief Flush raster data cache.
1678
 *
1679
 * @see GDALRasterBand::FlushCache()
1680
 */
1681
1682
CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1683
1684
0
{
1685
0
    VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1686
1687
0
    return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1688
0
}
1689
1690
/************************************************************************/
1691
/*                             DropCache()                              */
1692
/************************************************************************/
1693
1694
/**
1695
* \brief Drop raster data cache : data in cache will be lost.
1696
*
1697
* This call will recover memory used to cache data blocks for this raster
1698
* band, and ensure that new requests are referred to the underlying driver.
1699
*
1700
* This method is the same as the C function GDALDropRasterCache().
1701
*
1702
* @return CE_None on success.
1703
* @since 3.9
1704
*/
1705
1706
CPLErr GDALRasterBand::DropCache()
1707
1708
0
{
1709
0
    CPLErr result = CE_None;
1710
1711
0
    if (poBandBlockCache)
1712
0
        poBandBlockCache->DisableDirtyBlockWriting();
1713
1714
0
    CPLErr eGlobalErr = eFlushBlockErr;
1715
1716
0
    if (eFlushBlockErr != CE_None)
1717
0
    {
1718
0
        ReportError(
1719
0
            eFlushBlockErr, CPLE_AppDefined,
1720
0
            "An error occurred while writing a dirty block from DropCache");
1721
0
        eFlushBlockErr = CE_None;
1722
0
    }
1723
1724
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1725
0
        result = eGlobalErr;
1726
0
    else
1727
0
        result = poBandBlockCache->FlushCache();
1728
1729
0
    if (poBandBlockCache)
1730
0
        poBandBlockCache->EnableDirtyBlockWriting();
1731
1732
0
    return result;
1733
0
}
1734
1735
/************************************************************************/
1736
/*                        GDALDropRasterCache()                         */
1737
/************************************************************************/
1738
1739
/**
1740
* \brief Drop raster data cache.
1741
*
1742
* @see GDALRasterBand::DropCache()
1743
* @since 3.9
1744
*/
1745
1746
CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1747
1748
0
{
1749
0
    VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1750
1751
0
    return GDALRasterBand::FromHandle(hBand)->DropCache();
1752
0
}
1753
1754
/************************************************************************/
1755
/*                        UnreferenceBlock()                            */
1756
/*                                                                      */
1757
/*      Unreference the block from our array of blocks                  */
1758
/*      This method should only be called by                            */
1759
/*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1760
/*      the block cache mutex)                                          */
1761
/************************************************************************/
1762
1763
CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1764
0
{
1765
#ifdef notdef
1766
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1767
    {
1768
        if (poBandBlockCache == nullptr)
1769
            printf("poBandBlockCache == NULL\n"); /*ok*/
1770
        else
1771
            printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1772
        printf("caller = %s\n", pszCaller);            /*ok*/
1773
        printf("GDALRasterBand: %p\n", this);          /*ok*/
1774
        printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
1775
        printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
1776
        printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
1777
        printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
1778
        printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
1779
        poBlock->DumpBlock();
1780
        if (GetDataset() != nullptr)
1781
            printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1782
        GDALRasterBlock::Verify();
1783
        abort();
1784
    }
1785
#endif
1786
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1787
0
    return poBandBlockCache->UnreferenceBlock(poBlock);
1788
0
}
1789
1790
/************************************************************************/
1791
/*                        AddBlockToFreeList()                          */
1792
/*                                                                      */
1793
/*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
1794
/*      finished with a block about to be free'd, they pass it to that  */
1795
/*      method.                                                         */
1796
/************************************************************************/
1797
1798
//! @cond Doxygen_Suppress
1799
void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1800
0
{
1801
0
    CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1802
0
    return poBandBlockCache->AddBlockToFreeList(poBlock);
1803
0
}
1804
1805
//! @endcond
1806
1807
/************************************************************************/
1808
/*                           HasDirtyBlocks()                           */
1809
/************************************************************************/
1810
1811
//! @cond Doxygen_Suppress
1812
bool GDALRasterBand::HasDirtyBlocks() const
1813
0
{
1814
0
    return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1815
0
}
1816
1817
//! @endcond
1818
1819
/************************************************************************/
1820
/*                             FlushBlock()                             */
1821
/************************************************************************/
1822
1823
/** Flush a block out of the block cache.
1824
 * @param nXBlockOff block x offset
1825
 * @param nYBlockOff blocky offset
1826
 * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1827
 * @return CE_None in case of success, an error code otherwise.
1828
 */
1829
CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1830
                                  int bWriteDirtyBlock)
1831
1832
0
{
1833
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1834
0
        return (CE_Failure);
1835
1836
    /* -------------------------------------------------------------------- */
1837
    /*      Validate the request                                            */
1838
    /* -------------------------------------------------------------------- */
1839
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1840
0
    {
1841
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1842
0
                    "Illegal nBlockXOff value (%d) in "
1843
0
                    "GDALRasterBand::FlushBlock()\n",
1844
0
                    nXBlockOff);
1845
1846
0
        return (CE_Failure);
1847
0
    }
1848
1849
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1850
0
    {
1851
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1852
0
                    "Illegal nBlockYOff value (%d) in "
1853
0
                    "GDALRasterBand::FlushBlock()\n",
1854
0
                    nYBlockOff);
1855
1856
0
        return (CE_Failure);
1857
0
    }
1858
1859
0
    return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1860
0
                                        bWriteDirtyBlock);
1861
0
}
1862
1863
/************************************************************************/
1864
/*                        TryGetLockedBlockRef()                        */
1865
/************************************************************************/
1866
1867
/**
1868
 * \brief Try fetching block ref.
1869
 *
1870
 * This method will returned the requested block (locked) if it is already
1871
 * in the block cache for the layer.  If not, nullptr is returned.
1872
 *
1873
 * If a non-NULL value is returned, then a lock for the block will have been
1874
 * acquired on behalf of the caller.  It is absolutely imperative that the
1875
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1876
 * severe problems may result.
1877
 *
1878
 * @param nXBlockOff the horizontal block offset, with zero indicating
1879
 * the left most block, 1 the next block and so forth.
1880
 *
1881
 * @param nYBlockOff the vertical block offset, with zero indicating
1882
 * the top most block, 1 the next block and so forth.
1883
 *
1884
 * @return NULL if block not available, or locked block pointer.
1885
 */
1886
1887
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1888
                                                      int nYBlockOff)
1889
1890
0
{
1891
0
    if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1892
0
        return nullptr;
1893
1894
    /* -------------------------------------------------------------------- */
1895
    /*      Validate the request                                            */
1896
    /* -------------------------------------------------------------------- */
1897
0
    if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1898
0
    {
1899
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1900
0
                    "Illegal nBlockXOff value (%d) in "
1901
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1902
0
                    nXBlockOff);
1903
1904
0
        return (nullptr);
1905
0
    }
1906
1907
0
    if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1908
0
    {
1909
0
        ReportError(CE_Failure, CPLE_IllegalArg,
1910
0
                    "Illegal nBlockYOff value (%d) in "
1911
0
                    "GDALRasterBand::TryGetLockedBlockRef()\n",
1912
0
                    nYBlockOff);
1913
1914
0
        return (nullptr);
1915
0
    }
1916
1917
0
    return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1918
0
}
1919
1920
/************************************************************************/
1921
/*                         GetLockedBlockRef()                          */
1922
/************************************************************************/
1923
1924
/**
1925
 * \brief Fetch a pointer to an internally cached raster block.
1926
 *
1927
 * This method will returned the requested block (locked) if it is already
1928
 * in the block cache for the layer.  If not, the block will be read from
1929
 * the driver, and placed in the layer block cached, then returned.  If an
1930
 * error occurs reading the block from the driver, a NULL value will be
1931
 * returned.
1932
 *
1933
 * If a non-NULL value is returned, then a lock for the block will have been
1934
 * acquired on behalf of the caller.  It is absolutely imperative that the
1935
 * caller release this lock (with GDALRasterBlock::DropLock()) or else
1936
 * severe problems may result.
1937
 *
1938
 * Note that calling GetLockedBlockRef() on a previously uncached band will
1939
 * enable caching.
1940
 *
1941
 * @param nXBlockOff the horizontal block offset, with zero indicating
1942
 * the left most block, 1 the next block and so forth.
1943
 *
1944
 * @param nYBlockOff the vertical block offset, with zero indicating
1945
 * the top most block, 1 the next block and so forth.
1946
 *
1947
 * @param bJustInitialize If TRUE the block will be allocated and initialized,
1948
 * but not actually read from the source.  This is useful when it will just
1949
 * be completely set and written back.
1950
 *
1951
 * @return pointer to the block object, or NULL on failure.
1952
 */
1953
1954
GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1955
                                                   int nYBlockOff,
1956
                                                   int bJustInitialize)
1957
1958
0
{
1959
    /* -------------------------------------------------------------------- */
1960
    /*      Try and fetch from cache.                                       */
1961
    /* -------------------------------------------------------------------- */
1962
0
    GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1963
1964
    /* -------------------------------------------------------------------- */
1965
    /*      If we didn't find it in our memory cache, instantiate a         */
1966
    /*      block (potentially load from disk) and "adopt" it into the      */
1967
    /*      cache.                                                          */
1968
    /* -------------------------------------------------------------------- */
1969
0
    if (poBlock == nullptr)
1970
0
    {
1971
0
        if (!InitBlockInfo())
1972
0
            return (nullptr);
1973
1974
        /* --------------------------------------------------------------------
1975
         */
1976
        /*      Validate the request */
1977
        /* --------------------------------------------------------------------
1978
         */
1979
0
        if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1980
0
        {
1981
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1982
0
                        "Illegal nBlockXOff value (%d) in "
1983
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1984
0
                        nXBlockOff);
1985
1986
0
            return (nullptr);
1987
0
        }
1988
1989
0
        if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1990
0
        {
1991
0
            ReportError(CE_Failure, CPLE_IllegalArg,
1992
0
                        "Illegal nBlockYOff value (%d) in "
1993
0
                        "GDALRasterBand::GetLockedBlockRef()\n",
1994
0
                        nYBlockOff);
1995
1996
0
            return (nullptr);
1997
0
        }
1998
1999
0
        poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2000
0
        if (poBlock == nullptr)
2001
0
            return nullptr;
2002
2003
0
        poBlock->AddLock();
2004
2005
        /* We need to temporarily drop the read-write lock in the following */
2006
        /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2007
         */
2008
        /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2009
        /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2010
         */
2011
        /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2012
         */
2013
        /* called and attempt at taking the lock on T2 (already taken).
2014
         * Similarly */
2015
        /* for T2 with D1, hence a deadlock situation (#6163) */
2016
        /* But this may open the door to other problems... */
2017
0
        if (poDS)
2018
0
            poDS->TemporarilyDropReadWriteLock();
2019
        /* allocate data space */
2020
0
        CPLErr eErr = poBlock->Internalize();
2021
0
        if (poDS)
2022
0
            poDS->ReacquireReadWriteLock();
2023
0
        if (eErr != CE_None)
2024
0
        {
2025
0
            poBlock->DropLock();
2026
0
            delete poBlock;
2027
0
            return nullptr;
2028
0
        }
2029
2030
0
        if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2031
0
        {
2032
0
            poBlock->DropLock();
2033
0
            delete poBlock;
2034
0
            return nullptr;
2035
0
        }
2036
2037
0
        if (!bJustInitialize)
2038
0
        {
2039
0
            const GUInt32 nErrorCounter = CPLGetErrorCounter();
2040
0
            int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2041
0
            eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2042
0
            if (bCallLeaveReadWrite)
2043
0
                LeaveReadWrite();
2044
0
            if (eErr != CE_None)
2045
0
            {
2046
0
                poBlock->DropLock();
2047
0
                FlushBlock(nXBlockOff, nYBlockOff);
2048
0
                ReportError(CE_Failure, CPLE_AppDefined,
2049
0
                            "IReadBlock failed at X offset %d, Y offset %d%s",
2050
0
                            nXBlockOff, nYBlockOff,
2051
0
                            (nErrorCounter != CPLGetErrorCounter())
2052
0
                                ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2053
0
                                : "");
2054
0
                return nullptr;
2055
0
            }
2056
2057
0
            nBlockReads++;
2058
0
            if (static_cast<GIntBig>(nBlockReads) ==
2059
0
                    static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2060
0
                        1 &&
2061
0
                nBand == 1 && poDS != nullptr)
2062
0
            {
2063
0
                CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2064
0
                         poDS->GetDescription());
2065
0
            }
2066
0
        }
2067
0
    }
2068
2069
0
    return poBlock;
2070
0
}
2071
2072
/************************************************************************/
2073
/*                               Fill()                                 */
2074
/************************************************************************/
2075
2076
/**
2077
 * \brief Fill this band with a constant value.
2078
 *
2079
 * GDAL makes no guarantees
2080
 * about what values pixels in newly created files are set to, so this
2081
 * method can be used to clear a band to a specified "default" value.
2082
 * The fill value is passed in as a double but this will be converted
2083
 * to the underlying type before writing to the file. An optional
2084
 * second argument allows the imaginary component of a complex
2085
 * constant value to be specified.
2086
 *
2087
 * This method is the same as the C function GDALFillRaster().
2088
 *
2089
 * @param dfRealValue Real component of fill value
2090
 * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2091
 *
2092
 * @return CE_Failure if the write fails, otherwise CE_None
2093
 */
2094
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2095
0
{
2096
2097
    // General approach is to construct a source block of the file's
2098
    // native type containing the appropriate value and then copy this
2099
    // to each block in the image via the RasterBlock cache. Using
2100
    // the cache means we avoid file I/O if it is not necessary, at the
2101
    // expense of some extra memcpy's (since we write to the
2102
    // RasterBlock cache, which is then at some point written to the
2103
    // underlying file, rather than simply directly to the underlying
2104
    // file.)
2105
2106
    // Check we can write to the file.
2107
0
    if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2108
0
    {
2109
0
        return CE_Failure;
2110
0
    }
2111
2112
    // Make sure block parameters are set.
2113
0
    if (!InitBlockInfo())
2114
0
        return CE_Failure;
2115
2116
    // Allocate the source block.
2117
0
    auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2118
0
    int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2119
0
    auto blockByteSize = blockSize * elementSize;
2120
0
    unsigned char *srcBlock =
2121
0
        static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2122
0
    if (srcBlock == nullptr)
2123
0
    {
2124
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
2125
0
                    "GDALRasterBand::Fill(): Out of memory "
2126
0
                    "allocating " CPL_FRMT_GUIB " bytes.\n",
2127
0
                    static_cast<GUIntBig>(blockByteSize));
2128
0
        return CE_Failure;
2129
0
    }
2130
2131
    // Initialize the source block.
2132
0
    double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2133
0
    GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2134
0
                    elementSize, blockSize);
2135
2136
0
    const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2137
2138
    // Write block to block cache
2139
0
    for (int j = 0; j < nBlocksPerColumn; ++j)
2140
0
    {
2141
0
        for (int i = 0; i < nBlocksPerRow; ++i)
2142
0
        {
2143
0
            GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2144
0
            if (destBlock == nullptr)
2145
0
            {
2146
0
                ReportError(CE_Failure, CPLE_OutOfMemory,
2147
0
                            "GDALRasterBand::Fill(): Error "
2148
0
                            "while retrieving cache block.");
2149
0
                VSIFree(srcBlock);
2150
0
                return CE_Failure;
2151
0
            }
2152
0
            memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2153
0
            destBlock->MarkDirty();
2154
0
            destBlock->DropLock();
2155
0
        }
2156
0
    }
2157
2158
0
    if (bCallLeaveReadWrite)
2159
0
        LeaveReadWrite();
2160
2161
    // Free up the source block
2162
0
    VSIFree(srcBlock);
2163
2164
0
    return CE_None;
2165
0
}
2166
2167
/************************************************************************/
2168
/*                         GDALFillRaster()                             */
2169
/************************************************************************/
2170
2171
/**
2172
 * \brief Fill this band with a constant value.
2173
 *
2174
 * @see GDALRasterBand::Fill()
2175
 */
2176
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2177
                                  double dfImaginaryValue)
2178
0
{
2179
0
    VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2180
2181
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2182
0
    return poBand->Fill(dfRealValue, dfImaginaryValue);
2183
0
}
2184
2185
/************************************************************************/
2186
/*                             GetAccess()                              */
2187
/************************************************************************/
2188
2189
/**
2190
 * \brief Find out if we have update permission for this band.
2191
 *
2192
 * This method is the same as the C function GDALGetRasterAccess().
2193
 *
2194
 * @return Either GA_Update or GA_ReadOnly.
2195
 */
2196
2197
GDALAccess GDALRasterBand::GetAccess()
2198
2199
0
{
2200
0
    return eAccess;
2201
0
}
2202
2203
/************************************************************************/
2204
/*                        GDALGetRasterAccess()                         */
2205
/************************************************************************/
2206
2207
/**
2208
 * \brief Find out if we have update permission for this band.
2209
 *
2210
 * @see GDALRasterBand::GetAccess()
2211
 */
2212
2213
GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2214
2215
0
{
2216
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2217
2218
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2219
0
    return poBand->GetAccess();
2220
0
}
2221
2222
/************************************************************************/
2223
/*                          GetCategoryNames()                          */
2224
/************************************************************************/
2225
2226
/**
2227
 * \brief Fetch the list of category names for this raster.
2228
 *
2229
 * The return list is a "StringList" in the sense of the CPL functions.
2230
 * That is a NULL terminated array of strings.  Raster values without
2231
 * associated names will have an empty string in the returned list.  The
2232
 * first entry in the list is for raster values of zero, and so on.
2233
 *
2234
 * The returned stringlist should not be altered or freed by the application.
2235
 * It may change on the next GDAL call, so please copy it if it is needed
2236
 * for any period of time.
2237
 *
2238
 * This method is the same as the C function GDALGetRasterCategoryNames().
2239
 *
2240
 * @return list of names, or NULL if none.
2241
 */
2242
2243
char **GDALRasterBand::GetCategoryNames()
2244
2245
0
{
2246
0
    return nullptr;
2247
0
}
2248
2249
/************************************************************************/
2250
/*                     GDALGetRasterCategoryNames()                     */
2251
/************************************************************************/
2252
2253
/**
2254
 * \brief Fetch the list of category names for this raster.
2255
 *
2256
 * @see GDALRasterBand::GetCategoryNames()
2257
 */
2258
2259
char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2260
2261
0
{
2262
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2263
2264
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2265
0
    return poBand->GetCategoryNames();
2266
0
}
2267
2268
/************************************************************************/
2269
/*                          SetCategoryNames()                          */
2270
/************************************************************************/
2271
2272
/**
2273
 * \fn GDALRasterBand::SetCategoryNames(char**)
2274
 * \brief Set the category names for this band.
2275
 *
2276
 * See the GetCategoryNames() method for more on the interpretation of
2277
 * category names.
2278
 *
2279
 * This method is the same as the C function GDALSetRasterCategoryNames().
2280
 *
2281
 * @param papszNames the NULL terminated StringList of category names.  May
2282
 * be NULL to just clear the existing list.
2283
 *
2284
 * @return CE_None on success of CE_Failure on failure.  If unsupported
2285
 * by the driver CE_Failure is returned, but no error message is reported.
2286
 */
2287
2288
/**/
2289
/**/
2290
2291
CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2292
0
{
2293
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2294
0
        ReportError(CE_Failure, CPLE_NotSupported,
2295
0
                    "SetCategoryNames() not supported for this dataset.");
2296
2297
0
    return CE_Failure;
2298
0
}
2299
2300
/************************************************************************/
2301
/*                        GDALSetCategoryNames()                        */
2302
/************************************************************************/
2303
2304
/**
2305
 * \brief Set the category names for this band.
2306
 *
2307
 * @see GDALRasterBand::SetCategoryNames()
2308
 */
2309
2310
CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2311
                                              CSLConstList papszNames)
2312
2313
0
{
2314
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2315
2316
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2317
0
    return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2318
0
}
2319
2320
/************************************************************************/
2321
/*                           GetNoDataValue()                           */
2322
/************************************************************************/
2323
2324
/**
2325
 * \brief Fetch the no data value for this band.
2326
 *
2327
 * If there is no out of data value, an out of range value will generally
2328
 * be returned.  The no data value for a band is generally a special marker
2329
 * value used to mark pixels that are not valid data.  Such pixels should
2330
 * generally not be displayed, nor contribute to analysis operations.
2331
 *
2332
 * The no data value returned is 'raw', meaning that it has no offset and
2333
 * scale applied.
2334
 *
2335
 * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2336
 * lossy if the nodata value cannot exactly been represented by a double.
2337
 * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2338
 *
2339
 * This method is the same as the C function GDALGetRasterNoDataValue().
2340
 *
2341
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2342
 * is actually associated with this layer.  May be NULL (default).
2343
 *
2344
 * @return the nodata value for this band.
2345
 */
2346
2347
double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2348
2349
0
{
2350
0
    if (pbSuccess != nullptr)
2351
0
        *pbSuccess = FALSE;
2352
2353
0
    return -1e10;
2354
0
}
2355
2356
/************************************************************************/
2357
/*                      GDALGetRasterNoDataValue()                      */
2358
/************************************************************************/
2359
2360
/**
2361
 * \brief Fetch the no data value for this band.
2362
 *
2363
 * @see GDALRasterBand::GetNoDataValue()
2364
 */
2365
2366
double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2367
                                            int *pbSuccess)
2368
2369
0
{
2370
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2371
2372
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2373
0
    return poBand->GetNoDataValue(pbSuccess);
2374
0
}
2375
2376
/************************************************************************/
2377
/*                       GetNoDataValueAsInt64()                        */
2378
/************************************************************************/
2379
2380
/**
2381
 * \brief Fetch the no data value for this band.
2382
 *
2383
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2384
 *
2385
 * If there is no out of data value, an out of range value will generally
2386
 * be returned.  The no data value for a band is generally a special marker
2387
 * value used to mark pixels that are not valid data.  Such pixels should
2388
 * generally not be displayed, nor contribute to analysis operations.
2389
 *
2390
 * The no data value returned is 'raw', meaning that it has no offset and
2391
 * scale applied.
2392
 *
2393
 * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2394
 *
2395
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2396
 * is actually associated with this layer.  May be NULL (default).
2397
 *
2398
 * @return the nodata value for this band.
2399
 *
2400
 * @since GDAL 3.5
2401
 */
2402
2403
int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2404
2405
0
{
2406
0
    if (pbSuccess != nullptr)
2407
0
        *pbSuccess = FALSE;
2408
2409
0
    return std::numeric_limits<int64_t>::min();
2410
0
}
2411
2412
/************************************************************************/
2413
/*                   GDALGetRasterNoDataValueAsInt64()                  */
2414
/************************************************************************/
2415
2416
/**
2417
 * \brief Fetch the no data value for this band.
2418
 *
2419
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2420
 *
2421
 * @see GDALRasterBand::GetNoDataValueAsInt64()
2422
 *
2423
 * @since GDAL 3.5
2424
 */
2425
2426
int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2427
                                                    int *pbSuccess)
2428
2429
0
{
2430
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2431
0
                      std::numeric_limits<int64_t>::min());
2432
2433
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2434
0
    return poBand->GetNoDataValueAsInt64(pbSuccess);
2435
0
}
2436
2437
/************************************************************************/
2438
/*                       GetNoDataValueAsUInt64()                        */
2439
/************************************************************************/
2440
2441
/**
2442
 * \brief Fetch the no data value for this band.
2443
 *
2444
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2445
 *
2446
 * If there is no out of data value, an out of range value will generally
2447
 * be returned.  The no data value for a band is generally a special marker
2448
 * value used to mark pixels that are not valid data.  Such pixels should
2449
 * generally not be displayed, nor contribute to analysis operations.
2450
 *
2451
 * The no data value returned is 'raw', meaning that it has no offset and
2452
 * scale applied.
2453
 *
2454
 * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2455
 *
2456
 * @param pbSuccess pointer to a boolean to use to indicate if a value
2457
 * is actually associated with this layer.  May be NULL (default).
2458
 *
2459
 * @return the nodata value for this band.
2460
 *
2461
 * @since GDAL 3.5
2462
 */
2463
2464
uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2465
2466
0
{
2467
0
    if (pbSuccess != nullptr)
2468
0
        *pbSuccess = FALSE;
2469
2470
0
    return std::numeric_limits<uint64_t>::max();
2471
0
}
2472
2473
/************************************************************************/
2474
/*                   GDALGetRasterNoDataValueAsUInt64()                  */
2475
/************************************************************************/
2476
2477
/**
2478
 * \brief Fetch the no data value for this band.
2479
 *
2480
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2481
 *
2482
 * @see GDALRasterBand::GetNoDataValueAsUInt64()
2483
 *
2484
 * @since GDAL 3.5
2485
 */
2486
2487
uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2488
                                                      int *pbSuccess)
2489
2490
0
{
2491
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2492
0
                      std::numeric_limits<uint64_t>::max());
2493
2494
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2495
0
    return poBand->GetNoDataValueAsUInt64(pbSuccess);
2496
0
}
2497
2498
/************************************************************************/
2499
/*                        SetNoDataValueAsString()                      */
2500
/************************************************************************/
2501
2502
/**
2503
 * \brief Set the no data value for this band.
2504
 *
2505
 * Depending on drivers, changing the no data value may or may not have an
2506
 * effect on the pixel values of a raster that has just been created. It is
2507
 * thus advised to explicitly called Fill() if the intent is to initialize
2508
 * the raster to the nodata value.
2509
 * In any case, changing an existing no data value, when one already exists and
2510
 * the dataset exists or has been initialized, has no effect on the pixel whose
2511
 * value matched the previous nodata value.
2512
 *
2513
 * To clear the nodata value, use DeleteNoDataValue().
2514
 *
2515
 * @param pszNoData the value to set.
2516
 * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2517
 *             If the value cannot be exactly represented on the output data
2518
 *             type, *pbCannotBeExactlyRepresented will be set to true.
2519
 *
2520
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2521
 * by the driver, CE_Failure is returned but no error message will have
2522
 * been emitted.
2523
 *
2524
 * @since 3.11
2525
 */
2526
2527
CPLErr
2528
GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2529
                                       bool *pbCannotBeExactlyRepresented)
2530
0
{
2531
0
    if (pbCannotBeExactlyRepresented)
2532
0
        *pbCannotBeExactlyRepresented = false;
2533
0
    if (eDataType == GDT_Int64)
2534
0
    {
2535
0
        if (strchr(pszNoData, '.') ||
2536
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2537
0
        {
2538
0
            char *endptr = nullptr;
2539
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2540
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2541
0
                GDALIsValueExactAs<int64_t>(dfVal))
2542
0
            {
2543
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2544
0
            }
2545
0
        }
2546
0
        else
2547
0
        {
2548
0
            try
2549
0
            {
2550
0
                const auto val = std::stoll(pszNoData);
2551
0
                return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2552
0
            }
2553
0
            catch (const std::exception &)
2554
0
            {
2555
0
            }
2556
0
        }
2557
0
    }
2558
0
    else if (eDataType == GDT_UInt64)
2559
0
    {
2560
0
        if (strchr(pszNoData, '.') ||
2561
0
            CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2562
0
        {
2563
0
            char *endptr = nullptr;
2564
0
            const double dfVal = CPLStrtod(pszNoData, &endptr);
2565
0
            if (endptr == pszNoData + strlen(pszNoData) &&
2566
0
                GDALIsValueExactAs<uint64_t>(dfVal))
2567
0
            {
2568
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2569
0
            }
2570
0
        }
2571
0
        else
2572
0
        {
2573
0
            try
2574
0
            {
2575
0
                const auto val = std::stoull(pszNoData);
2576
0
                return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2577
0
            }
2578
0
            catch (const std::exception &)
2579
0
            {
2580
0
            }
2581
0
        }
2582
0
    }
2583
0
    else if (eDataType == GDT_Float32)
2584
0
    {
2585
0
        char *endptr = nullptr;
2586
0
        const float fVal = CPLStrtof(pszNoData, &endptr);
2587
0
        if (endptr == pszNoData + strlen(pszNoData))
2588
0
        {
2589
0
            return SetNoDataValue(double(fVal));
2590
0
        }
2591
0
    }
2592
0
    else
2593
0
    {
2594
0
        char *endptr = nullptr;
2595
0
        const double dfVal = CPLStrtod(pszNoData, &endptr);
2596
0
        if (endptr == pszNoData + strlen(pszNoData) &&
2597
0
            GDALIsValueExactAs(dfVal, eDataType))
2598
0
        {
2599
0
            return SetNoDataValue(dfVal);
2600
0
        }
2601
0
    }
2602
0
    if (pbCannotBeExactlyRepresented)
2603
0
        *pbCannotBeExactlyRepresented = true;
2604
0
    return CE_Failure;
2605
0
}
2606
2607
/************************************************************************/
2608
/*                           SetNoDataValue()                           */
2609
/************************************************************************/
2610
2611
/**
2612
 * \fn GDALRasterBand::SetNoDataValue(double)
2613
 * \brief Set the no data value for this band.
2614
 *
2615
 * Depending on drivers, changing the no data value may or may not have an
2616
 * effect on the pixel values of a raster that has just been created. It is
2617
 * thus advised to explicitly called Fill() if the intent is to initialize
2618
 * the raster to the nodata value.
2619
 * In any case, changing an existing no data value, when one already exists and
2620
 * the dataset exists or has been initialized, has no effect on the pixel whose
2621
 * value matched the previous nodata value.
2622
 *
2623
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2624
 * be represented by a double, use SetNoDataValueAsInt64() or
2625
 * SetNoDataValueAsUInt64() instead.
2626
 *
2627
 * To clear the nodata value, use DeleteNoDataValue().
2628
 *
2629
 * This method is the same as the C function GDALSetRasterNoDataValue().
2630
 *
2631
 * @param dfNoData the value to set.
2632
 *
2633
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2634
 * by the driver, CE_Failure is returned but no error message will have
2635
 * been emitted.
2636
 */
2637
2638
/**/
2639
/**/
2640
2641
CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2642
2643
0
{
2644
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2645
0
        ReportError(CE_Failure, CPLE_NotSupported,
2646
0
                    "SetNoDataValue() not supported for this dataset.");
2647
2648
0
    return CE_Failure;
2649
0
}
2650
2651
/************************************************************************/
2652
/*                         GDALSetRasterNoDataValue()                   */
2653
/************************************************************************/
2654
2655
/**
2656
 * \brief Set the no data value for this band.
2657
 *
2658
 * Depending on drivers, changing the no data value may or may not have an
2659
 * effect on the pixel values of a raster that has just been created. It is
2660
 * thus advised to explicitly called Fill() if the intent is to initialize
2661
 * the raster to the nodata value.
2662
 * In any case, changing an existing no data value, when one already exists and
2663
 * the dataset exists or has been initialized, has no effect on the pixel whose
2664
 * value matched the previous nodata value.
2665
 *
2666
 * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2667
 * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2668
 * GDALSetRasterNoDataValueAsUInt64() instead.
2669
 *
2670
 * @see GDALRasterBand::SetNoDataValue()
2671
 */
2672
2673
CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2674
                                            double dfValue)
2675
2676
0
{
2677
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2678
2679
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2680
0
    return poBand->SetNoDataValue(dfValue);
2681
0
}
2682
2683
/************************************************************************/
2684
/*                       SetNoDataValueAsInt64()                        */
2685
/************************************************************************/
2686
2687
/**
2688
 * \brief Set the no data value for this band.
2689
 *
2690
 * This method should ONLY be called on rasters whose data type is GDT_Int64.
2691
 *
2692
 * Depending on drivers, changing the no data value may or may not have an
2693
 * effect on the pixel values of a raster that has just been created. It is
2694
 * thus advised to explicitly called Fill() if the intent is to initialize
2695
 * the raster to the nodata value.
2696
 * In ay case, changing an existing no data value, when one already exists and
2697
 * the dataset exists or has been initialized, has no effect on the pixel whose
2698
 * value matched the previous nodata value.
2699
 *
2700
 * To clear the nodata value, use DeleteNoDataValue().
2701
 *
2702
 * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2703
 *
2704
 * @param nNoDataValue the value to set.
2705
 *
2706
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2707
 * by the driver, CE_Failure is returned but no error message will have
2708
 * been emitted.
2709
 *
2710
 * @since GDAL 3.5
2711
 */
2712
2713
CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2714
2715
0
{
2716
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2717
0
        ReportError(CE_Failure, CPLE_NotSupported,
2718
0
                    "SetNoDataValueAsInt64() not supported for this dataset.");
2719
2720
0
    return CE_Failure;
2721
0
}
2722
2723
/************************************************************************/
2724
/*                 GDALSetRasterNoDataValueAsInt64()                    */
2725
/************************************************************************/
2726
2727
/**
2728
 * \brief Set the no data value for this band.
2729
 *
2730
 * This function should ONLY be called on rasters whose data type is GDT_Int64.
2731
 *
2732
 * Depending on drivers, changing the no data value may or may not have an
2733
 * effect on the pixel values of a raster that has just been created. It is
2734
 * thus advised to explicitly called Fill() if the intent is to initialize
2735
 * the raster to the nodata value.
2736
 * In ay case, changing an existing no data value, when one already exists and
2737
 * the dataset exists or has been initialized, has no effect on the pixel whose
2738
 * value matched the previous nodata value.
2739
 *
2740
 * @see GDALRasterBand::SetNoDataValueAsInt64()
2741
 *
2742
 * @since GDAL 3.5
2743
 */
2744
2745
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2746
                                                   int64_t nValue)
2747
2748
0
{
2749
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2750
2751
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2752
0
    return poBand->SetNoDataValueAsInt64(nValue);
2753
0
}
2754
2755
/************************************************************************/
2756
/*                       SetNoDataValueAsUInt64()                       */
2757
/************************************************************************/
2758
2759
/**
2760
 * \brief Set the no data value for this band.
2761
 *
2762
 * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2763
 *
2764
 * Depending on drivers, changing the no data value may or may not have an
2765
 * effect on the pixel values of a raster that has just been created. It is
2766
 * thus advised to explicitly called Fill() if the intent is to initialize
2767
 * the raster to the nodata value.
2768
 * In ay case, changing an existing no data value, when one already exists and
2769
 * the dataset exists or has been initialized, has no effect on the pixel whose
2770
 * value matched the previous nodata value.
2771
 *
2772
 * To clear the nodata value, use DeleteNoDataValue().
2773
 *
2774
 * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2775
 *
2776
 * @param nNoDataValue the value to set.
2777
 *
2778
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2779
 * by the driver, CE_Failure is returned but no error message will have
2780
 * been emitted.
2781
 *
2782
 * @since GDAL 3.5
2783
 */
2784
2785
CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2786
2787
0
{
2788
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2789
0
        ReportError(CE_Failure, CPLE_NotSupported,
2790
0
                    "SetNoDataValueAsUInt64() not supported for this dataset.");
2791
2792
0
    return CE_Failure;
2793
0
}
2794
2795
/************************************************************************/
2796
/*                 GDALSetRasterNoDataValueAsUInt64()                    */
2797
/************************************************************************/
2798
2799
/**
2800
 * \brief Set the no data value for this band.
2801
 *
2802
 * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2803
 *
2804
 * Depending on drivers, changing the no data value may or may not have an
2805
 * effect on the pixel values of a raster that has just been created. It is
2806
 * thus advised to explicitly called Fill() if the intent is to initialize
2807
 * the raster to the nodata value.
2808
 * In ay case, changing an existing no data value, when one already exists and
2809
 * the dataset exists or has been initialized, has no effect on the pixel whose
2810
 * value matched the previous nodata value.
2811
 *
2812
 * @see GDALRasterBand::SetNoDataValueAsUInt64()
2813
 *
2814
 * @since GDAL 3.5
2815
 */
2816
2817
CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2818
                                                    uint64_t nValue)
2819
2820
0
{
2821
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2822
2823
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2824
0
    return poBand->SetNoDataValueAsUInt64(nValue);
2825
0
}
2826
2827
/************************************************************************/
2828
/*                        DeleteNoDataValue()                           */
2829
/************************************************************************/
2830
2831
/**
2832
 * \brief Remove the no data value for this band.
2833
 *
2834
 * This method is the same as the C function GDALDeleteRasterNoDataValue().
2835
 *
2836
 * @return CE_None on success, or CE_Failure on failure.  If unsupported
2837
 * by the driver, CE_Failure is returned but no error message will have
2838
 * been emitted.
2839
 *
2840
 */
2841
2842
CPLErr GDALRasterBand::DeleteNoDataValue()
2843
2844
0
{
2845
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2846
0
        ReportError(CE_Failure, CPLE_NotSupported,
2847
0
                    "DeleteNoDataValue() not supported for this dataset.");
2848
2849
0
    return CE_Failure;
2850
0
}
2851
2852
/************************************************************************/
2853
/*                       GDALDeleteRasterNoDataValue()                  */
2854
/************************************************************************/
2855
2856
/**
2857
 * \brief Remove the no data value for this band.
2858
 *
2859
 * @see GDALRasterBand::DeleteNoDataValue()
2860
 *
2861
 */
2862
2863
CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2864
2865
0
{
2866
0
    VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2867
2868
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2869
0
    return poBand->DeleteNoDataValue();
2870
0
}
2871
2872
/************************************************************************/
2873
/*                             GetMaximum()                             */
2874
/************************************************************************/
2875
2876
/**
2877
 * \brief Fetch the maximum value for this band.
2878
 *
2879
 * For file formats that don't know this intrinsically, the maximum supported
2880
 * value for the data type will generally be returned.
2881
 *
2882
 * This method is the same as the C function GDALGetRasterMaximum().
2883
 *
2884
 * @param pbSuccess pointer to a boolean to use to indicate if the
2885
 * returned value is a tight maximum or not.  May be NULL (default).
2886
 *
2887
 * @return the maximum raster value (excluding no data pixels)
2888
 */
2889
2890
double GDALRasterBand::GetMaximum(int *pbSuccess)
2891
2892
0
{
2893
0
    const char *pszValue = nullptr;
2894
2895
0
    if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2896
0
    {
2897
0
        if (pbSuccess != nullptr)
2898
0
            *pbSuccess = TRUE;
2899
2900
0
        return CPLAtofM(pszValue);
2901
0
    }
2902
2903
0
    if (pbSuccess != nullptr)
2904
0
        *pbSuccess = FALSE;
2905
2906
0
    switch (eDataType)
2907
0
    {
2908
0
        case GDT_UInt8:
2909
0
        {
2910
0
            EnablePixelTypeSignedByteWarning(false);
2911
0
            const char *pszPixelType =
2912
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2913
0
            EnablePixelTypeSignedByteWarning(true);
2914
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2915
0
                return 127;
2916
2917
0
            return 255;
2918
0
        }
2919
2920
0
        case GDT_Int8:
2921
0
            return 127;
2922
2923
0
        case GDT_UInt16:
2924
0
            return 65535;
2925
2926
0
        case GDT_Int16:
2927
0
        case GDT_CInt16:
2928
0
            return 32767;
2929
2930
0
        case GDT_Int32:
2931
0
        case GDT_CInt32:
2932
0
            return 2147483647.0;
2933
2934
0
        case GDT_UInt32:
2935
0
            return 4294967295.0;
2936
2937
0
        case GDT_Int64:
2938
0
            return static_cast<double>(std::numeric_limits<GInt64>::max());
2939
2940
0
        case GDT_UInt64:
2941
0
            return static_cast<double>(std::numeric_limits<GUInt64>::max());
2942
2943
0
        case GDT_Float16:
2944
0
        case GDT_CFloat16:
2945
0
            return 65504.0;
2946
2947
0
        case GDT_Float32:
2948
0
        case GDT_CFloat32:
2949
0
            return 4294967295.0;  // Not actually accurate.
2950
2951
0
        case GDT_Float64:
2952
0
        case GDT_CFloat64:
2953
0
            return 4294967295.0;  // Not actually accurate.
2954
2955
0
        case GDT_Unknown:
2956
0
        case GDT_TypeCount:
2957
0
            break;
2958
0
    }
2959
0
    return 4294967295.0;  // Not actually accurate.
2960
0
}
2961
2962
/************************************************************************/
2963
/*                        GDALGetRasterMaximum()                        */
2964
/************************************************************************/
2965
2966
/**
2967
 * \brief Fetch the maximum value for this band.
2968
 *
2969
 * @see GDALRasterBand::GetMaximum()
2970
 */
2971
2972
double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2973
2974
0
{
2975
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2976
2977
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2978
0
    return poBand->GetMaximum(pbSuccess);
2979
0
}
2980
2981
/************************************************************************/
2982
/*                             GetMinimum()                             */
2983
/************************************************************************/
2984
2985
/**
2986
 * \brief Fetch the minimum value for this band.
2987
 *
2988
 * For file formats that don't know this intrinsically, the minimum supported
2989
 * value for the data type will generally be returned.
2990
 *
2991
 * This method is the same as the C function GDALGetRasterMinimum().
2992
 *
2993
 * @param pbSuccess pointer to a boolean to use to indicate if the
2994
 * returned value is a tight minimum or not.  May be NULL (default).
2995
 *
2996
 * @return the minimum raster value (excluding no data pixels)
2997
 */
2998
2999
double GDALRasterBand::GetMinimum(int *pbSuccess)
3000
3001
0
{
3002
0
    const char *pszValue = nullptr;
3003
3004
0
    if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3005
0
    {
3006
0
        if (pbSuccess != nullptr)
3007
0
            *pbSuccess = TRUE;
3008
3009
0
        return CPLAtofM(pszValue);
3010
0
    }
3011
3012
0
    if (pbSuccess != nullptr)
3013
0
        *pbSuccess = FALSE;
3014
3015
0
    switch (eDataType)
3016
0
    {
3017
0
        case GDT_UInt8:
3018
0
        {
3019
0
            EnablePixelTypeSignedByteWarning(false);
3020
0
            const char *pszPixelType =
3021
0
                GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3022
0
            EnablePixelTypeSignedByteWarning(true);
3023
0
            if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3024
0
                return -128;
3025
3026
0
            return 0;
3027
0
        }
3028
3029
0
        case GDT_Int8:
3030
0
            return -128;
3031
3032
0
        case GDT_UInt16:
3033
0
            return 0;
3034
3035
0
        case GDT_Int16:
3036
0
        case GDT_CInt16:
3037
0
            return -32768;
3038
3039
0
        case GDT_Int32:
3040
0
        case GDT_CInt32:
3041
0
            return -2147483648.0;
3042
3043
0
        case GDT_UInt32:
3044
0
            return 0;
3045
3046
0
        case GDT_Int64:
3047
0
            return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3048
3049
0
        case GDT_UInt64:
3050
0
            return 0;
3051
3052
0
        case GDT_Float16:
3053
0
        case GDT_CFloat16:
3054
0
            return -65504.0;
3055
3056
0
        case GDT_Float32:
3057
0
        case GDT_CFloat32:
3058
0
            return -4294967295.0;  // Not actually accurate.
3059
3060
0
        case GDT_Float64:
3061
0
        case GDT_CFloat64:
3062
0
            return -4294967295.0;  // Not actually accurate.
3063
3064
0
        case GDT_Unknown:
3065
0
        case GDT_TypeCount:
3066
0
            break;
3067
0
    }
3068
0
    return -4294967295.0;  // Not actually accurate.
3069
0
}
3070
3071
/************************************************************************/
3072
/*                        GDALGetRasterMinimum()                        */
3073
/************************************************************************/
3074
3075
/**
3076
 * \brief Fetch the minimum value for this band.
3077
 *
3078
 * @see GDALRasterBand::GetMinimum()
3079
 */
3080
3081
double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3082
3083
0
{
3084
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3085
3086
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3087
0
    return poBand->GetMinimum(pbSuccess);
3088
0
}
3089
3090
/************************************************************************/
3091
/*                       GetColorInterpretation()                       */
3092
/************************************************************************/
3093
3094
/**
3095
 * \brief How should this band be interpreted as color?
3096
 *
3097
 * GCI_Undefined is returned when the format doesn't know anything
3098
 * about the color interpretation.
3099
 *
3100
 * This method is the same as the C function
3101
 * GDALGetRasterColorInterpretation().
3102
 *
3103
 * @return color interpretation value for band.
3104
 */
3105
3106
GDALColorInterp GDALRasterBand::GetColorInterpretation()
3107
3108
0
{
3109
0
    return GCI_Undefined;
3110
0
}
3111
3112
/************************************************************************/
3113
/*                  GDALGetRasterColorInterpretation()                  */
3114
/************************************************************************/
3115
3116
/**
3117
 * \brief How should this band be interpreted as color?
3118
 *
3119
 * @see GDALRasterBand::GetColorInterpretation()
3120
 */
3121
3122
GDALColorInterp CPL_STDCALL
3123
GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3124
3125
0
{
3126
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3127
3128
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3129
0
    return poBand->GetColorInterpretation();
3130
0
}
3131
3132
/************************************************************************/
3133
/*                       SetColorInterpretation()                       */
3134
/************************************************************************/
3135
3136
/**
3137
 * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3138
 * \brief Set color interpretation of a band.
3139
 *
3140
 * This method is the same as the C function GDALSetRasterColorInterpretation().
3141
 *
3142
 * @param eColorInterp the new color interpretation to apply to this band.
3143
 *
3144
 * @return CE_None on success or CE_Failure if method is unsupported by format.
3145
 */
3146
3147
/**/
3148
/**/
3149
3150
CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3151
3152
0
{
3153
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3154
0
        ReportError(CE_Failure, CPLE_NotSupported,
3155
0
                    "SetColorInterpretation() not supported for this dataset.");
3156
0
    return CE_Failure;
3157
0
}
3158
3159
/************************************************************************/
3160
/*                  GDALSetRasterColorInterpretation()                  */
3161
/************************************************************************/
3162
3163
/**
3164
 * \brief Set color interpretation of a band.
3165
 *
3166
 * @see GDALRasterBand::SetColorInterpretation()
3167
 */
3168
3169
CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3170
    GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3171
3172
0
{
3173
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3174
3175
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3176
0
    return poBand->SetColorInterpretation(eColorInterp);
3177
0
}
3178
3179
/************************************************************************/
3180
/*                           GetColorTable()                            */
3181
/************************************************************************/
3182
3183
/**
3184
 * \brief Fetch the color table associated with band.
3185
 *
3186
 * If there is no associated color table, the return result is NULL.  The
3187
 * returned color table remains owned by the GDALRasterBand, and can't
3188
 * be depended on for long, nor should it ever be modified by the caller.
3189
 *
3190
 * This method is the same as the C function GDALGetRasterColorTable().
3191
 *
3192
 * @return internal color table, or NULL.
3193
 */
3194
3195
GDALColorTable *GDALRasterBand::GetColorTable()
3196
3197
0
{
3198
0
    return nullptr;
3199
0
}
3200
3201
/************************************************************************/
3202
/*                      GDALGetRasterColorTable()                       */
3203
/************************************************************************/
3204
3205
/**
3206
 * \brief Fetch the color table associated with band.
3207
 *
3208
 * @see GDALRasterBand::GetColorTable()
3209
 */
3210
3211
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3212
3213
0
{
3214
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3215
3216
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3217
0
    return GDALColorTable::ToHandle(poBand->GetColorTable());
3218
0
}
3219
3220
/************************************************************************/
3221
/*                           SetColorTable()                            */
3222
/************************************************************************/
3223
3224
/**
3225
 * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3226
 * \brief Set the raster color table.
3227
 *
3228
 * The driver will make a copy of all desired data in the colortable.  It
3229
 * remains owned by the caller after the call.
3230
 *
3231
 * This method is the same as the C function GDALSetRasterColorTable().
3232
 *
3233
 * @param poCT the color table to apply.  This may be NULL to clear the color
3234
 * table (where supported).
3235
 *
3236
 * @return CE_None on success, or CE_Failure on failure.  If the action is
3237
 * unsupported by the driver, a value of CE_Failure is returned, but no
3238
 * error is issued.
3239
 */
3240
3241
/**/
3242
/**/
3243
3244
CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3245
3246
0
{
3247
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3248
0
        ReportError(CE_Failure, CPLE_NotSupported,
3249
0
                    "SetColorTable() not supported for this dataset.");
3250
0
    return CE_Failure;
3251
0
}
3252
3253
/************************************************************************/
3254
/*                      GDALSetRasterColorTable()                       */
3255
/************************************************************************/
3256
3257
/**
3258
 * \brief Set the raster color table.
3259
 *
3260
 * @see GDALRasterBand::SetColorTable()
3261
 */
3262
3263
CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3264
                                           GDALColorTableH hCT)
3265
3266
0
{
3267
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3268
3269
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3270
0
    return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3271
0
}
3272
3273
/************************************************************************/
3274
/*                       HasArbitraryOverviews()                        */
3275
/************************************************************************/
3276
3277
/**
3278
 * \brief Check for arbitrary overviews.
3279
 *
3280
 * This returns TRUE if the underlying datastore can compute arbitrary
3281
 * overviews efficiently, such as is the case with OGDI over a network.
3282
 * Datastores with arbitrary overviews don't generally have any fixed
3283
 * overviews, but the RasterIO() method can be used in downsampling mode
3284
 * to get overview data efficiently.
3285
 *
3286
 * This method is the same as the C function GDALHasArbitraryOverviews(),
3287
 *
3288
 * @return TRUE if arbitrary overviews available (efficiently), otherwise
3289
 * FALSE.
3290
 */
3291
3292
int GDALRasterBand::HasArbitraryOverviews()
3293
3294
0
{
3295
0
    return FALSE;
3296
0
}
3297
3298
/************************************************************************/
3299
/*                     GDALHasArbitraryOverviews()                      */
3300
/************************************************************************/
3301
3302
/**
3303
 * \brief Check for arbitrary overviews.
3304
 *
3305
 * @see GDALRasterBand::HasArbitraryOverviews()
3306
 */
3307
3308
int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3309
3310
0
{
3311
0
    VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3312
3313
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3314
0
    return poBand->HasArbitraryOverviews();
3315
0
}
3316
3317
/************************************************************************/
3318
/*                          GetOverviewCount()                          */
3319
/************************************************************************/
3320
3321
/**
3322
 * \brief Return the number of overview layers available.
3323
 *
3324
 * This method is the same as the C function GDALGetOverviewCount().
3325
 *
3326
 * @return overview count, zero if none.
3327
 */
3328
3329
int GDALRasterBand::GetOverviewCount()
3330
3331
0
{
3332
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3333
0
        poDS->AreOverviewsEnabled())
3334
0
        return poDS->oOvManager.GetOverviewCount(nBand);
3335
3336
0
    return 0;
3337
0
}
3338
3339
/************************************************************************/
3340
/*                        GDALGetOverviewCount()                        */
3341
/************************************************************************/
3342
3343
/**
3344
 * \brief Return the number of overview layers available.
3345
 *
3346
 * @see GDALRasterBand::GetOverviewCount()
3347
 */
3348
3349
int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3350
3351
0
{
3352
0
    VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3353
3354
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3355
0
    return poBand->GetOverviewCount();
3356
0
}
3357
3358
/************************************************************************/
3359
/*                            GetOverview()                             */
3360
/************************************************************************/
3361
3362
/**
3363
 * \brief Fetch overview raster band object.
3364
 *
3365
 * This method is the same as the C function GDALGetOverview().
3366
 *
3367
 * @param i overview index between 0 and GetOverviewCount()-1.
3368
 *
3369
 * @return overview GDALRasterBand.
3370
 */
3371
3372
GDALRasterBand *GDALRasterBand::GetOverview(int i)
3373
3374
0
{
3375
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3376
0
        poDS->AreOverviewsEnabled())
3377
0
        return poDS->oOvManager.GetOverview(nBand, i);
3378
3379
0
    return nullptr;
3380
0
}
3381
3382
/************************************************************************/
3383
/*                          GDALGetOverview()                           */
3384
/************************************************************************/
3385
3386
/**
3387
 * \brief Fetch overview raster band object.
3388
 *
3389
 * @see GDALRasterBand::GetOverview()
3390
 */
3391
3392
GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3393
3394
0
{
3395
0
    VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3396
3397
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3398
0
    return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3399
0
}
3400
3401
/************************************************************************/
3402
/*                      GetRasterSampleOverview()                       */
3403
/************************************************************************/
3404
3405
/**
3406
 * \brief Fetch best sampling overview.
3407
 *
3408
 * Returns the most reduced overview of the given band that still satisfies
3409
 * the desired number of samples.  This function can be used with zero
3410
 * as the number of desired samples to fetch the most reduced overview.
3411
 * The same band as was passed in will be returned if it has not overviews,
3412
 * or if none of the overviews have enough samples.
3413
 *
3414
 * This method is the same as the C functions GDALGetRasterSampleOverview()
3415
 * and GDALGetRasterSampleOverviewEx().
3416
 *
3417
 * @param nDesiredSamples the returned band will have at least this many
3418
 * pixels.
3419
 *
3420
 * @return optimal overview or the band itself.
3421
 */
3422
3423
GDALRasterBand *
3424
GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3425
3426
0
{
3427
0
    GDALRasterBand *poBestBand = this;
3428
3429
0
    double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3430
3431
0
    for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3432
0
    {
3433
0
        GDALRasterBand *poOBand = GetOverview(iOverview);
3434
3435
0
        if (poOBand == nullptr)
3436
0
            continue;
3437
3438
0
        const double dfOSamples =
3439
0
            poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3440
3441
0
        if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3442
0
        {
3443
0
            dfBestSamples = dfOSamples;
3444
0
            poBestBand = poOBand;
3445
0
        }
3446
0
    }
3447
3448
0
    return poBestBand;
3449
0
}
3450
3451
/************************************************************************/
3452
/*                    GDALGetRasterSampleOverview()                     */
3453
/************************************************************************/
3454
3455
/**
3456
 * \brief Fetch best sampling overview.
3457
 *
3458
 * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3459
 * billion samples.
3460
 *
3461
 * @see GDALRasterBand::GetRasterSampleOverview()
3462
 * @see GDALGetRasterSampleOverviewEx()
3463
 */
3464
3465
GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3466
                                                        int nDesiredSamples)
3467
3468
0
{
3469
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3470
3471
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3472
0
    return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3473
0
        nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3474
0
}
3475
3476
/************************************************************************/
3477
/*                    GDALGetRasterSampleOverviewEx()                   */
3478
/************************************************************************/
3479
3480
/**
3481
 * \brief Fetch best sampling overview.
3482
 *
3483
 * @see GDALRasterBand::GetRasterSampleOverview()
3484
 */
3485
3486
GDALRasterBandH CPL_STDCALL
3487
GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3488
3489
0
{
3490
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3491
3492
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3493
0
    return GDALRasterBand::ToHandle(
3494
0
        poBand->GetRasterSampleOverview(nDesiredSamples));
3495
0
}
3496
3497
/************************************************************************/
3498
/*                           BuildOverviews()                           */
3499
/************************************************************************/
3500
3501
/**
3502
 * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3503
 * GDALProgressFunc, void*) \brief Build raster overview(s)
3504
 *
3505
 * If the operation is unsupported for the indicated dataset, then
3506
 * CE_Failure is returned, and CPLGetLastErrorNo() will return
3507
 * CPLE_NotSupported.
3508
 *
3509
 * WARNING: Most formats don't support per-band overview computation, but
3510
 * require that overviews are computed for all bands of a dataset, using
3511
 * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3512
 * is the HFA driver which supports this method.
3513
 *
3514
 * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3515
 * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3516
 * applied.
3517
 * @param nOverviews number of overviews to build.
3518
 * @param panOverviewList the list of overview decimation factors to build.
3519
 * @param pfnProgress a function to call to report progress, or NULL.
3520
 * @param pProgressData application data to pass to the progress function.
3521
 * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3522
 *                     key=value pairs, or NULL
3523
 *
3524
 * @return CE_None on success or CE_Failure if the operation doesn't work.
3525
 */
3526
3527
/**/
3528
/**/
3529
3530
CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3531
                                      int /*nOverviews*/,
3532
                                      const int * /*panOverviewList*/,
3533
                                      GDALProgressFunc /*pfnProgress*/,
3534
                                      void * /*pProgressData*/,
3535
                                      CSLConstList /* papszOptions */)
3536
3537
0
{
3538
0
    ReportError(CE_Failure, CPLE_NotSupported,
3539
0
                "BuildOverviews() not supported for this dataset.");
3540
3541
0
    return (CE_Failure);
3542
0
}
3543
3544
/************************************************************************/
3545
/*                             GetOffset()                              */
3546
/************************************************************************/
3547
3548
/**
3549
 * \brief Fetch the raster value offset.
3550
 *
3551
 * This value (in combination with the GetScale() value) can be used to
3552
 * transform raw pixel values into the units returned by GetUnitType().
3553
 * For example this might be used to store elevations in GUInt16 bands
3554
 * with a precision of 0.1, and starting from -100.
3555
 *
3556
 * Units value = (raw value * scale) + offset
3557
 *
3558
 * Note that applying scale and offset is of the responsibility of the user,
3559
 * and is not done by methods such as RasterIO() or ReadBlock().
3560
 *
3561
 * For file formats that don't know this intrinsically a value of zero
3562
 * is returned.
3563
 *
3564
 * This method is the same as the C function GDALGetRasterOffset().
3565
 *
3566
 * @param pbSuccess pointer to a boolean to use to indicate if the
3567
 * returned value is meaningful or not.  May be NULL (default).
3568
 *
3569
 * @return the raster offset.
3570
 */
3571
3572
double GDALRasterBand::GetOffset(int *pbSuccess)
3573
3574
0
{
3575
0
    if (pbSuccess != nullptr)
3576
0
        *pbSuccess = FALSE;
3577
3578
0
    return 0.0;
3579
0
}
3580
3581
/************************************************************************/
3582
/*                        GDALGetRasterOffset()                         */
3583
/************************************************************************/
3584
3585
/**
3586
 * \brief Fetch the raster value offset.
3587
 *
3588
 * @see GDALRasterBand::GetOffset()
3589
 */
3590
3591
double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3592
3593
0
{
3594
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3595
3596
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3597
0
    return poBand->GetOffset(pbSuccess);
3598
0
}
3599
3600
/************************************************************************/
3601
/*                             SetOffset()                              */
3602
/************************************************************************/
3603
3604
/**
3605
 * \fn GDALRasterBand::SetOffset(double)
3606
 * \brief Set scaling offset.
3607
 *
3608
 * Very few formats implement this method.   When not implemented it will
3609
 * issue a CPLE_NotSupported error and return CE_Failure.
3610
 *
3611
 * This method is the same as the C function GDALSetRasterOffset().
3612
 *
3613
 * @param dfNewOffset the new offset.
3614
 *
3615
 * @return CE_None or success or CE_Failure on failure.
3616
 */
3617
3618
/**/
3619
/**/
3620
3621
CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3622
0
{
3623
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3624
0
        ReportError(CE_Failure, CPLE_NotSupported,
3625
0
                    "SetOffset() not supported on this raster band.");
3626
3627
0
    return CE_Failure;
3628
0
}
3629
3630
/************************************************************************/
3631
/*                        GDALSetRasterOffset()                         */
3632
/************************************************************************/
3633
3634
/**
3635
 * \brief Set scaling offset.
3636
 *
3637
 * @see GDALRasterBand::SetOffset()
3638
 */
3639
3640
CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3641
                                       double dfNewOffset)
3642
3643
0
{
3644
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3645
3646
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3647
0
    return poBand->SetOffset(dfNewOffset);
3648
0
}
3649
3650
/************************************************************************/
3651
/*                              GetScale()                              */
3652
/************************************************************************/
3653
3654
/**
3655
 * \brief Fetch the raster value scale.
3656
 *
3657
 * This value (in combination with the GetOffset() value) can be used to
3658
 * transform raw pixel values into the units returned by GetUnitType().
3659
 * For example this might be used to store elevations in GUInt16 bands
3660
 * with a precision of 0.1, and starting from -100.
3661
 *
3662
 * Units value = (raw value * scale) + offset
3663
 *
3664
 * Note that applying scale and offset is of the responsibility of the user,
3665
 * and is not done by methods such as RasterIO() or ReadBlock().
3666
 *
3667
 * For file formats that don't know this intrinsically a value of one
3668
 * is returned.
3669
 *
3670
 * This method is the same as the C function GDALGetRasterScale().
3671
 *
3672
 * @param pbSuccess pointer to a boolean to use to indicate if the
3673
 * returned value is meaningful or not.  May be NULL (default).
3674
 *
3675
 * @return the raster scale.
3676
 */
3677
3678
double GDALRasterBand::GetScale(int *pbSuccess)
3679
3680
0
{
3681
0
    if (pbSuccess != nullptr)
3682
0
        *pbSuccess = FALSE;
3683
3684
0
    return 1.0;
3685
0
}
3686
3687
/************************************************************************/
3688
/*                         GDALGetRasterScale()                         */
3689
/************************************************************************/
3690
3691
/**
3692
 * \brief Fetch the raster value scale.
3693
 *
3694
 * @see GDALRasterBand::GetScale()
3695
 */
3696
3697
double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3698
3699
0
{
3700
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3701
3702
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3703
0
    return poBand->GetScale(pbSuccess);
3704
0
}
3705
3706
/************************************************************************/
3707
/*                              SetScale()                              */
3708
/************************************************************************/
3709
3710
/**
3711
 * \fn GDALRasterBand::SetScale(double)
3712
 * \brief Set scaling ratio.
3713
 *
3714
 * Very few formats implement this method.   When not implemented it will
3715
 * issue a CPLE_NotSupported error and return CE_Failure.
3716
 *
3717
 * This method is the same as the C function GDALSetRasterScale().
3718
 *
3719
 * @param dfNewScale the new scale.
3720
 *
3721
 * @return CE_None or success or CE_Failure on failure.
3722
 */
3723
3724
/**/
3725
/**/
3726
3727
CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3728
3729
0
{
3730
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3731
0
        ReportError(CE_Failure, CPLE_NotSupported,
3732
0
                    "SetScale() not supported on this raster band.");
3733
3734
0
    return CE_Failure;
3735
0
}
3736
3737
/************************************************************************/
3738
/*                        GDALSetRasterScale()                          */
3739
/************************************************************************/
3740
3741
/**
3742
 * \brief Set scaling ratio.
3743
 *
3744
 * @see GDALRasterBand::SetScale()
3745
 */
3746
3747
CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3748
3749
0
{
3750
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3751
3752
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3753
0
    return poBand->SetScale(dfNewOffset);
3754
0
}
3755
3756
/************************************************************************/
3757
/*                            GetUnitType()                             */
3758
/************************************************************************/
3759
3760
/**
3761
 * \brief Return raster unit type.
3762
 *
3763
 * Return a name for the units of this raster's values.  For instance, it
3764
 * might be "m" for an elevation model in meters, or "ft" for feet.  If no
3765
 * units are available, a value of "" will be returned.  The returned string
3766
 * should not be modified, nor freed by the calling application.
3767
 *
3768
 * This method is the same as the C function GDALGetRasterUnitType().
3769
 *
3770
 * @return unit name string.
3771
 */
3772
3773
const char *GDALRasterBand::GetUnitType()
3774
3775
0
{
3776
0
    return "";
3777
0
}
3778
3779
/************************************************************************/
3780
/*                       GDALGetRasterUnitType()                        */
3781
/************************************************************************/
3782
3783
/**
3784
 * \brief Return raster unit type.
3785
 *
3786
 * @see GDALRasterBand::GetUnitType()
3787
 */
3788
3789
const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3790
3791
0
{
3792
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3793
3794
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3795
0
    return poBand->GetUnitType();
3796
0
}
3797
3798
/************************************************************************/
3799
/*                            SetUnitType()                             */
3800
/************************************************************************/
3801
3802
/**
3803
 * \fn GDALRasterBand::SetUnitType(const char*)
3804
 * \brief Set unit type.
3805
 *
3806
 * Set the unit type for a raster band.  Values should be one of
3807
 * "" (the default indicating it is unknown), "m" indicating meters,
3808
 * or "ft" indicating feet, though other nonstandard values are allowed.
3809
 *
3810
 * This method is the same as the C function GDALSetRasterUnitType().
3811
 *
3812
 * @param pszNewValue the new unit type value.
3813
 *
3814
 * @return CE_None on success or CE_Failure if not successful, or
3815
 * unsupported.
3816
 */
3817
3818
/**/
3819
/**/
3820
3821
CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3822
3823
0
{
3824
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3825
0
        ReportError(CE_Failure, CPLE_NotSupported,
3826
0
                    "SetUnitType() not supported on this raster band.");
3827
0
    return CE_Failure;
3828
0
}
3829
3830
/************************************************************************/
3831
/*                       GDALSetRasterUnitType()                        */
3832
/************************************************************************/
3833
3834
/**
3835
 * \brief Set unit type.
3836
 *
3837
 * @see GDALRasterBand::SetUnitType()
3838
 *
3839
 */
3840
3841
CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842
                                         const char *pszNewValue)
3843
3844
0
{
3845
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846
3847
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848
0
    return poBand->SetUnitType(pszNewValue);
3849
0
}
3850
3851
/************************************************************************/
3852
/*                              GetXSize()                              */
3853
/************************************************************************/
3854
3855
/**
3856
 * \brief Fetch XSize of raster.
3857
 *
3858
 * This method is the same as the C function GDALGetRasterBandXSize().
3859
 *
3860
 * @return the width in pixels of this band.
3861
 */
3862
3863
int GDALRasterBand::GetXSize() const
3864
3865
0
{
3866
0
    return nRasterXSize;
3867
0
}
3868
3869
/************************************************************************/
3870
/*                       GDALGetRasterBandXSize()                       */
3871
/************************************************************************/
3872
3873
/**
3874
 * \brief Fetch XSize of raster.
3875
 *
3876
 * @see GDALRasterBand::GetXSize()
3877
 */
3878
3879
int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880
3881
0
{
3882
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883
3884
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885
0
    return poBand->GetXSize();
3886
0
}
3887
3888
/************************************************************************/
3889
/*                              GetYSize()                              */
3890
/************************************************************************/
3891
3892
/**
3893
 * \brief Fetch YSize of raster.
3894
 *
3895
 * This method is the same as the C function GDALGetRasterBandYSize().
3896
 *
3897
 * @return the height in pixels of this band.
3898
 */
3899
3900
int GDALRasterBand::GetYSize() const
3901
3902
0
{
3903
0
    return nRasterYSize;
3904
0
}
3905
3906
/************************************************************************/
3907
/*                       GDALGetRasterBandYSize()                       */
3908
/************************************************************************/
3909
3910
/**
3911
 * \brief Fetch YSize of raster.
3912
 *
3913
 * @see GDALRasterBand::GetYSize()
3914
 */
3915
3916
int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917
3918
0
{
3919
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920
3921
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922
0
    return poBand->GetYSize();
3923
0
}
3924
3925
/************************************************************************/
3926
/*                              GetBand()                               */
3927
/************************************************************************/
3928
3929
/**
3930
 * \brief Fetch the band number.
3931
 *
3932
 * This method returns the band that this GDALRasterBand objects represents
3933
 * within its dataset.  This method may return a value of 0 to indicate
3934
 * GDALRasterBand objects without an apparently relationship to a dataset,
3935
 * such as GDALRasterBands serving as overviews.
3936
 *
3937
 * This method is the same as the C function GDALGetBandNumber().
3938
 *
3939
 * @return band number (1+) or 0 if the band number isn't known.
3940
 */
3941
3942
int GDALRasterBand::GetBand() const
3943
3944
0
{
3945
0
    return nBand;
3946
0
}
3947
3948
/************************************************************************/
3949
/*                         GDALGetBandNumber()                          */
3950
/************************************************************************/
3951
3952
/**
3953
 * \brief Fetch the band number.
3954
 *
3955
 * @see GDALRasterBand::GetBand()
3956
 */
3957
3958
int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3959
3960
0
{
3961
0
    VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3962
3963
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3964
0
    return poBand->GetBand();
3965
0
}
3966
3967
/************************************************************************/
3968
/*                             GetDataset()                             */
3969
/************************************************************************/
3970
3971
/**
3972
 * \brief Fetch the owning dataset handle.
3973
 *
3974
 * Note that some GDALRasterBands are not considered to be a part of a dataset,
3975
 * such as overviews or other "freestanding" bands.
3976
 *
3977
 * This method is the same as the C function GDALGetBandDataset().
3978
 *
3979
 * @return the pointer to the GDALDataset to which this band belongs, or
3980
 * NULL if this cannot be determined.
3981
 */
3982
3983
GDALDataset *GDALRasterBand::GetDataset() const
3984
3985
0
{
3986
0
    return poDS;
3987
0
}
3988
3989
/************************************************************************/
3990
/*                         GDALGetBandDataset()                         */
3991
/************************************************************************/
3992
3993
/**
3994
 * \brief Fetch the owning dataset handle.
3995
 *
3996
 * @see GDALRasterBand::GetDataset()
3997
 */
3998
3999
GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000
4001
0
{
4002
0
    VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003
4004
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005
0
    return GDALDataset::ToHandle(poBand->GetDataset());
4006
0
}
4007
4008
/************************************************************************/
4009
/*                        ComputeFloat16NoDataValue()                     */
4010
/************************************************************************/
4011
4012
static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013
                                             double dfNoDataValue,
4014
                                             int &bGotNoDataValue,
4015
                                             GFloat16 &fNoDataValue,
4016
                                             bool &bGotFloat16NoDataValue)
4017
0
{
4018
0
    if (eDataType == GDT_Float16 && bGotNoDataValue)
4019
0
    {
4020
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4021
0
        if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4022
0
        {
4023
0
            fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4024
0
            bGotFloat16NoDataValue = true;
4025
0
            bGotNoDataValue = false;
4026
0
        }
4027
0
    }
4028
0
}
4029
4030
/************************************************************************/
4031
/*                        ComputeFloatNoDataValue()                     */
4032
/************************************************************************/
4033
4034
static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035
                                           double dfNoDataValue,
4036
                                           int &bGotNoDataValue,
4037
                                           float &fNoDataValue,
4038
                                           bool &bGotFloatNoDataValue)
4039
0
{
4040
0
    if (eDataType == GDT_Float32 && bGotNoDataValue)
4041
0
    {
4042
0
        dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4043
0
        if (GDALIsValueInRange<float>(dfNoDataValue))
4044
0
        {
4045
0
            fNoDataValue = static_cast<float>(dfNoDataValue);
4046
0
            bGotFloatNoDataValue = true;
4047
0
            bGotNoDataValue = false;
4048
0
        }
4049
0
    }
4050
0
}
4051
4052
/************************************************************************/
4053
/*                        struct GDALNoDataValues                       */
4054
/************************************************************************/
4055
4056
/**
4057
 * \brief No-data-values for all types
4058
 *
4059
 * The functions below pass various no-data-values around. To avoid
4060
 * long argument lists, this struct collects the no-data-values for
4061
 * all types into a single, convenient place.
4062
 **/
4063
4064
struct GDALNoDataValues
4065
{
4066
    int bGotNoDataValue;
4067
    double dfNoDataValue;
4068
4069
    bool bGotInt64NoDataValue;
4070
    int64_t nInt64NoDataValue;
4071
4072
    bool bGotUInt64NoDataValue;
4073
    uint64_t nUInt64NoDataValue;
4074
4075
    bool bGotFloatNoDataValue;
4076
    float fNoDataValue;
4077
4078
    bool bGotFloat16NoDataValue;
4079
    GFloat16 hfNoDataValue;
4080
4081
    GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4082
0
        : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4083
0
          bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4084
0
          bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4085
0
          bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4086
0
          bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4087
0
    {
4088
0
        if (eDataType == GDT_Int64)
4089
0
        {
4090
0
            int nGot = false;
4091
0
            nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4092
0
            bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4093
0
            if (bGotInt64NoDataValue)
4094
0
            {
4095
0
                dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4096
0
                bGotNoDataValue =
4097
0
                    nInt64NoDataValue <=
4098
0
                        std::numeric_limits<int64_t>::max() - 1024 &&
4099
0
                    static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4100
0
            }
4101
0
            else
4102
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4103
0
        }
4104
0
        else if (eDataType == GDT_UInt64)
4105
0
        {
4106
0
            int nGot = false;
4107
0
            nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4108
0
            bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4109
0
            if (bGotUInt64NoDataValue)
4110
0
            {
4111
0
                dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4112
0
                bGotNoDataValue =
4113
0
                    nUInt64NoDataValue <=
4114
0
                        std::numeric_limits<uint64_t>::max() - 2048 &&
4115
0
                    static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4116
0
            }
4117
0
            else
4118
0
                dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4119
0
        }
4120
0
        else
4121
0
        {
4122
0
            dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4123
0
            bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4124
4125
0
            ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4126
0
                                    fNoDataValue, bGotFloatNoDataValue);
4127
4128
0
            ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4129
0
                                      hfNoDataValue, bGotFloat16NoDataValue);
4130
0
        }
4131
0
    }
4132
};
4133
4134
/************************************************************************/
4135
/*                            ARE_REAL_EQUAL()                          */
4136
/************************************************************************/
4137
4138
inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4139
0
{
4140
0
    using std::abs;
4141
0
    return dfVal1 == dfVal2 || /* Should cover infinity */
4142
0
           abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4143
0
                                      abs(dfVal1 + dfVal2) * ulp;
4144
0
}
4145
4146
/************************************************************************/
4147
/*                            GetHistogram()                            */
4148
/************************************************************************/
4149
4150
/**
4151
 * \brief Compute raster histogram.
4152
 *
4153
 * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4154
 *
4155
 * For example to compute a simple 256 entry histogram of eight bit data,
4156
 * the following would be suitable.  The unusual bounds are to ensure that
4157
 * bucket boundaries don't fall right on integer values causing possible errors
4158
 * due to rounding after scaling.
4159
\code{.cpp}
4160
    GUIntBig anHistogram[256];
4161
4162
    poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4163
                          GDALDummyProgress, nullptr );
4164
\endcode
4165
 *
4166
 * Note that setting bApproxOK will generally result in a subsampling of the
4167
 * file, and will utilize overviews if available.  It should generally
4168
 * produce a representative histogram for the data that is suitable for use
4169
 * in generating histogram based luts for instance.  Generally bApproxOK is
4170
 * much faster than an exactly computed histogram.
4171
 *
4172
 * This method is the same as the C functions GDALGetRasterHistogram() and
4173
 * GDALGetRasterHistogramEx().
4174
 *
4175
 * @param dfMin the lower bound of the histogram.
4176
 * @param dfMax the upper bound of the histogram.
4177
 * @param nBuckets the number of buckets in panHistogram.
4178
 * @param panHistogram array into which the histogram totals are placed.
4179
 * @param bIncludeOutOfRange if TRUE values below the histogram range will
4180
 * mapped into panHistogram[0], and values above will be mapped into
4181
 * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4182
 * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4183
 * @param pfnProgress function to report progress to completion.
4184
 * @param pProgressData application data to pass to pfnProgress.
4185
 *
4186
 * @return CE_None on success, or CE_Failure if something goes wrong.
4187
 */
4188
4189
CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4190
                                    GUIntBig *panHistogram,
4191
                                    int bIncludeOutOfRange, int bApproxOK,
4192
                                    GDALProgressFunc pfnProgress,
4193
                                    void *pProgressData)
4194
4195
0
{
4196
0
    CPLAssert(nullptr != panHistogram);
4197
4198
0
    if (pfnProgress == nullptr)
4199
0
        pfnProgress = GDALDummyProgress;
4200
4201
    /* -------------------------------------------------------------------- */
4202
    /*      If we have overviews, use them for the histogram.               */
4203
    /* -------------------------------------------------------------------- */
4204
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4205
0
    {
4206
        // FIXME: should we use the most reduced overview here or use some
4207
        // minimum number of samples like GDALRasterBand::ComputeStatistics()
4208
        // does?
4209
0
        GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4210
4211
0
        if (poBestOverview != this)
4212
0
        {
4213
0
            return poBestOverview->GetHistogram(
4214
0
                dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4215
0
                bApproxOK, pfnProgress, pProgressData);
4216
0
        }
4217
0
    }
4218
4219
    /* -------------------------------------------------------------------- */
4220
    /*      Read actual data and build histogram.                           */
4221
    /* -------------------------------------------------------------------- */
4222
0
    if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4223
0
    {
4224
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4225
0
        return CE_Failure;
4226
0
    }
4227
4228
    // Written this way to deal with NaN
4229
0
    if (!(dfMax > dfMin))
4230
0
    {
4231
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4232
0
                    "dfMax should be strictly greater than dfMin");
4233
0
        return CE_Failure;
4234
0
    }
4235
4236
0
    GDALRasterIOExtraArg sExtraArg;
4237
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4238
4239
0
    const double dfScale = nBuckets / (dfMax - dfMin);
4240
0
    if (dfScale == 0 || !std::isfinite(dfScale))
4241
0
    {
4242
0
        ReportError(CE_Failure, CPLE_IllegalArg,
4243
0
                    "dfMin and dfMax should be finite values such that "
4244
0
                    "nBuckets / (dfMax - dfMin) is non-zero");
4245
0
        return CE_Failure;
4246
0
    }
4247
0
    memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4248
4249
0
    GDALNoDataValues sNoDataValues(this, eDataType);
4250
0
    GDALRasterBand *poMaskBand = nullptr;
4251
0
    if (!sNoDataValues.bGotNoDataValue)
4252
0
    {
4253
0
        const int l_nMaskFlags = GetMaskFlags();
4254
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
4255
0
            GetColorInterpretation() != GCI_AlphaBand)
4256
0
        {
4257
0
            poMaskBand = GetMaskBand();
4258
0
        }
4259
0
    }
4260
4261
0
    bool bSignedByte = false;
4262
0
    if (eDataType == GDT_UInt8)
4263
0
    {
4264
0
        EnablePixelTypeSignedByteWarning(false);
4265
0
        const char *pszPixelType =
4266
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4267
0
        EnablePixelTypeSignedByteWarning(true);
4268
0
        bSignedByte =
4269
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4270
0
    }
4271
4272
0
    if (bApproxOK && HasArbitraryOverviews())
4273
0
    {
4274
        /* --------------------------------------------------------------------
4275
         */
4276
        /*      Figure out how much the image should be reduced to get an */
4277
        /*      approximate value. */
4278
        /* --------------------------------------------------------------------
4279
         */
4280
0
        const double dfReduction =
4281
0
            sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4282
0
                 GDALSTAT_APPROX_NUMSAMPLES);
4283
4284
0
        int nXReduced = nRasterXSize;
4285
0
        int nYReduced = nRasterYSize;
4286
0
        if (dfReduction > 1.0)
4287
0
        {
4288
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4289
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4290
4291
            // Catch the case of huge resizing ratios here
4292
0
            if (nXReduced == 0)
4293
0
                nXReduced = 1;
4294
0
            if (nYReduced == 0)
4295
0
                nYReduced = 1;
4296
0
        }
4297
4298
0
        void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4299
0
                                          nXReduced, nYReduced);
4300
0
        if (!pData)
4301
0
            return CE_Failure;
4302
4303
0
        const CPLErr eErr =
4304
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4305
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4306
0
        if (eErr != CE_None)
4307
0
        {
4308
0
            CPLFree(pData);
4309
0
            return eErr;
4310
0
        }
4311
4312
0
        GByte *pabyMaskData = nullptr;
4313
0
        if (poMaskBand)
4314
0
        {
4315
0
            pabyMaskData =
4316
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4317
0
            if (!pabyMaskData)
4318
0
            {
4319
0
                CPLFree(pData);
4320
0
                return CE_Failure;
4321
0
            }
4322
4323
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4324
0
                                     pabyMaskData, nXReduced, nYReduced,
4325
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
4326
0
            {
4327
0
                CPLFree(pData);
4328
0
                CPLFree(pabyMaskData);
4329
0
                return CE_Failure;
4330
0
            }
4331
0
        }
4332
4333
        // This isn't the fastest way to do this, but is easier for now.
4334
0
        for (int iY = 0; iY < nYReduced; iY++)
4335
0
        {
4336
0
            for (int iX = 0; iX < nXReduced; iX++)
4337
0
            {
4338
0
                const int iOffset = iX + iY * nXReduced;
4339
0
                double dfValue = 0.0;
4340
4341
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
4342
0
                    continue;
4343
4344
0
                switch (eDataType)
4345
0
                {
4346
0
                    case GDT_UInt8:
4347
0
                    {
4348
0
                        if (bSignedByte)
4349
0
                            dfValue =
4350
0
                                static_cast<signed char *>(pData)[iOffset];
4351
0
                        else
4352
0
                            dfValue = static_cast<GByte *>(pData)[iOffset];
4353
0
                        break;
4354
0
                    }
4355
0
                    case GDT_Int8:
4356
0
                        dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357
0
                        break;
4358
0
                    case GDT_UInt16:
4359
0
                        dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360
0
                        break;
4361
0
                    case GDT_Int16:
4362
0
                        dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363
0
                        break;
4364
0
                    case GDT_UInt32:
4365
0
                        dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366
0
                        break;
4367
0
                    case GDT_Int32:
4368
0
                        dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369
0
                        break;
4370
0
                    case GDT_UInt64:
4371
0
                        dfValue = static_cast<double>(
4372
0
                            static_cast<GUInt64 *>(pData)[iOffset]);
4373
0
                        break;
4374
0
                    case GDT_Int64:
4375
0
                        dfValue = static_cast<double>(
4376
0
                            static_cast<GInt64 *>(pData)[iOffset]);
4377
0
                        break;
4378
0
                    case GDT_Float16:
4379
0
                    {
4380
0
                        using namespace std;
4381
0
                        const GFloat16 hfValue =
4382
0
                            static_cast<GFloat16 *>(pData)[iOffset];
4383
0
                        if (isnan(hfValue) ||
4384
0
                            (sNoDataValues.bGotFloat16NoDataValue &&
4385
0
                             ARE_REAL_EQUAL(hfValue,
4386
0
                                            sNoDataValues.hfNoDataValue)))
4387
0
                            continue;
4388
0
                        dfValue = hfValue;
4389
0
                        break;
4390
0
                    }
4391
0
                    case GDT_Float32:
4392
0
                    {
4393
0
                        const float fValue =
4394
0
                            static_cast<float *>(pData)[iOffset];
4395
0
                        if (std::isnan(fValue) ||
4396
0
                            (sNoDataValues.bGotFloatNoDataValue &&
4397
0
                             ARE_REAL_EQUAL(fValue,
4398
0
                                            sNoDataValues.fNoDataValue)))
4399
0
                            continue;
4400
0
                        dfValue = double(fValue);
4401
0
                        break;
4402
0
                    }
4403
0
                    case GDT_Float64:
4404
0
                        dfValue = static_cast<double *>(pData)[iOffset];
4405
0
                        if (std::isnan(dfValue))
4406
0
                            continue;
4407
0
                        break;
4408
0
                    case GDT_CInt16:
4409
0
                    {
4410
0
                        const double dfReal =
4411
0
                            static_cast<GInt16 *>(pData)[iOffset * 2];
4412
0
                        const double dfImag =
4413
0
                            static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4414
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4415
0
                            continue;
4416
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4417
0
                    }
4418
0
                    break;
4419
0
                    case GDT_CInt32:
4420
0
                    {
4421
0
                        const double dfReal =
4422
0
                            static_cast<GInt32 *>(pData)[iOffset * 2];
4423
0
                        const double dfImag =
4424
0
                            static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4425
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4426
0
                            continue;
4427
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4428
0
                    }
4429
0
                    break;
4430
0
                    case GDT_CFloat16:
4431
0
                    {
4432
0
                        const double dfReal =
4433
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2];
4434
0
                        const double dfImag =
4435
0
                            static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4436
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4437
0
                            continue;
4438
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4439
0
                        break;
4440
0
                    }
4441
0
                    case GDT_CFloat32:
4442
0
                    {
4443
0
                        const double dfReal =
4444
0
                            double(static_cast<float *>(pData)[iOffset * 2]);
4445
0
                        const double dfImag = double(
4446
0
                            static_cast<float *>(pData)[iOffset * 2 + 1]);
4447
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4448
0
                            continue;
4449
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4450
0
                        break;
4451
0
                    }
4452
0
                    case GDT_CFloat64:
4453
0
                    {
4454
0
                        const double dfReal =
4455
0
                            static_cast<double *>(pData)[iOffset * 2];
4456
0
                        const double dfImag =
4457
0
                            static_cast<double *>(pData)[iOffset * 2 + 1];
4458
0
                        if (std::isnan(dfReal) || std::isnan(dfImag))
4459
0
                            continue;
4460
0
                        dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4461
0
                        break;
4462
0
                    }
4463
0
                    case GDT_Unknown:
4464
0
                    case GDT_TypeCount:
4465
0
                        CPLAssert(false);
4466
0
                }
4467
4468
0
                if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4469
0
                    sNoDataValues.bGotNoDataValue &&
4470
0
                    ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4471
0
                    continue;
4472
4473
                // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4474
                // finite, the result of the multiplication cannot be NaN
4475
0
                const double dfIndex = floor((dfValue - dfMin) * dfScale);
4476
4477
0
                if (dfIndex < 0)
4478
0
                {
4479
0
                    if (bIncludeOutOfRange)
4480
0
                        panHistogram[0]++;
4481
0
                }
4482
0
                else if (dfIndex >= nBuckets)
4483
0
                {
4484
0
                    if (bIncludeOutOfRange)
4485
0
                        ++panHistogram[nBuckets - 1];
4486
0
                }
4487
0
                else
4488
0
                {
4489
0
                    ++panHistogram[static_cast<int>(dfIndex)];
4490
0
                }
4491
0
            }
4492
0
        }
4493
4494
0
        CPLFree(pData);
4495
0
        CPLFree(pabyMaskData);
4496
0
    }
4497
0
    else  // No arbitrary overviews.
4498
0
    {
4499
0
        if (!InitBlockInfo())
4500
0
            return CE_Failure;
4501
4502
        /* --------------------------------------------------------------------
4503
         */
4504
        /*      Figure out the ratio of blocks we will read to get an */
4505
        /*      approximate value. */
4506
        /* --------------------------------------------------------------------
4507
         */
4508
4509
0
        int nSampleRate = 1;
4510
0
        if (bApproxOK)
4511
0
        {
4512
0
            nSampleRate = static_cast<int>(std::max(
4513
0
                1.0,
4514
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4515
            // We want to avoid probing only the first column of blocks for
4516
            // a square shaped raster, because it is not unlikely that it may
4517
            // be padding only (#6378).
4518
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4519
0
                nSampleRate += 1;
4520
0
        }
4521
4522
0
        GByte *pabyMaskData = nullptr;
4523
0
        if (poMaskBand)
4524
0
        {
4525
0
            pabyMaskData = static_cast<GByte *>(
4526
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4527
0
            if (!pabyMaskData)
4528
0
            {
4529
0
                return CE_Failure;
4530
0
            }
4531
0
        }
4532
4533
        /* --------------------------------------------------------------------
4534
         */
4535
        /*      Read the blocks, and add to histogram. */
4536
        /* --------------------------------------------------------------------
4537
         */
4538
0
        for (GIntBig iSampleBlock = 0;
4539
0
             iSampleBlock <
4540
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4541
0
             iSampleBlock += nSampleRate)
4542
0
        {
4543
0
            if (!pfnProgress(
4544
0
                    static_cast<double>(iSampleBlock) /
4545
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4546
0
                    "Compute Histogram", pProgressData))
4547
0
            {
4548
0
                CPLFree(pabyMaskData);
4549
0
                return CE_Failure;
4550
0
            }
4551
4552
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4553
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4554
4555
0
            int nXCheck = 0, nYCheck = 0;
4556
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4557
4558
0
            if (poMaskBand &&
4559
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4560
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
4561
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4562
0
                                     0, nBlockXSize, nullptr) != CE_None)
4563
0
            {
4564
0
                CPLFree(pabyMaskData);
4565
0
                return CE_Failure;
4566
0
            }
4567
4568
0
            GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4569
0
            if (poBlock == nullptr)
4570
0
            {
4571
0
                CPLFree(pabyMaskData);
4572
0
                return CE_Failure;
4573
0
            }
4574
4575
0
            void *pData = poBlock->GetDataRef();
4576
4577
            // this is a special case for a common situation.
4578
0
            if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4579
0
                (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4580
0
                nXCheck == nBlockXSize && nBuckets == 256)
4581
0
            {
4582
0
                const GPtrDiff_t nPixels =
4583
0
                    static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4584
0
                GByte *pabyData = static_cast<GByte *>(pData);
4585
4586
0
                for (GPtrDiff_t i = 0; i < nPixels; i++)
4587
0
                {
4588
0
                    if (pabyMaskData && pabyMaskData[i] == 0)
4589
0
                        continue;
4590
0
                    if (!(sNoDataValues.bGotNoDataValue &&
4591
0
                          (pabyData[i] ==
4592
0
                           static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4593
0
                    {
4594
0
                        panHistogram[pabyData[i]]++;
4595
0
                    }
4596
0
                }
4597
4598
0
                poBlock->DropLock();
4599
0
                continue;  // To next sample block.
4600
0
            }
4601
4602
            // This isn't the fastest way to do this, but is easier for now.
4603
0
            for (int iY = 0; iY < nYCheck; iY++)
4604
0
            {
4605
0
                for (int iX = 0; iX < nXCheck; iX++)
4606
0
                {
4607
0
                    const GPtrDiff_t iOffset =
4608
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4609
4610
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
4611
0
                        continue;
4612
4613
0
                    double dfValue = 0.0;
4614
4615
0
                    switch (eDataType)
4616
0
                    {
4617
0
                        case GDT_UInt8:
4618
0
                        {
4619
0
                            if (bSignedByte)
4620
0
                                dfValue =
4621
0
                                    static_cast<signed char *>(pData)[iOffset];
4622
0
                            else
4623
0
                                dfValue = static_cast<GByte *>(pData)[iOffset];
4624
0
                            break;
4625
0
                        }
4626
0
                        case GDT_Int8:
4627
0
                            dfValue = static_cast<GInt8 *>(pData)[iOffset];
4628
0
                            break;
4629
0
                        case GDT_UInt16:
4630
0
                            dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4631
0
                            break;
4632
0
                        case GDT_Int16:
4633
0
                            dfValue = static_cast<GInt16 *>(pData)[iOffset];
4634
0
                            break;
4635
0
                        case GDT_UInt32:
4636
0
                            dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4637
0
                            break;
4638
0
                        case GDT_Int32:
4639
0
                            dfValue = static_cast<GInt32 *>(pData)[iOffset];
4640
0
                            break;
4641
0
                        case GDT_UInt64:
4642
0
                            dfValue = static_cast<double>(
4643
0
                                static_cast<GUInt64 *>(pData)[iOffset]);
4644
0
                            break;
4645
0
                        case GDT_Int64:
4646
0
                            dfValue = static_cast<double>(
4647
0
                                static_cast<GInt64 *>(pData)[iOffset]);
4648
0
                            break;
4649
0
                        case GDT_Float16:
4650
0
                        {
4651
0
                            using namespace std;
4652
0
                            const GFloat16 hfValue =
4653
0
                                static_cast<GFloat16 *>(pData)[iOffset];
4654
0
                            if (isnan(hfValue) ||
4655
0
                                (sNoDataValues.bGotFloat16NoDataValue &&
4656
0
                                 ARE_REAL_EQUAL(hfValue,
4657
0
                                                sNoDataValues.hfNoDataValue)))
4658
0
                                continue;
4659
0
                            dfValue = hfValue;
4660
0
                            break;
4661
0
                        }
4662
0
                        case GDT_Float32:
4663
0
                        {
4664
0
                            const float fValue =
4665
0
                                static_cast<float *>(pData)[iOffset];
4666
0
                            if (std::isnan(fValue) ||
4667
0
                                (sNoDataValues.bGotFloatNoDataValue &&
4668
0
                                 ARE_REAL_EQUAL(fValue,
4669
0
                                                sNoDataValues.fNoDataValue)))
4670
0
                                continue;
4671
0
                            dfValue = double(fValue);
4672
0
                            break;
4673
0
                        }
4674
0
                        case GDT_Float64:
4675
0
                            dfValue = static_cast<double *>(pData)[iOffset];
4676
0
                            if (std::isnan(dfValue))
4677
0
                                continue;
4678
0
                            break;
4679
0
                        case GDT_CInt16:
4680
0
                        {
4681
0
                            double dfReal =
4682
0
                                static_cast<GInt16 *>(pData)[iOffset * 2];
4683
0
                            double dfImag =
4684
0
                                static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4685
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686
0
                            break;
4687
0
                        }
4688
0
                        case GDT_CInt32:
4689
0
                        {
4690
0
                            double dfReal =
4691
0
                                static_cast<GInt32 *>(pData)[iOffset * 2];
4692
0
                            double dfImag =
4693
0
                                static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4694
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4695
0
                            break;
4696
0
                        }
4697
0
                        case GDT_CFloat16:
4698
0
                        {
4699
0
                            double dfReal =
4700
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2];
4701
0
                            double dfImag =
4702
0
                                static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4703
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4704
0
                                continue;
4705
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4706
0
                            break;
4707
0
                        }
4708
0
                        case GDT_CFloat32:
4709
0
                        {
4710
0
                            double dfReal = double(
4711
0
                                static_cast<float *>(pData)[iOffset * 2]);
4712
0
                            double dfImag = double(
4713
0
                                static_cast<float *>(pData)[iOffset * 2 + 1]);
4714
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4715
0
                                continue;
4716
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4717
0
                            break;
4718
0
                        }
4719
0
                        case GDT_CFloat64:
4720
0
                        {
4721
0
                            double dfReal =
4722
0
                                static_cast<double *>(pData)[iOffset * 2];
4723
0
                            double dfImag =
4724
0
                                static_cast<double *>(pData)[iOffset * 2 + 1];
4725
0
                            if (std::isnan(dfReal) || std::isnan(dfImag))
4726
0
                                continue;
4727
0
                            dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4728
0
                            break;
4729
0
                        }
4730
0
                        case GDT_Unknown:
4731
0
                        case GDT_TypeCount:
4732
0
                            CPLAssert(false);
4733
0
                            CPLFree(pabyMaskData);
4734
0
                            return CE_Failure;
4735
0
                    }
4736
4737
0
                    if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4738
0
                        sNoDataValues.bGotNoDataValue &&
4739
0
                        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4740
0
                        continue;
4741
4742
                    // Given that dfValue and dfMin are not NaN, and dfScale > 0
4743
                    // and finite, the result of the multiplication cannot be
4744
                    // NaN
4745
0
                    const double dfIndex = floor((dfValue - dfMin) * dfScale);
4746
4747
0
                    if (dfIndex < 0)
4748
0
                    {
4749
0
                        if (bIncludeOutOfRange)
4750
0
                            panHistogram[0]++;
4751
0
                    }
4752
0
                    else if (dfIndex >= nBuckets)
4753
0
                    {
4754
0
                        if (bIncludeOutOfRange)
4755
0
                            ++panHistogram[nBuckets - 1];
4756
0
                    }
4757
0
                    else
4758
0
                    {
4759
0
                        ++panHistogram[static_cast<int>(dfIndex)];
4760
0
                    }
4761
0
                }
4762
0
            }
4763
4764
0
            poBlock->DropLock();
4765
0
        }
4766
4767
0
        CPLFree(pabyMaskData);
4768
0
    }
4769
4770
0
    pfnProgress(1.0, "Compute Histogram", pProgressData);
4771
4772
0
    return CE_None;
4773
0
}
4774
4775
/************************************************************************/
4776
/*                       GDALGetRasterHistogram()                       */
4777
/************************************************************************/
4778
4779
/**
4780
 * \brief Compute raster histogram.
4781
 *
4782
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4783
 * exceeding 2 billion.
4784
 *
4785
 * @see GDALRasterBand::GetHistogram()
4786
 * @see GDALGetRasterHistogramEx()
4787
 */
4788
4789
CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4790
                                          double dfMax, int nBuckets,
4791
                                          int *panHistogram,
4792
                                          int bIncludeOutOfRange, int bApproxOK,
4793
                                          GDALProgressFunc pfnProgress,
4794
                                          void *pProgressData)
4795
4796
0
{
4797
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4798
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4799
4800
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4801
4802
0
    GUIntBig *panHistogramTemp =
4803
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4804
0
    if (panHistogramTemp == nullptr)
4805
0
    {
4806
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4807
0
                            "Out of memory in GDALGetRasterHistogram().");
4808
0
        return CE_Failure;
4809
0
    }
4810
4811
0
    CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4812
0
                                       bIncludeOutOfRange, bApproxOK,
4813
0
                                       pfnProgress, pProgressData);
4814
4815
0
    if (eErr == CE_None)
4816
0
    {
4817
0
        for (int i = 0; i < nBuckets; i++)
4818
0
        {
4819
0
            if (panHistogramTemp[i] > INT_MAX)
4820
0
            {
4821
0
                CPLError(CE_Warning, CPLE_AppDefined,
4822
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
4823
0
                         " exceeds maximum 32 bit value",
4824
0
                         i, panHistogramTemp[i]);
4825
0
                panHistogram[i] = INT_MAX;
4826
0
            }
4827
0
            else
4828
0
            {
4829
0
                panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4830
0
            }
4831
0
        }
4832
0
    }
4833
4834
0
    CPLFree(panHistogramTemp);
4835
4836
0
    return eErr;
4837
0
}
4838
4839
/************************************************************************/
4840
/*                      GDALGetRasterHistogramEx()                      */
4841
/************************************************************************/
4842
4843
/**
4844
 * \brief Compute raster histogram.
4845
 *
4846
 * @see GDALRasterBand::GetHistogram()
4847
 *
4848
 */
4849
4850
CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4851
    GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4852
    GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4853
    GDALProgressFunc pfnProgress, void *pProgressData)
4854
4855
0
{
4856
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4857
0
    VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4858
4859
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4860
4861
0
    return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4862
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
4863
0
                                pProgressData);
4864
0
}
4865
4866
/************************************************************************/
4867
/*                        GetDefaultHistogram()                         */
4868
/************************************************************************/
4869
4870
/**
4871
 * \brief Fetch default raster histogram.
4872
 *
4873
 * The default method in GDALRasterBand will compute a default histogram. This
4874
 * method is overridden by derived classes (such as GDALPamRasterBand,
4875
 * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4876
 * stored histogram.
4877
 *
4878
 * This method is the same as the C functions GDALGetDefaultHistogram() and
4879
 * GDALGetDefaultHistogramEx().
4880
 *
4881
 * @param pdfMin pointer to double value that will contain the lower bound of
4882
 * the histogram.
4883
 * @param pdfMax pointer to double value that will contain the upper bound of
4884
 * the histogram.
4885
 * @param pnBuckets pointer to int value that will contain the number of buckets
4886
 * in *ppanHistogram.
4887
 * @param ppanHistogram pointer to array into which the histogram totals are
4888
 * placed. To be freed with VSIFree
4889
 * @param bForce TRUE to force the computation. If FALSE and no default
4890
 * histogram is available, the method will return CE_Warning
4891
 * @param pfnProgress function to report progress to completion.
4892
 * @param pProgressData application data to pass to pfnProgress.
4893
 *
4894
 * @return CE_None on success, CE_Failure if something goes wrong, or
4895
 * CE_Warning if no default histogram is available.
4896
 */
4897
4898
CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4899
                                           int *pnBuckets,
4900
                                           GUIntBig **ppanHistogram, int bForce,
4901
                                           GDALProgressFunc pfnProgress,
4902
                                           void *pProgressData)
4903
4904
0
{
4905
0
    CPLAssert(nullptr != pnBuckets);
4906
0
    CPLAssert(nullptr != ppanHistogram);
4907
0
    CPLAssert(nullptr != pdfMin);
4908
0
    CPLAssert(nullptr != pdfMax);
4909
4910
0
    *pnBuckets = 0;
4911
0
    *ppanHistogram = nullptr;
4912
4913
0
    if (!bForce)
4914
0
        return CE_Warning;
4915
4916
0
    int nBuckets = 256;
4917
4918
0
    bool bSignedByte = false;
4919
0
    if (eDataType == GDT_UInt8)
4920
0
    {
4921
0
        EnablePixelTypeSignedByteWarning(false);
4922
0
        const char *pszPixelType =
4923
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4924
0
        EnablePixelTypeSignedByteWarning(true);
4925
0
        bSignedByte =
4926
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4927
0
    }
4928
4929
0
    if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4930
0
    {
4931
0
        *pdfMin = -0.5;
4932
0
        *pdfMax = 255.5;
4933
0
    }
4934
0
    else if (GetRasterDataType() == GDT_Int8)
4935
0
    {
4936
0
        *pdfMin = -128 - 0.5;
4937
0
        *pdfMax = 127 + 0.5;
4938
0
    }
4939
0
    else
4940
0
    {
4941
4942
0
        const CPLErr eErr =
4943
0
            GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4944
0
        if (eErr != CE_None)
4945
0
            return eErr;
4946
0
        if (*pdfMin == *pdfMax)
4947
0
        {
4948
0
            nBuckets = 1;
4949
0
            *pdfMin -= 0.5;
4950
0
            *pdfMax += 0.5;
4951
0
        }
4952
0
        else
4953
0
        {
4954
0
            const double dfHalfBucket =
4955
0
                (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4956
0
            *pdfMin -= dfHalfBucket;
4957
0
            *pdfMax += dfHalfBucket;
4958
0
        }
4959
0
    }
4960
4961
0
    *ppanHistogram =
4962
0
        static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4963
0
    if (*ppanHistogram == nullptr)
4964
0
    {
4965
0
        ReportError(CE_Failure, CPLE_OutOfMemory,
4966
0
                    "Out of memory in GetDefaultHistogram().");
4967
0
        return CE_Failure;
4968
0
    }
4969
4970
0
    *pnBuckets = nBuckets;
4971
0
    CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4972
0
                               TRUE, FALSE, pfnProgress, pProgressData);
4973
0
    if (eErr != CE_None)
4974
0
    {
4975
0
        *pnBuckets = 0;
4976
0
    }
4977
0
    return eErr;
4978
0
}
4979
4980
/************************************************************************/
4981
/*                      GDALGetDefaultHistogram()                       */
4982
/************************************************************************/
4983
4984
/**
4985
 * \brief Fetch default raster histogram.
4986
 *
4987
 * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4988
 * exceeding 2 billion.
4989
 *
4990
 * @see GDALRasterBand::GDALGetDefaultHistogram()
4991
 * @see GDALGetRasterHistogramEx()
4992
 */
4993
4994
CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4995
                                           double *pdfMin, double *pdfMax,
4996
                                           int *pnBuckets, int **ppanHistogram,
4997
                                           int bForce,
4998
                                           GDALProgressFunc pfnProgress,
4999
                                           void *pProgressData)
5000
5001
0
{
5002
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5003
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5004
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5005
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5006
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5007
5008
0
    GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5009
0
    GUIntBig *panHistogramTemp = nullptr;
5010
0
    CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5011
0
                                              &panHistogramTemp, bForce,
5012
0
                                              pfnProgress, pProgressData);
5013
0
    if (eErr == CE_None)
5014
0
    {
5015
0
        const int nBuckets = *pnBuckets;
5016
0
        *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5017
0
        if (*ppanHistogram == nullptr)
5018
0
        {
5019
0
            poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5020
0
                                "Out of memory in GDALGetDefaultHistogram().");
5021
0
            VSIFree(panHistogramTemp);
5022
0
            return CE_Failure;
5023
0
        }
5024
5025
0
        for (int i = 0; i < nBuckets; ++i)
5026
0
        {
5027
0
            if (panHistogramTemp[i] > INT_MAX)
5028
0
            {
5029
0
                CPLError(CE_Warning, CPLE_AppDefined,
5030
0
                         "Count for bucket %d, which is " CPL_FRMT_GUIB
5031
0
                         " exceeds maximum 32 bit value",
5032
0
                         i, panHistogramTemp[i]);
5033
0
                (*ppanHistogram)[i] = INT_MAX;
5034
0
            }
5035
0
            else
5036
0
            {
5037
0
                (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5038
0
            }
5039
0
        }
5040
5041
0
        CPLFree(panHistogramTemp);
5042
0
    }
5043
0
    else
5044
0
    {
5045
0
        *ppanHistogram = nullptr;
5046
0
    }
5047
5048
0
    return eErr;
5049
0
}
5050
5051
/************************************************************************/
5052
/*                      GDALGetDefaultHistogramEx()                     */
5053
/************************************************************************/
5054
5055
/**
5056
 * \brief Fetch default raster histogram.
5057
 *
5058
 * @see GDALRasterBand::GetDefaultHistogram()
5059
 *
5060
 */
5061
5062
CPLErr CPL_STDCALL
5063
GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5064
                          int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5065
                          GDALProgressFunc pfnProgress, void *pProgressData)
5066
5067
0
{
5068
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5069
0
    VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5070
0
    VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5071
0
    VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5072
0
    VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5073
5074
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5075
0
    return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5076
0
                                       bForce, pfnProgress, pProgressData);
5077
0
}
5078
5079
/************************************************************************/
5080
/*                             AdviseRead()                             */
5081
/************************************************************************/
5082
5083
/**
5084
 * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5085
 * \brief Advise driver of upcoming read requests.
5086
 *
5087
 * Some GDAL drivers operate more efficiently if they know in advance what
5088
 * set of upcoming read requests will be made.  The AdviseRead() method allows
5089
 * an application to notify the driver of the region of interest,
5090
 * and at what resolution the region will be read.
5091
 *
5092
 * Many drivers just ignore the AdviseRead() call, but it can dramatically
5093
 * accelerate access via some drivers.
5094
 *
5095
 * Depending on call paths, drivers might receive several calls to
5096
 * AdviseRead() with the same parameters.
5097
 *
5098
 * @param nXOff The pixel offset to the top left corner of the region
5099
 * of the band to be accessed.  This would be zero to start from the left side.
5100
 *
5101
 * @param nYOff The line offset to the top left corner of the region
5102
 * of the band to be accessed.  This would be zero to start from the top.
5103
 *
5104
 * @param nXSize The width of the region of the band to be accessed in pixels.
5105
 *
5106
 * @param nYSize The height of the region of the band to be accessed in lines.
5107
 *
5108
 * @param nBufXSize the width of the buffer image into which the desired region
5109
 * is to be read, or from which it is to be written.
5110
 *
5111
 * @param nBufYSize the height of the buffer image into which the desired
5112
 * region is to be read, or from which it is to be written.
5113
 *
5114
 * @param eBufType the type of the pixel values in the pData data buffer.  The
5115
 * pixel values will automatically be translated to/from the GDALRasterBand
5116
 * data type as needed.
5117
 *
5118
 * @param papszOptions a list of name=value strings with special control
5119
 * options.  Normally this is NULL.
5120
 *
5121
 * @return CE_Failure if the request is invalid and CE_None if it works or
5122
 * is ignored.
5123
 */
5124
5125
/**/
5126
/**/
5127
5128
CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5129
                                  int /*nYSize*/, int /*nBufXSize*/,
5130
                                  int /*nBufYSize*/, GDALDataType /*eBufType*/,
5131
                                  char ** /*papszOptions*/)
5132
0
{
5133
0
    return CE_None;
5134
0
}
5135
5136
/************************************************************************/
5137
/*                        GDALRasterAdviseRead()                        */
5138
/************************************************************************/
5139
5140
/**
5141
 * \brief Advise driver of upcoming read requests.
5142
 *
5143
 * @see GDALRasterBand::AdviseRead()
5144
 */
5145
5146
CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5147
                                        int nYOff, int nXSize, int nYSize,
5148
                                        int nBufXSize, int nBufYSize,
5149
                                        GDALDataType eDT,
5150
                                        CSLConstList papszOptions)
5151
5152
0
{
5153
0
    VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5154
5155
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5156
0
    return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5157
0
                              nBufYSize, eDT,
5158
0
                              const_cast<char **>(papszOptions));
5159
0
}
5160
5161
/************************************************************************/
5162
/*                           GetStatistics()                            */
5163
/************************************************************************/
5164
5165
/**
5166
 * \brief Fetch image statistics.
5167
 *
5168
 * Returns the minimum, maximum, mean and standard deviation of all
5169
 * pixel values in this band.  If approximate statistics are sufficient,
5170
 * the bApproxOK flag can be set to true in which case overviews, or a
5171
 * subset of image tiles may be used in computing the statistics.
5172
 *
5173
 * If bForce is FALSE results will only be returned if it can be done
5174
 * quickly (i.e. without scanning the image, typically by using pre-existing
5175
 * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5176
 * returned efficiently, the method will return CE_Warning but no warning will
5177
 * be issued. This is a non-standard use of the CE_Warning return value
5178
 * to indicate "nothing done".
5179
 *
5180
 * If bForce is TRUE, and results are quickly available without scanning the
5181
 * image, they will be used. If bForce is TRUE and results are not quickly
5182
 * available, GetStatistics() forwards the computation to ComputeStatistics(),
5183
 * which will scan the image.
5184
 *
5185
 * To always force recomputation of statistics, use ComputeStatistics() instead
5186
 * of this method.
5187
 *
5188
 * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5189
 * will generally cache statistics in the .pam file allowing fast fetch
5190
 * after the first request.
5191
 *
5192
 * This method is the same as the C function GDALGetRasterStatistics().
5193
 *
5194
 * @param bApproxOK If TRUE statistics may be computed based on overviews
5195
 * or a subset of all tiles.
5196
 *
5197
 * @param bForce If FALSE statistics will only be returned if it can
5198
 * be done without rescanning the image. If TRUE, statistics computation will
5199
 * be forced if pre-existing values are not quickly available.
5200
 *
5201
 * @param pdfMin Location into which to load image minimum (may be NULL).
5202
 *
5203
 * @param pdfMax Location into which to load image maximum (may be NULL).-
5204
 *
5205
 * @param pdfMean Location into which to load image mean (may be NULL).
5206
 *
5207
 * @param pdfStdDev Location into which to load image standard deviation
5208
 * (may be NULL).
5209
 *
5210
 * @return CE_None on success, CE_Warning if no values returned,
5211
 * CE_Failure if an error occurs.
5212
 */
5213
5214
CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5215
                                     double *pdfMax, double *pdfMean,
5216
                                     double *pdfStdDev)
5217
5218
0
{
5219
    /* -------------------------------------------------------------------- */
5220
    /*      Do we already have metadata items for the requested values?     */
5221
    /* -------------------------------------------------------------------- */
5222
0
    if ((pdfMin == nullptr ||
5223
0
         GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5224
0
        (pdfMax == nullptr ||
5225
0
         GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5226
0
        (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5227
0
        (pdfStdDev == nullptr ||
5228
0
         GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5229
0
    {
5230
0
        if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5231
0
        {
5232
0
            if (pdfMin != nullptr)
5233
0
                *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5234
0
            if (pdfMax != nullptr)
5235
0
                *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5236
0
            if (pdfMean != nullptr)
5237
0
                *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5238
0
            if (pdfStdDev != nullptr)
5239
0
                *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5240
5241
0
            return CE_None;
5242
0
        }
5243
0
    }
5244
5245
    /* -------------------------------------------------------------------- */
5246
    /*      Does the driver already know the min/max?                       */
5247
    /* -------------------------------------------------------------------- */
5248
0
    if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5249
0
    {
5250
0
        int bSuccessMin = FALSE;
5251
0
        int bSuccessMax = FALSE;
5252
5253
0
        const double dfMin = GetMinimum(&bSuccessMin);
5254
0
        const double dfMax = GetMaximum(&bSuccessMax);
5255
5256
0
        if (bSuccessMin && bSuccessMax)
5257
0
        {
5258
0
            if (pdfMin != nullptr)
5259
0
                *pdfMin = dfMin;
5260
0
            if (pdfMax != nullptr)
5261
0
                *pdfMax = dfMax;
5262
0
            return CE_None;
5263
0
        }
5264
0
    }
5265
5266
    /* -------------------------------------------------------------------- */
5267
    /*      Either return without results, or force computation.            */
5268
    /* -------------------------------------------------------------------- */
5269
0
    if (!bForce)
5270
0
        return CE_Warning;
5271
0
    else
5272
0
        return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5273
0
                                 GDALDummyProgress, nullptr);
5274
0
}
5275
5276
/************************************************************************/
5277
/*                      GDALGetRasterStatistics()                       */
5278
/************************************************************************/
5279
5280
/**
5281
 * \brief Fetch image statistics.
5282
 *
5283
 * @see GDALRasterBand::GetStatistics()
5284
 */
5285
5286
CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5287
                                           int bForce, double *pdfMin,
5288
                                           double *pdfMax, double *pdfMean,
5289
                                           double *pdfStdDev)
5290
5291
0
{
5292
0
    VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5293
5294
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5295
0
    return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5296
0
                                 pdfStdDev);
5297
0
}
5298
5299
/************************************************************************/
5300
/*                         GDALUInt128                                  */
5301
/************************************************************************/
5302
5303
#ifdef HAVE_UINT128_T
5304
class GDALUInt128
5305
{
5306
    __uint128_t val;
5307
5308
0
    explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5309
0
    {
5310
0
    }
5311
5312
  public:
5313
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5314
0
    {
5315
        // Evaluates to just a single mul on x86_64
5316
0
        return GDALUInt128(static_cast<__uint128_t>(first) * second);
5317
0
    }
5318
5319
    GDALUInt128 operator-(const GDALUInt128 &other) const
5320
0
    {
5321
0
        return GDALUInt128(val - other.val);
5322
0
    }
5323
5324
    operator double() const
5325
0
    {
5326
0
        return static_cast<double>(val);
5327
0
    }
5328
};
5329
#else
5330
5331
#if defined(_MSC_VER) && defined(_M_X64)
5332
#include <intrin.h>
5333
#endif
5334
5335
class GDALUInt128
5336
{
5337
    GUIntBig low, high;
5338
5339
    GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5340
    {
5341
    }
5342
5343
  public:
5344
    static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5345
    {
5346
#if defined(_MSC_VER) && defined(_M_X64)
5347
        GUIntBig highRes;
5348
        GUIntBig lowRes = _umul128(first, second, &highRes);
5349
        return GDALUInt128(lowRes, highRes);
5350
#else
5351
        const GUInt32 firstLow = static_cast<GUInt32>(first);
5352
        const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5353
        const GUInt32 secondLow = static_cast<GUInt32>(second);
5354
        const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5355
        GUIntBig highRes = 0;
5356
        const GUIntBig firstLowSecondHigh =
5357
            static_cast<GUIntBig>(firstLow) * secondHigh;
5358
        const GUIntBig firstHighSecondLow =
5359
            static_cast<GUIntBig>(firstHigh) * secondLow;
5360
        const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5361
        if (middleTerm < firstLowSecondHigh)  // check for overflow
5362
            highRes += static_cast<GUIntBig>(1) << 32;
5363
        const GUIntBig firstLowSecondLow =
5364
            static_cast<GUIntBig>(firstLow) * secondLow;
5365
        GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5366
        if (lowRes < firstLowSecondLow)  // check for overflow
5367
            highRes++;
5368
        highRes +=
5369
            (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5370
        return GDALUInt128(lowRes, highRes);
5371
#endif
5372
    }
5373
5374
    GDALUInt128 operator-(const GDALUInt128 &other) const
5375
    {
5376
        GUIntBig highRes = high - other.high;
5377
        GUIntBig lowRes = low - other.low;
5378
        if (lowRes > low)  // check for underflow
5379
            --highRes;
5380
        return GDALUInt128(lowRes, highRes);
5381
    }
5382
5383
    operator double() const
5384
    {
5385
        const double twoPow64 = 18446744073709551616.0;
5386
        return high * twoPow64 + low;
5387
    }
5388
};
5389
#endif
5390
5391
/************************************************************************/
5392
/*                    ComputeStatisticsInternal()                       */
5393
/************************************************************************/
5394
5395
// Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5396
// not needed.
5397
0
#define static_cast_for_coverity_scan static_cast
5398
5399
// The rationale for below optimizations is detailed in statistics.txt
5400
5401
// Use with T = GByte or GUInt16 only !
5402
template <class T, bool COMPUTE_OTHER_STATS>
5403
struct ComputeStatisticsInternalGeneric
5404
{
5405
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5406
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5407
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5408
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5409
0
    {
5410
0
        static_assert(std::is_same<T, GByte>::value ||
5411
0
                          std::is_same<T, GUInt16>::value,
5412
0
                      "bad type for T");
5413
0
        if (bHasNoData)
5414
0
        {
5415
            // General case
5416
0
            for (int iY = 0; iY < nYCheck; iY++)
5417
0
            {
5418
0
                for (int iX = 0; iX < nXCheck; iX++)
5419
0
                {
5420
0
                    const GPtrDiff_t iOffset =
5421
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5422
0
                    const GUInt32 nValue = pData[iOffset];
5423
0
                    if (nValue == nNoDataValue)
5424
0
                        continue;
5425
0
                    if (nValue < nMin)
5426
0
                        nMin = nValue;
5427
0
                    if (nValue > nMax)
5428
0
                        nMax = nValue;
5429
                    if constexpr (COMPUTE_OTHER_STATS)
5430
0
                    {
5431
0
                        nValidCount++;
5432
0
                        nSum += nValue;
5433
0
                        nSumSquare +=
5434
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5435
0
                            nValue;
5436
0
                    }
5437
0
                }
5438
0
            }
5439
            if constexpr (COMPUTE_OTHER_STATS)
5440
0
            {
5441
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5442
0
            }
5443
0
        }
5444
0
        else if (nMin == std::numeric_limits<T>::lowest() &&
5445
0
                 nMax == std::numeric_limits<T>::max())
5446
0
        {
5447
            if constexpr (COMPUTE_OTHER_STATS)
5448
0
            {
5449
                // Optimization when there is no nodata and we know we have already
5450
                // reached the min and max
5451
0
                for (int iY = 0; iY < nYCheck; iY++)
5452
0
                {
5453
0
                    int iX;
5454
0
                    for (iX = 0; iX + 3 < nXCheck; iX += 4)
5455
0
                    {
5456
0
                        const GPtrDiff_t iOffset =
5457
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458
0
                        const GUIntBig nValue = pData[iOffset];
5459
0
                        const GUIntBig nValue2 = pData[iOffset + 1];
5460
0
                        const GUIntBig nValue3 = pData[iOffset + 2];
5461
0
                        const GUIntBig nValue4 = pData[iOffset + 3];
5462
0
                        nSum += nValue;
5463
0
                        nSumSquare += nValue * nValue;
5464
0
                        nSum += nValue2;
5465
0
                        nSumSquare += nValue2 * nValue2;
5466
0
                        nSum += nValue3;
5467
0
                        nSumSquare += nValue3 * nValue3;
5468
0
                        nSum += nValue4;
5469
0
                        nSumSquare += nValue4 * nValue4;
5470
0
                    }
5471
0
                    for (; iX < nXCheck; ++iX)
5472
0
                    {
5473
0
                        const GPtrDiff_t iOffset =
5474
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5475
0
                        const GUIntBig nValue = pData[iOffset];
5476
0
                        nSum += nValue;
5477
0
                        nSumSquare += nValue * nValue;
5478
0
                    }
5479
0
                }
5480
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5481
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5482
0
            }
5483
0
        }
5484
0
        else
5485
0
        {
5486
0
            for (int iY = 0; iY < nYCheck; iY++)
5487
0
            {
5488
0
                int iX;
5489
0
                for (iX = 0; iX + 1 < nXCheck; iX += 2)
5490
0
                {
5491
0
                    const GPtrDiff_t iOffset =
5492
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493
0
                    const GUInt32 nValue = pData[iOffset];
5494
0
                    const GUInt32 nValue2 = pData[iOffset + 1];
5495
0
                    if (nValue < nValue2)
5496
0
                    {
5497
0
                        if (nValue < nMin)
5498
0
                            nMin = nValue;
5499
0
                        if (nValue2 > nMax)
5500
0
                            nMax = nValue2;
5501
0
                    }
5502
0
                    else
5503
0
                    {
5504
0
                        if (nValue2 < nMin)
5505
0
                            nMin = nValue2;
5506
0
                        if (nValue > nMax)
5507
0
                            nMax = nValue;
5508
0
                    }
5509
                    if constexpr (COMPUTE_OTHER_STATS)
5510
0
                    {
5511
0
                        nSum += nValue;
5512
0
                        nSumSquare +=
5513
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5514
0
                            nValue;
5515
0
                        nSum += nValue2;
5516
0
                        nSumSquare +=
5517
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5518
0
                            nValue2;
5519
0
                    }
5520
0
                }
5521
0
                if (iX < nXCheck)
5522
0
                {
5523
0
                    const GPtrDiff_t iOffset =
5524
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5525
0
                    const GUInt32 nValue = pData[iOffset];
5526
0
                    if (nValue < nMin)
5527
0
                        nMin = nValue;
5528
0
                    if (nValue > nMax)
5529
0
                        nMax = nValue;
5530
0
                    if (COMPUTE_OTHER_STATS)
5531
0
                    {
5532
0
                        nSum += nValue;
5533
0
                        nSumSquare +=
5534
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5535
0
                            nValue;
5536
0
                    }
5537
0
                }
5538
0
            }
5539
            if constexpr (COMPUTE_OTHER_STATS)
5540
0
            {
5541
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5542
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5543
0
            }
5544
0
        }
5545
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&)
5546
};
5547
5548
// Specialization for Byte that is mostly 32 bit friendly as it avoids
5549
// using 64bit accumulators in internal loops. This also slightly helps in
5550
// 64bit mode.
5551
template <bool COMPUTE_OTHER_STATS>
5552
struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5553
{
5554
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5555
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5556
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5557
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5558
0
    {
5559
0
        int nOuterLoops = nXCheck / 65536;
5560
0
        if (nXCheck % 65536)
5561
0
            nOuterLoops++;
5562
5563
0
        if (bHasNoData)
5564
0
        {
5565
            // General case
5566
0
            for (int iY = 0; iY < nYCheck; iY++)
5567
0
            {
5568
0
                int iX = 0;
5569
0
                for (int k = 0; k < nOuterLoops; k++)
5570
0
                {
5571
0
                    int iMax = iX + 65536;
5572
0
                    if (iMax > nXCheck)
5573
0
                        iMax = nXCheck;
5574
0
                    GUInt32 nSum32bit = 0;
5575
0
                    GUInt32 nSumSquare32bit = 0;
5576
0
                    GUInt32 nValidCount32bit = 0;
5577
0
                    GUInt32 nSampleCount32bit = 0;
5578
0
                    for (; iX < iMax; iX++)
5579
0
                    {
5580
0
                        const GPtrDiff_t iOffset =
5581
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5582
0
                        const GUInt32 nValue = pData[iOffset];
5583
5584
0
                        nSampleCount32bit++;
5585
0
                        if (nValue == nNoDataValue)
5586
0
                            continue;
5587
0
                        if (nValue < nMin)
5588
0
                            nMin = nValue;
5589
0
                        if (nValue > nMax)
5590
0
                            nMax = nValue;
5591
                        if constexpr (COMPUTE_OTHER_STATS)
5592
0
                        {
5593
0
                            nValidCount32bit++;
5594
0
                            nSum32bit += nValue;
5595
0
                            nSumSquare32bit += nValue * nValue;
5596
0
                        }
5597
0
                    }
5598
                    if constexpr (COMPUTE_OTHER_STATS)
5599
0
                    {
5600
0
                        nSampleCount += nSampleCount32bit;
5601
0
                        nValidCount += nValidCount32bit;
5602
0
                        nSum += nSum32bit;
5603
0
                        nSumSquare += nSumSquare32bit;
5604
0
                    }
5605
0
                }
5606
0
            }
5607
0
        }
5608
0
        else if (nMin == 0 && nMax == 255)
5609
0
        {
5610
            if constexpr (COMPUTE_OTHER_STATS)
5611
0
            {
5612
                // Optimization when there is no nodata and we know we have already
5613
                // reached the min and max
5614
0
                for (int iY = 0; iY < nYCheck; iY++)
5615
0
                {
5616
0
                    int iX = 0;
5617
0
                    for (int k = 0; k < nOuterLoops; k++)
5618
0
                    {
5619
0
                        int iMax = iX + 65536;
5620
0
                        if (iMax > nXCheck)
5621
0
                            iMax = nXCheck;
5622
0
                        GUInt32 nSum32bit = 0;
5623
0
                        GUInt32 nSumSquare32bit = 0;
5624
0
                        for (; iX + 3 < iMax; iX += 4)
5625
0
                        {
5626
0
                            const GPtrDiff_t iOffset =
5627
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5628
0
                            const GUInt32 nValue = pData[iOffset];
5629
0
                            const GUInt32 nValue2 = pData[iOffset + 1];
5630
0
                            const GUInt32 nValue3 = pData[iOffset + 2];
5631
0
                            const GUInt32 nValue4 = pData[iOffset + 3];
5632
0
                            nSum32bit += nValue;
5633
0
                            nSumSquare32bit += nValue * nValue;
5634
0
                            nSum32bit += nValue2;
5635
0
                            nSumSquare32bit += nValue2 * nValue2;
5636
0
                            nSum32bit += nValue3;
5637
0
                            nSumSquare32bit += nValue3 * nValue3;
5638
0
                            nSum32bit += nValue4;
5639
0
                            nSumSquare32bit += nValue4 * nValue4;
5640
0
                        }
5641
0
                        nSum += nSum32bit;
5642
0
                        nSumSquare += nSumSquare32bit;
5643
0
                    }
5644
0
                    for (; iX < nXCheck; ++iX)
5645
0
                    {
5646
0
                        const GPtrDiff_t iOffset =
5647
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5648
0
                        const GUIntBig nValue = pData[iOffset];
5649
0
                        nSum += nValue;
5650
0
                        nSumSquare += nValue * nValue;
5651
0
                    }
5652
0
                }
5653
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5654
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5655
0
            }
5656
0
        }
5657
0
        else
5658
0
        {
5659
0
            for (int iY = 0; iY < nYCheck; iY++)
5660
0
            {
5661
0
                int iX = 0;
5662
0
                for (int k = 0; k < nOuterLoops; k++)
5663
0
                {
5664
0
                    int iMax = iX + 65536;
5665
0
                    if (iMax > nXCheck)
5666
0
                        iMax = nXCheck;
5667
0
                    GUInt32 nSum32bit = 0;
5668
0
                    GUInt32 nSumSquare32bit = 0;
5669
0
                    for (; iX + 1 < iMax; iX += 2)
5670
0
                    {
5671
0
                        const GPtrDiff_t iOffset =
5672
0
                            iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673
0
                        const GUInt32 nValue = pData[iOffset];
5674
0
                        const GUInt32 nValue2 = pData[iOffset + 1];
5675
0
                        if (nValue < nValue2)
5676
0
                        {
5677
0
                            if (nValue < nMin)
5678
0
                                nMin = nValue;
5679
0
                            if (nValue2 > nMax)
5680
0
                                nMax = nValue2;
5681
0
                        }
5682
0
                        else
5683
0
                        {
5684
0
                            if (nValue2 < nMin)
5685
0
                                nMin = nValue2;
5686
0
                            if (nValue > nMax)
5687
0
                                nMax = nValue;
5688
0
                        }
5689
                        if constexpr (COMPUTE_OTHER_STATS)
5690
0
                        {
5691
0
                            nSum32bit += nValue;
5692
0
                            nSumSquare32bit += nValue * nValue;
5693
0
                            nSum32bit += nValue2;
5694
0
                            nSumSquare32bit += nValue2 * nValue2;
5695
0
                        }
5696
0
                    }
5697
                    if constexpr (COMPUTE_OTHER_STATS)
5698
0
                    {
5699
0
                        nSum += nSum32bit;
5700
0
                        nSumSquare += nSumSquare32bit;
5701
0
                    }
5702
0
                }
5703
0
                if (iX < nXCheck)
5704
0
                {
5705
0
                    const GPtrDiff_t iOffset =
5706
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5707
0
                    const GUInt32 nValue = pData[iOffset];
5708
0
                    if (nValue < nMin)
5709
0
                        nMin = nValue;
5710
0
                    if (nValue > nMax)
5711
0
                        nMax = nValue;
5712
                    if constexpr (COMPUTE_OTHER_STATS)
5713
0
                    {
5714
0
                        nSum += nValue;
5715
0
                        nSumSquare +=
5716
0
                            static_cast_for_coverity_scan<GUIntBig>(nValue) *
5717
0
                            nValue;
5718
0
                    }
5719
0
                }
5720
0
            }
5721
            if constexpr (COMPUTE_OTHER_STATS)
5722
0
            {
5723
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5724
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5725
0
            }
5726
0
        }
5727
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&)
5728
};
5729
5730
template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5731
{
5732
    static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5733
                  bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5734
                  GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5735
                  GUIntBig &nSampleCount, GUIntBig &nValidCount)
5736
    {
5737
        ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5738
            nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5739
            nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5740
    }
5741
};
5742
5743
#if (defined(__x86_64__) || defined(_M_X64)) &&                                \
5744
    (defined(__GNUC__) || defined(_MSC_VER))
5745
5746
#include "gdal_avx2_emulation.hpp"
5747
5748
0
#define ZERO256 GDALmm256_setzero_si256()
5749
5750
template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5751
static void
5752
ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5753
                              // assumed to be aligned on 256 bits
5754
                              const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5755
                              GUIntBig &nSum, GUIntBig &nSumSquare,
5756
                              GUIntBig &nSampleCount, GUIntBig &nValidCount)
5757
0
{
5758
    // 32-byte alignment may not be enforced by linker, so do it at hand
5759
0
    GByte
5760
0
        aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5761
0
    GByte *paby32ByteAligned =
5762
0
        aby32ByteUnaligned +
5763
0
        (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5764
0
    GByte *pabyMin = paby32ByteAligned;
5765
0
    GByte *pabyMax = paby32ByteAligned + 32;
5766
0
    GUInt32 *panSum =
5767
0
        COMPUTE_OTHER_STATS
5768
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5769
0
            : nullptr;
5770
0
    GUInt32 *panSumSquare =
5771
0
        COMPUTE_OTHER_STATS
5772
0
            ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5773
0
            : nullptr;
5774
5775
0
    CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5776
5777
0
    GPtrDiff_t i = 0;
5778
    // Make sure that sumSquare can fit on uint32
5779
    // * 8 since we can hold 8 sums per vector register
5780
0
    const int nMaxIterationsPerInnerLoop =
5781
0
        8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5782
0
    GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5783
0
    if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5784
0
        nOuterLoops++;
5785
5786
0
    GDALm256i ymm_min =
5787
0
        GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5788
0
    GDALm256i ymm_max = ymm_min;
5789
0
    [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5790
5791
0
    for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5792
0
    {
5793
0
        const auto iMax =
5794
0
            std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5795
5796
        // holds 4 uint32 sums in [0], [2], [4] and [6]
5797
0
        [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5798
0
        [[maybe_unused]] GDALm256i ymm_sumsquare =
5799
0
            ZERO256;  // holds 8 uint32 sums
5800
0
        for (; i + 31 < iMax; i += 32)
5801
0
        {
5802
0
            const GDALm256i ymm = GDALmm256_load_si256(
5803
0
                reinterpret_cast<const GDALm256i *>(pData + i));
5804
0
            if (COMPUTE_MIN)
5805
0
            {
5806
0
                ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5807
0
            }
5808
0
            if (COMPUTE_MAX)
5809
0
            {
5810
0
                ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5811
0
            }
5812
5813
            if constexpr (COMPUTE_OTHER_STATS)
5814
0
            {
5815
                // Extract even-8bit values
5816
0
                const GDALm256i ymm_even =
5817
0
                    GDALmm256_and_si256(ymm, ymm_mask_8bits);
5818
                // Compute square of those 16 values as 32 bit result
5819
                // and add adjacent pairs
5820
0
                const GDALm256i ymm_even_square =
5821
0
                    GDALmm256_madd_epi16(ymm_even, ymm_even);
5822
                // Add to the sumsquare accumulator
5823
0
                ymm_sumsquare =
5824
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5825
5826
                // Extract odd-8bit values
5827
0
                const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5828
0
                const GDALm256i ymm_odd_square =
5829
0
                    GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5830
0
                ymm_sumsquare =
5831
0
                    GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5832
5833
                // Now compute the sums
5834
0
                ymm_sum = GDALmm256_add_epi32(ymm_sum,
5835
0
                                              GDALmm256_sad_epu8(ymm, ZERO256));
5836
0
            }
5837
0
        }
5838
5839
        if constexpr (COMPUTE_OTHER_STATS)
5840
0
        {
5841
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5842
0
                                  ymm_sum);
5843
0
            GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5844
0
                                  ymm_sumsquare);
5845
5846
0
            nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5847
0
            nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5848
0
                          panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5849
0
                          panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5850
0
                          panSumSquare[7];
5851
0
        }
5852
0
    }
5853
5854
    if constexpr (COMPUTE_MIN)
5855
0
    {
5856
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5857
0
    }
5858
    if constexpr (COMPUTE_MAX)
5859
0
    {
5860
0
        GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5861
0
    }
5862
    if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5863
0
    {
5864
0
        for (int j = 0; j < 32; j++)
5865
0
        {
5866
            if constexpr (COMPUTE_MIN)
5867
0
            {
5868
0
                if (pabyMin[j] < nMin)
5869
0
                    nMin = pabyMin[j];
5870
0
            }
5871
            if constexpr (COMPUTE_MAX)
5872
0
            {
5873
0
                if (pabyMax[j] > nMax)
5874
0
                    nMax = pabyMax[j];
5875
0
            }
5876
0
        }
5877
0
    }
5878
5879
0
    for (; i < nBlockPixels; i++)
5880
0
    {
5881
0
        const GUInt32 nValue = pData[i];
5882
        if constexpr (COMPUTE_MIN)
5883
0
        {
5884
0
            if (nValue < nMin)
5885
0
                nMin = nValue;
5886
0
        }
5887
        if constexpr (COMPUTE_MAX)
5888
0
        {
5889
0
            if (nValue > nMax)
5890
0
                nMax = nValue;
5891
0
        }
5892
        if constexpr (COMPUTE_OTHER_STATS)
5893
0
        {
5894
0
            nSum += nValue;
5895
0
            nSumSquare +=
5896
0
                static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5897
0
        }
5898
0
    }
5899
5900
    if constexpr (COMPUTE_OTHER_STATS)
5901
0
    {
5902
0
        nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5903
0
        nValidCount += static_cast<GUIntBig>(nBlockPixels);
5904
0
    }
5905
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&)
5906
5907
// SSE2/AVX2 optimization for GByte case
5908
// In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5909
// penaly in using the emulation, because, given the mm256 intrinsics used here,
5910
// there are strictly equivalent to 2 parallel SSE2 streams.
5911
template <bool COMPUTE_OTHER_STATS>
5912
struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5913
{
5914
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
5915
                  // assumed to be aligned on 256 bits
5916
                  const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5917
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5918
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5919
                  GUIntBig &nValidCount)
5920
0
    {
5921
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5922
0
        if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5923
0
            nMin <= nMax)
5924
0
        {
5925
            // 32-byte alignment may not be enforced by linker, so do it at hand
5926
0
            GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5927
0
            GByte *paby32ByteAligned =
5928
0
                aby32ByteUnaligned +
5929
0
                (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5930
0
            GByte *pabyMin = paby32ByteAligned;
5931
0
            GByte *pabyMax = paby32ByteAligned + 32;
5932
0
            GUInt32 *panSum =
5933
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5934
0
            GUInt32 *panSumSquare =
5935
0
                reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5936
5937
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5938
5939
0
            GPtrDiff_t i = 0;
5940
            // Make sure that sumSquare can fit on uint32
5941
            // * 8 since we can hold 8 sums per vector register
5942
0
            const int nMaxIterationsPerInnerLoop =
5943
0
                8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5944
0
            auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5945
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5946
0
                nOuterLoops++;
5947
5948
0
            const GDALm256i ymm_nodata =
5949
0
                GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5950
            // any non noData value in [min,max] would do.
5951
0
            const GDALm256i ymm_neutral =
5952
0
                GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5953
0
            GDALm256i ymm_min = ymm_neutral;
5954
0
            GDALm256i ymm_max = ymm_neutral;
5955
0
            [[maybe_unused]] const auto ymm_mask_8bits =
5956
0
                GDALmm256_set1_epi16(0xFF);
5957
5958
0
            const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5959
0
            const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5960
0
            const bool bComputeMinMax =
5961
0
                nMin > nMinThreshold || nMax < nMaxThreshold;
5962
5963
0
            for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5964
0
            {
5965
0
                const auto iMax =
5966
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5967
5968
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5969
0
                [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5970
                // holds 8 uint32 sums
5971
0
                [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5972
                // holds 4 uint32 sums in [0], [2], [4] and [6]
5973
0
                [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5974
0
                const auto iInit = i;
5975
0
                for (; i + 31 < iMax; i += 32)
5976
0
                {
5977
0
                    const GDALm256i ymm = GDALmm256_load_si256(
5978
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
5979
5980
                    // Check which values are nodata
5981
0
                    const GDALm256i ymm_eq_nodata =
5982
0
                        GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5983
                    if constexpr (COMPUTE_OTHER_STATS)
5984
0
                    {
5985
                        // Count how many values are nodata (due to cmpeq
5986
                        // putting 255 when condition is met, this will actually
5987
                        // be 255 times the number of nodata value, spread in 4
5988
                        // 64 bits words). We can use add_epi32 as the counter
5989
                        // will not overflow uint32
5990
0
                        ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5991
0
                            ymm_count_nodata_mul_255,
5992
0
                            GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5993
0
                    }
5994
                    // Replace all nodata values by zero for the purpose of sum
5995
                    // and sumquare.
5996
0
                    const GDALm256i ymm_nodata_by_zero =
5997
0
                        GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5998
0
                    if (bComputeMinMax)
5999
0
                    {
6000
                        // Replace all nodata values by a neutral value for the
6001
                        // purpose of min and max.
6002
0
                        const GDALm256i ymm_nodata_by_neutral =
6003
0
                            GDALmm256_or_si256(
6004
0
                                GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6005
0
                                ymm_nodata_by_zero);
6006
6007
0
                        ymm_min =
6008
0
                            GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6009
0
                        ymm_max =
6010
0
                            GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6011
0
                    }
6012
6013
                    if constexpr (COMPUTE_OTHER_STATS)
6014
0
                    {
6015
                        // Extract even-8bit values
6016
0
                        const GDALm256i ymm_even = GDALmm256_and_si256(
6017
0
                            ymm_nodata_by_zero, ymm_mask_8bits);
6018
                        // Compute square of those 16 values as 32 bit result
6019
                        // and add adjacent pairs
6020
0
                        const GDALm256i ymm_even_square =
6021
0
                            GDALmm256_madd_epi16(ymm_even, ymm_even);
6022
                        // Add to the sumsquare accumulator
6023
0
                        ymm_sumsquare =
6024
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6025
6026
                        // Extract odd-8bit values
6027
0
                        const GDALm256i ymm_odd =
6028
0
                            GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6029
0
                        const GDALm256i ymm_odd_square =
6030
0
                            GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6031
0
                        ymm_sumsquare =
6032
0
                            GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6033
6034
                        // Now compute the sums
6035
0
                        ymm_sum = GDALmm256_add_epi32(
6036
0
                            ymm_sum,
6037
0
                            GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6038
0
                    }
6039
0
                }
6040
6041
                if constexpr (COMPUTE_OTHER_STATS)
6042
0
                {
6043
0
                    GUInt32 *panCoutNoDataMul255 = panSum;
6044
0
                    GDALmm256_store_si256(
6045
0
                        reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6046
0
                        ymm_count_nodata_mul_255);
6047
6048
0
                    nSampleCount += (i - iInit);
6049
6050
0
                    nValidCount +=
6051
0
                        (i - iInit) -
6052
0
                        (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6053
0
                         panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6054
0
                            255;
6055
6056
0
                    GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6057
0
                                          ymm_sum);
6058
0
                    GDALmm256_store_si256(
6059
0
                        reinterpret_cast<GDALm256i *>(panSumSquare),
6060
0
                        ymm_sumsquare);
6061
0
                    nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6062
0
                    nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6063
0
                                  panSumSquare[1] + panSumSquare[2] +
6064
0
                                  panSumSquare[3] + panSumSquare[4] +
6065
0
                                  panSumSquare[5] + panSumSquare[6] +
6066
0
                                  panSumSquare[7];
6067
0
                }
6068
0
            }
6069
6070
0
            if (bComputeMinMax)
6071
0
            {
6072
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6073
0
                                      ymm_min);
6074
0
                GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6075
0
                                      ymm_max);
6076
0
                for (int j = 0; j < 32; j++)
6077
0
                {
6078
0
                    if (pabyMin[j] < nMin)
6079
0
                        nMin = pabyMin[j];
6080
0
                    if (pabyMax[j] > nMax)
6081
0
                        nMax = pabyMax[j];
6082
0
                }
6083
0
            }
6084
6085
            if constexpr (COMPUTE_OTHER_STATS)
6086
0
            {
6087
0
                nSampleCount += nBlockPixels - i;
6088
0
            }
6089
0
            for (; i < nBlockPixels; i++)
6090
0
            {
6091
0
                const GUInt32 nValue = pData[i];
6092
0
                if (nValue == nNoDataValue)
6093
0
                    continue;
6094
0
                if (nValue < nMin)
6095
0
                    nMin = nValue;
6096
0
                if (nValue > nMax)
6097
0
                    nMax = nValue;
6098
                if constexpr (COMPUTE_OTHER_STATS)
6099
0
                {
6100
0
                    nValidCount++;
6101
0
                    nSum += nValue;
6102
0
                    nSumSquare +=
6103
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6104
0
                        nValue;
6105
0
                }
6106
0
            }
6107
0
        }
6108
0
        else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6109
0
        {
6110
0
            if (nMin > 0)
6111
0
            {
6112
0
                if (nMax < 255)
6113
0
                {
6114
0
                    ComputeStatisticsByteNoNodata<true, true,
6115
0
                                                  COMPUTE_OTHER_STATS>(
6116
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6117
0
                        nSampleCount, nValidCount);
6118
0
                }
6119
0
                else
6120
0
                {
6121
0
                    ComputeStatisticsByteNoNodata<true, false,
6122
0
                                                  COMPUTE_OTHER_STATS>(
6123
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6124
0
                        nSampleCount, nValidCount);
6125
0
                }
6126
0
            }
6127
0
            else
6128
0
            {
6129
0
                if (nMax < 255)
6130
0
                {
6131
0
                    ComputeStatisticsByteNoNodata<false, true,
6132
0
                                                  COMPUTE_OTHER_STATS>(
6133
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6134
0
                        nSampleCount, nValidCount);
6135
0
                }
6136
0
                else
6137
0
                {
6138
0
                    ComputeStatisticsByteNoNodata<false, false,
6139
0
                                                  COMPUTE_OTHER_STATS>(
6140
0
                        nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6141
0
                        nSampleCount, nValidCount);
6142
0
                }
6143
0
            }
6144
0
        }
6145
0
        else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6146
0
                 (nBlockXSize % 32) == 0)
6147
0
        {
6148
0
            for (int iY = 0; iY < nYCheck; iY++)
6149
0
            {
6150
0
                ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6151
0
                    nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6152
0
                    nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6153
0
            }
6154
0
        }
6155
0
        else
6156
0
        {
6157
0
            ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6158
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6159
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6160
0
        }
6161
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&)
6162
};
6163
6164
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6165
static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6166
                             GUIntBig i)
6167
0
{
6168
0
    nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6169
0
}
6170
6171
// AVX2/SSE2 optimization for GUInt16 case
6172
template <bool COMPUTE_OTHER_STATS>
6173
struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6174
{
6175
    static void f(int nXCheck, int nBlockXSize, int nYCheck,
6176
                  // assumed to be aligned on 128 bits
6177
                  const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6178
                  GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6179
                  GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6180
                  GUIntBig &nValidCount)
6181
0
    {
6182
0
        const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6183
0
        if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6184
0
        {
6185
0
            CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6186
6187
0
            GPtrDiff_t i = 0;
6188
            // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6189
            // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6190
            // Furthermore the shift is also needed to use madd_epi16
6191
0
            const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6192
0
            GDALm256i ymm_min = GDALmm256_load_si256(
6193
0
                reinterpret_cast<const GDALm256i *>(pData + i));
6194
0
            ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6195
0
            GDALm256i ymm_max = ymm_min;
6196
0
            [[maybe_unused]] GDALm256i ymm_sumsquare =
6197
0
                ZERO256;  // holds 4 uint64 sums
6198
6199
            // Make sure that sum can fit on uint32
6200
            // * 8 since we can hold 8 sums per vector register
6201
0
            const int nMaxIterationsPerInnerLoop =
6202
0
                8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6203
0
            GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6204
0
            if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6205
0
                nOuterLoops++;
6206
6207
0
            const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6208
0
            [[maybe_unused]] const auto ymm_mask_16bits =
6209
0
                GDALmm256_set1_epi32(0xFFFF);
6210
0
            [[maybe_unused]] const auto ymm_mask_32bits =
6211
0
                GDALmm256_set1_epi64x(0xFFFFFFFF);
6212
6213
0
            GUIntBig nSumThis = 0;
6214
0
            for (int k = 0; k < nOuterLoops; k++)
6215
0
            {
6216
0
                const auto iMax =
6217
0
                    std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6218
6219
0
                [[maybe_unused]] GDALm256i ymm_sum =
6220
0
                    ZERO256;  // holds 8 uint32 sums
6221
0
                for (; i + 15 < iMax; i += 16)
6222
0
                {
6223
0
                    const GDALm256i ymm = GDALmm256_load_si256(
6224
0
                        reinterpret_cast<const GDALm256i *>(pData + i));
6225
0
                    const GDALm256i ymm_shifted =
6226
0
                        GDALmm256_add_epi16(ymm, ymm_m32768);
6227
0
                    if (bComputeMinMax)
6228
0
                    {
6229
0
                        ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6230
0
                        ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6231
0
                    }
6232
6233
                    if constexpr (COMPUTE_OTHER_STATS)
6234
0
                    {
6235
                        // Note: the int32 range can overflow for (0-32768)^2 +
6236
                        // (0-32768)^2 = 0x80000000, but as we know the result
6237
                        // is positive, this is OK as we interpret is a uint32.
6238
0
                        const GDALm256i ymm_square =
6239
0
                            GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6240
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6241
0
                            ymm_sumsquare,
6242
0
                            GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6243
0
                        ymm_sumsquare = GDALmm256_add_epi64(
6244
0
                            ymm_sumsquare,
6245
0
                            GDALmm256_srli_epi64(ymm_square, 32));
6246
6247
                        // Now compute the sums
6248
0
                        ymm_sum = GDALmm256_add_epi32(
6249
0
                            ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6250
0
                        ymm_sum = GDALmm256_add_epi32(
6251
0
                            ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6252
0
                    }
6253
0
                }
6254
6255
                if constexpr (COMPUTE_OTHER_STATS)
6256
0
                {
6257
0
                    GUInt32 anSum[8];
6258
0
                    GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6259
0
                                           ymm_sum);
6260
0
                    nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6261
0
                                anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6262
0
                                anSum[6] + anSum[7];
6263
0
                }
6264
0
            }
6265
6266
0
            if (bComputeMinMax)
6267
0
            {
6268
0
                GUInt16 anMin[16];
6269
0
                GUInt16 anMax[16];
6270
6271
                // Unshift the result
6272
0
                ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6273
0
                ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6274
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6275
0
                                       ymm_min);
6276
0
                GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6277
0
                                       ymm_max);
6278
0
                for (int j = 0; j < 16; j++)
6279
0
                {
6280
0
                    if (anMin[j] < nMin)
6281
0
                        nMin = anMin[j];
6282
0
                    if (anMax[j] > nMax)
6283
0
                        nMax = anMax[j];
6284
0
                }
6285
0
            }
6286
6287
            if constexpr (COMPUTE_OTHER_STATS)
6288
0
            {
6289
0
                GUIntBig anSumSquare[4];
6290
0
                GDALmm256_storeu_si256(
6291
0
                    reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6292
0
                nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6293
0
                              anSumSquare[3];
6294
6295
                // Unshift the sum of squares
6296
0
                UnshiftSumSquare(nSumSquare, nSumThis,
6297
0
                                 static_cast<GUIntBig>(i));
6298
6299
0
                nSum += nSumThis;
6300
6301
0
                for (; i < nBlockPixels; i++)
6302
0
                {
6303
0
                    const GUInt32 nValue = pData[i];
6304
0
                    if (nValue < nMin)
6305
0
                        nMin = nValue;
6306
0
                    if (nValue > nMax)
6307
0
                        nMax = nValue;
6308
0
                    nSum += nValue;
6309
0
                    nSumSquare +=
6310
0
                        static_cast_for_coverity_scan<GUIntBig>(nValue) *
6311
0
                        nValue;
6312
0
                }
6313
6314
0
                nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6315
0
                nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6316
0
            }
6317
0
        }
6318
0
        else
6319
0
        {
6320
0
            ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6321
0
                nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6322
0
                nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6323
0
        }
6324
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&)
6325
};
6326
6327
#endif
6328
// (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6329
// defined(_MSC_VER))
6330
6331
/************************************************************************/
6332
/*                          GetPixelValue()                             */
6333
/************************************************************************/
6334
6335
static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6336
                                   const void *pData, GPtrDiff_t iOffset,
6337
                                   const GDALNoDataValues &sNoDataValues,
6338
                                   bool &bValid)
6339
0
{
6340
0
    bValid = true;
6341
0
    double dfValue = 0;
6342
0
    switch (eDataType)
6343
0
    {
6344
0
        case GDT_UInt8:
6345
0
        {
6346
0
            if (bSignedByte)
6347
0
                dfValue = static_cast<const signed char *>(pData)[iOffset];
6348
0
            else
6349
0
                dfValue = static_cast<const GByte *>(pData)[iOffset];
6350
0
            break;
6351
0
        }
6352
0
        case GDT_Int8:
6353
0
            dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6354
0
            break;
6355
0
        case GDT_UInt16:
6356
0
            dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6357
0
            break;
6358
0
        case GDT_Int16:
6359
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6360
0
            break;
6361
0
        case GDT_UInt32:
6362
0
            dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6363
0
            break;
6364
0
        case GDT_Int32:
6365
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6366
0
            break;
6367
0
        case GDT_UInt64:
6368
0
            dfValue = static_cast<double>(
6369
0
                static_cast<const std::uint64_t *>(pData)[iOffset]);
6370
0
            break;
6371
0
        case GDT_Int64:
6372
0
            dfValue = static_cast<double>(
6373
0
                static_cast<const std::int64_t *>(pData)[iOffset]);
6374
0
            break;
6375
0
        case GDT_Float16:
6376
0
        {
6377
0
            using namespace std;
6378
0
            const GFloat16 hfValue =
6379
0
                static_cast<const GFloat16 *>(pData)[iOffset];
6380
0
            if (isnan(hfValue) ||
6381
0
                (sNoDataValues.bGotFloat16NoDataValue &&
6382
0
                 ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6383
0
            {
6384
0
                bValid = false;
6385
0
                return 0.0;
6386
0
            }
6387
0
            dfValue = hfValue;
6388
0
            return dfValue;
6389
0
        }
6390
0
        case GDT_Float32:
6391
0
        {
6392
0
            const float fValue = static_cast<const float *>(pData)[iOffset];
6393
0
            if (std::isnan(fValue) ||
6394
0
                (sNoDataValues.bGotFloatNoDataValue &&
6395
0
                 ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6396
0
            {
6397
0
                bValid = false;
6398
0
                return 0.0;
6399
0
            }
6400
0
            dfValue = double(fValue);
6401
0
            return dfValue;
6402
0
        }
6403
0
        case GDT_Float64:
6404
0
            dfValue = static_cast<const double *>(pData)[iOffset];
6405
0
            if (std::isnan(dfValue))
6406
0
            {
6407
0
                bValid = false;
6408
0
                return 0.0;
6409
0
            }
6410
0
            break;
6411
0
        case GDT_CInt16:
6412
0
            dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6413
0
            break;
6414
0
        case GDT_CInt32:
6415
0
            dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6416
0
            break;
6417
0
        case GDT_CFloat16:
6418
0
            dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6419
0
            if (std::isnan(dfValue))
6420
0
            {
6421
0
                bValid = false;
6422
0
                return 0.0;
6423
0
            }
6424
0
            break;
6425
0
        case GDT_CFloat32:
6426
0
            dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6427
0
            if (std::isnan(dfValue))
6428
0
            {
6429
0
                bValid = false;
6430
0
                return 0.0;
6431
0
            }
6432
0
            break;
6433
0
        case GDT_CFloat64:
6434
0
            dfValue = static_cast<const double *>(pData)[iOffset * 2];
6435
0
            if (std::isnan(dfValue))
6436
0
            {
6437
0
                bValid = false;
6438
0
                return 0.0;
6439
0
            }
6440
0
            break;
6441
0
        case GDT_Unknown:
6442
0
        case GDT_TypeCount:
6443
0
            CPLAssert(false);
6444
0
            break;
6445
0
    }
6446
6447
0
    if (sNoDataValues.bGotNoDataValue &&
6448
0
        ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6449
0
    {
6450
0
        bValid = false;
6451
0
        return 0.0;
6452
0
    }
6453
0
    return dfValue;
6454
0
}
6455
6456
/************************************************************************/
6457
/*                         SetValidPercent()                            */
6458
/************************************************************************/
6459
6460
//! @cond Doxygen_Suppress
6461
/**
6462
 * \brief Set percentage of valid (not nodata) pixels.
6463
 *
6464
 * Stores the percentage of valid pixels in the metadata item
6465
 * STATISTICS_VALID_PERCENT
6466
 *
6467
 * @param nSampleCount Number of sampled pixels.
6468
 *
6469
 * @param nValidCount Number of valid pixels.
6470
 */
6471
6472
void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6473
                                     GUIntBig nValidCount)
6474
0
{
6475
0
    if (nValidCount == 0)
6476
0
    {
6477
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6478
0
    }
6479
0
    else if (nValidCount == nSampleCount)
6480
0
    {
6481
0
        SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6482
0
    }
6483
0
    else /* nValidCount < nSampleCount */
6484
0
    {
6485
0
        char szValue[128] = {0};
6486
6487
        /* percentage is only an indicator: limit precision */
6488
0
        CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6489
0
                    100. * static_cast<double>(nValidCount) / nSampleCount);
6490
6491
0
        if (EQUAL(szValue, "100"))
6492
0
        {
6493
            /* don't set 100 percent valid
6494
             * because some of the sampled pixels were nodata */
6495
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6496
0
        }
6497
0
        else
6498
0
        {
6499
0
            SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6500
0
        }
6501
0
    }
6502
0
}
6503
6504
//! @endcond
6505
6506
#if (defined(__x86_64__) || defined(_M_X64))
6507
6508
#ifdef __AVX2__
6509
6510
#define set1_ps _mm256_set1_ps
6511
#define loadu_ps _mm256_loadu_ps
6512
#define or_ps _mm256_or_ps
6513
#define min_ps _mm256_min_ps
6514
#define max_ps _mm256_max_ps
6515
#define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6516
#define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6517
#define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6518
#define movemask_ps _mm256_movemask_ps
6519
#define storeu_ps _mm256_storeu_ps
6520
#define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6521
#define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6522
6523
#define unpacklo_ps _mm256_unpacklo_ps
6524
#define castps_pd _mm256_castps_pd
6525
6526
inline __m256 dup_hi_ps(__m256 x)
6527
{
6528
    const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6529
    return _mm256_permutevar8x32_ps(x, idx);
6530
}
6531
6532
#define setzero_pd _mm256_setzero_pd
6533
#define set1_pd _mm256_set1_pd
6534
#define loadu_pd _mm256_loadu_pd
6535
#define or_pd _mm256_or_pd
6536
#define min_pd _mm256_min_pd
6537
#define max_pd _mm256_max_pd
6538
#define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6539
#define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6540
#define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6541
#define movemask_pd _mm256_movemask_pd
6542
#define add_pd _mm256_add_pd
6543
#define sub_pd _mm256_sub_pd
6544
#define mul_pd _mm256_mul_pd
6545
#define div_pd _mm256_div_pd
6546
#define storeu_pd _mm256_storeu_pd
6547
#define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6548
#define blendv_pd _mm256_blendv_pd
6549
#ifdef __FMA__
6550
#define fmadd_pd _mm256_fmadd_pd
6551
#else
6552
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6553
#endif
6554
6555
#else
6556
6557
0
#define set1_ps _mm_set1_ps
6558
0
#define loadu_ps _mm_loadu_ps
6559
0
#define or_ps _mm_or_ps
6560
0
#define min_ps _mm_min_ps
6561
0
#define max_ps _mm_max_ps
6562
0
#define cmpeq_ps _mm_cmpeq_ps
6563
0
#define cmpneq_ps _mm_cmpneq_ps
6564
0
#define cmpunord_ps _mm_cmpunord_ps
6565
0
#define movemask_ps _mm_movemask_ps
6566
0
#define storeu_ps _mm_storeu_ps
6567
0
#define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6568
0
#define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6569
0
#define unpacklo_ps _mm_unpacklo_ps
6570
0
#define castps_pd _mm_castps_pd
6571
0
#define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6572
6573
0
#define setzero_pd _mm_setzero_pd
6574
0
#define set1_pd _mm_set1_pd
6575
0
#define loadu_pd _mm_loadu_pd
6576
0
#define or_pd _mm_or_pd
6577
0
#define min_pd _mm_min_pd
6578
0
#define max_pd _mm_max_pd
6579
0
#define cmpeq_pd _mm_cmpeq_pd
6580
0
#define cmpneq_pd _mm_cmpneq_pd
6581
0
#define cmpunord_pd _mm_cmpunord_pd
6582
0
#define movemask_pd _mm_movemask_pd
6583
0
#define add_pd _mm_add_pd
6584
0
#define sub_pd _mm_sub_pd
6585
0
#define mul_pd _mm_mul_pd
6586
0
#define div_pd _mm_div_pd
6587
0
#define storeu_pd _mm_storeu_pd
6588
0
#define cvtsd_f64 _mm_cvtsd_f64
6589
#ifdef __FMA__
6590
#define fmadd_pd _mm_fmadd_pd
6591
#else
6592
0
#define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6593
#endif
6594
6595
inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6596
0
{
6597
#if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6598
    return _mm_blendv_pd(a, b, mask);
6599
#else
6600
0
    return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6601
0
#endif
6602
0
}
6603
#endif
6604
6605
0
#define dup_lo_ps(x) unpacklo_ps((x), (x))
6606
6607
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6608
#if defined(__GNUC__)
6609
__attribute__((noinline))
6610
#endif
6611
static int
6612
ComputeStatisticsFloat32_SSE2(const float *pafData,
6613
                              [[maybe_unused]] float fNoDataValue, int iX,
6614
                              int nCount, float &fMin, float &fMax,
6615
                              double &dfBlockMean, double &dfBlockM2,
6616
                              double &dfBlockValidCount)
6617
0
{
6618
0
    auto vValidCount = setzero_pd();
6619
0
    const auto vOne = set1_pd(1);
6620
0
    [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6621
6622
0
    auto vMin = set1_ps(fMin);
6623
0
    auto vMax = set1_ps(fMax);
6624
6625
0
    auto vMean_lo = setzero_pd();
6626
0
    auto vM2_lo = setzero_pd();
6627
6628
0
    auto vMean_hi = setzero_pd();
6629
0
    auto vM2_hi = setzero_pd();
6630
6631
0
    constexpr int VALS_PER_LOOP =
6632
0
        static_cast<int>(sizeof(vOne) / sizeof(float));
6633
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6634
0
    {
6635
0
        const auto vValues = loadu_ps(pafData + iX);
6636
6637
0
        auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6638
        if constexpr (HAS_NODATA)
6639
0
        {
6640
0
            isNaNOrNoData = or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6641
0
        }
6642
0
        if (movemask_ps(isNaNOrNoData))
6643
0
        {
6644
0
            break;
6645
0
        }
6646
6647
0
        vMin = min_ps(vMin, vValues);
6648
0
        vMax = max_ps(vMax, vValues);
6649
6650
0
        const auto vValues_lo = cvtps_lo_pd(vValues);
6651
0
        const auto vValues_hi = cvtps_hi_pd(vValues);
6652
0
        [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6653
6654
0
        vValidCount = add_pd(vValidCount, vOne);
6655
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6656
6657
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6658
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6659
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6660
0
        {
6661
0
            const auto vMinNotSameAsMax_lo =
6662
0
                castps_pd(dup_lo_ps(vMinNotSameAsMax));
6663
0
            vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6664
0
            const auto vNewM2_lo =
6665
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6666
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6667
        }
6668
        else
6669
0
        {
6670
0
            vMean_lo = vNewMean_lo;
6671
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6672
0
        }
6673
6674
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6675
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6676
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6677
0
        {
6678
0
            const auto vMinNotSameAsMax_hi =
6679
0
                castps_pd(dup_hi_ps(vMinNotSameAsMax));
6680
0
            vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6681
0
            const auto vNewM2_hi =
6682
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6683
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6684
        }
6685
        else
6686
0
        {
6687
0
            vMean_hi = vNewMean_hi;
6688
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6689
0
        }
6690
0
    }
6691
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6692
0
    if (dfValidVectorCount > 0)
6693
0
    {
6694
0
        float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6695
0
        storeu_ps(afMin, vMin);
6696
0
        storeu_ps(afMax, vMax);
6697
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6698
0
        {
6699
0
            fMin = std::min(fMin, afMin[i]);
6700
0
            fMax = std::max(fMax, afMax[i]);
6701
0
        }
6702
6703
0
        double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6704
0
        storeu_pd(adfMean, vMean_lo);
6705
0
        storeu_pd(adfM2, vM2_lo);
6706
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6707
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6708
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6709
0
        {
6710
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6711
0
            dfBlockM2 += adfM2[i];
6712
0
            if (adfMean[i] != dfBlockMean)
6713
0
            {
6714
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6715
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6716
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6717
0
                             dfValidVectorCount / dfNewValidCount;
6718
0
            }
6719
0
            dfBlockValidCount = dfNewValidCount;
6720
0
        }
6721
0
    }
6722
6723
0
    return iX;
6724
0
}
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, true>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<false, false>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, true>(float const*, float, int, int, float&, float&, double&, double&, double&)
Unexecuted instantiation: gdalrasterband.cpp:int ComputeStatisticsFloat32_SSE2<true, false>(float const*, float, int, int, float&, float&, double&, double&, double&)
6725
6726
template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6727
#if defined(__GNUC__)
6728
__attribute__((noinline))
6729
#endif
6730
static int
6731
ComputeStatisticsFloat64_SSE2(const double *padfData,
6732
                              [[maybe_unused]] double dfNoDataValue, int iX,
6733
                              int nCount, double &dfMin, double &dfMax,
6734
                              double &dfBlockMean, double &dfBlockM2,
6735
                              double &dfBlockValidCount)
6736
0
{
6737
0
    auto vValidCount = setzero_pd();
6738
0
    const auto vOne = set1_pd(1);
6739
0
    [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6740
6741
0
    auto vMin_lo = set1_pd(dfMin);
6742
0
    auto vMax_lo = set1_pd(dfMax);
6743
0
    auto vMean_lo = setzero_pd();
6744
0
    auto vM2_lo = setzero_pd();
6745
6746
0
    auto vMin_hi = vMin_lo;
6747
0
    auto vMax_hi = vMax_lo;
6748
0
    auto vMean_hi = setzero_pd();
6749
0
    auto vM2_hi = setzero_pd();
6750
6751
0
    constexpr int VALS_PER_LOOP =
6752
0
        2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6753
0
    for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6754
0
    {
6755
0
        const auto vValues_lo = loadu_pd(padfData + iX);
6756
0
        const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6757
        // Check if there's at least one NaN in both vectors
6758
0
        auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6759
        if constexpr (HAS_NODATA)
6760
0
        {
6761
0
            isNaNOrNoData =
6762
0
                or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6763
0
                                           cmpeq_pd(vValues_hi, vNoData)));
6764
0
        }
6765
0
        if (movemask_pd(isNaNOrNoData))
6766
0
        {
6767
0
            break;
6768
0
        }
6769
6770
0
        vValidCount = add_pd(vValidCount, vOne);
6771
0
        const auto vInvValidCount = div_pd(vOne, vValidCount);
6772
6773
0
        vMin_lo = min_pd(vMin_lo, vValues_lo);
6774
0
        vMax_lo = max_pd(vMax_lo, vValues_lo);
6775
0
        const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6776
0
        const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6777
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6778
0
        {
6779
0
            const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6780
0
            vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6781
0
            const auto vNewM2_lo =
6782
0
                fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6783
0
            vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6784
        }
6785
        else
6786
0
        {
6787
0
            vMean_lo = vNewMean_lo;
6788
0
            vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6789
0
        }
6790
6791
0
        vMin_hi = min_pd(vMin_hi, vValues_hi);
6792
0
        vMax_hi = max_pd(vMax_hi, vValues_hi);
6793
0
        const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6794
0
        const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6795
        if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6796
0
        {
6797
0
            const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6798
0
            vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6799
0
            const auto vNewM2_hi =
6800
0
                fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6801
0
            vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6802
        }
6803
        else
6804
0
        {
6805
0
            vMean_hi = vNewMean_hi;
6806
0
            vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6807
0
        }
6808
0
    }
6809
0
    const double dfValidVectorCount = cvtsd_f64(vValidCount);
6810
0
    if (dfValidVectorCount > 0)
6811
0
    {
6812
0
        double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6813
0
            adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6814
0
        storeu_pd(adfMin, vMin_lo);
6815
0
        storeu_pd(adfMax, vMax_lo);
6816
0
        storeu_pd(adfMean, vMean_lo);
6817
0
        storeu_pd(adfM2, vM2_lo);
6818
0
        storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6819
0
        storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6820
0
        storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6821
0
        storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6822
6823
0
        for (int i = 0; i < VALS_PER_LOOP; ++i)
6824
0
        {
6825
0
            dfMin = std::min(dfMin, adfMin[i]);
6826
0
            dfMax = std::max(dfMax, adfMax[i]);
6827
0
            const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6828
0
            dfBlockM2 += adfM2[i];
6829
0
            if (adfMean[i] != dfBlockMean)
6830
0
            {
6831
0
                const double dfDelta = adfMean[i] - dfBlockMean;
6832
0
                dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6833
0
                dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6834
0
                             dfValidVectorCount / dfNewValidCount;
6835
0
            }
6836
0
            dfBlockValidCount = dfNewValidCount;
6837
0
        }
6838
0
    }
6839
6840
0
    return iX;
6841
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&)
6842
6843
#endif
6844
6845
/************************************************************************/
6846
/*                         ComputeStatistics()                          */
6847
/************************************************************************/
6848
6849
/**
6850
 * \brief Compute image statistics.
6851
 *
6852
 * Returns the minimum, maximum, mean and standard deviation of all
6853
 * pixel values in this band.  If approximate statistics are sufficient,
6854
 * the bApproxOK flag can be set to true in which case overviews, or a
6855
 * subset of image tiles may be used in computing the statistics.
6856
 *
6857
 * Once computed, the statistics will generally be "set" back on the
6858
 * raster band using SetStatistics().
6859
 *
6860
 * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6861
 *
6862
 * This method is the same as the C function GDALComputeRasterStatistics().
6863
 *
6864
 * @param bApproxOK If TRUE statistics may be computed based on overviews
6865
 * or a subset of all tiles.
6866
 *
6867
 * @param pdfMin Location into which to load image minimum (may be NULL).
6868
 *
6869
 * @param pdfMax Location into which to load image maximum (may be NULL).-
6870
 *
6871
 * @param pdfMean Location into which to load image mean (may be NULL).
6872
 *
6873
 * @param pdfStdDev Location into which to load image standard deviation
6874
 * (may be NULL).
6875
 *
6876
 * @param pfnProgress a function to call to report progress, or NULL.
6877
 *
6878
 * @param pProgressData application data to pass to the progress function.
6879
 *
6880
 * @return CE_None on success, or CE_Failure if an error occurs or processing
6881
 * is terminated by the user.
6882
 */
6883
6884
CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6885
                                         double *pdfMax, double *pdfMean,
6886
                                         double *pdfStdDev,
6887
                                         GDALProgressFunc pfnProgress,
6888
                                         void *pProgressData)
6889
6890
0
{
6891
0
    if (pfnProgress == nullptr)
6892
0
        pfnProgress = GDALDummyProgress;
6893
6894
    /* -------------------------------------------------------------------- */
6895
    /*      If we have overview bands, use them for statistics.             */
6896
    /* -------------------------------------------------------------------- */
6897
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6898
0
    {
6899
0
        GDALRasterBand *poBand =
6900
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6901
6902
0
        if (poBand != this)
6903
0
        {
6904
0
            CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6905
0
                                                    pdfMean, pdfStdDev,
6906
0
                                                    pfnProgress, pProgressData);
6907
0
            if (eErr == CE_None)
6908
0
            {
6909
0
                if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6910
0
                {
6911
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6912
0
                    SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6913
0
                }
6914
6915
                /* transfer metadata from overview band to this */
6916
0
                const char *pszPercentValid =
6917
0
                    poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6918
6919
0
                if (pszPercentValid != nullptr)
6920
0
                {
6921
0
                    SetMetadataItem("STATISTICS_VALID_PERCENT",
6922
0
                                    pszPercentValid);
6923
0
                }
6924
0
            }
6925
0
            return eErr;
6926
0
        }
6927
0
    }
6928
6929
0
    if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6930
0
    {
6931
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6932
0
        return CE_Failure;
6933
0
    }
6934
6935
    /* -------------------------------------------------------------------- */
6936
    /*      Read actual data and compute statistics.                        */
6937
    /* -------------------------------------------------------------------- */
6938
    // Using Welford algorithm:
6939
    // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6940
    // to compute standard deviation in a more numerically robust way than
6941
    // the difference of the sum of square values with the square of the sum.
6942
    // dfMean and dfM2 are updated at each sample.
6943
    // dfM2 is the sum of square of differences to the current mean.
6944
0
    double dfMin = std::numeric_limits<double>::infinity();
6945
0
    double dfMax = -std::numeric_limits<double>::infinity();
6946
0
    double dfMean = 0.0;
6947
0
    double dfM2 = 0.0;
6948
6949
0
    GDALRasterIOExtraArg sExtraArg;
6950
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6951
6952
0
    GDALNoDataValues sNoDataValues(this, eDataType);
6953
0
    GDALRasterBand *poMaskBand = nullptr;
6954
0
    if (!sNoDataValues.bGotNoDataValue)
6955
0
    {
6956
0
        const int l_nMaskFlags = GetMaskFlags();
6957
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
6958
0
            GetColorInterpretation() != GCI_AlphaBand)
6959
0
        {
6960
0
            poMaskBand = GetMaskBand();
6961
0
        }
6962
0
    }
6963
6964
0
    bool bSignedByte = false;
6965
0
    if (eDataType == GDT_UInt8)
6966
0
    {
6967
0
        EnablePixelTypeSignedByteWarning(false);
6968
0
        const char *pszPixelType =
6969
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6970
0
        EnablePixelTypeSignedByteWarning(true);
6971
0
        bSignedByte =
6972
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6973
0
    }
6974
6975
0
    GUIntBig nSampleCount = 0;
6976
0
    GUIntBig nValidCount = 0;
6977
6978
0
    if (bApproxOK && HasArbitraryOverviews())
6979
0
    {
6980
        /* --------------------------------------------------------------------
6981
         */
6982
        /*      Figure out how much the image should be reduced to get an */
6983
        /*      approximate value. */
6984
        /* --------------------------------------------------------------------
6985
         */
6986
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6987
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6988
6989
0
        int nXReduced = nRasterXSize;
6990
0
        int nYReduced = nRasterYSize;
6991
0
        if (dfReduction > 1.0)
6992
0
        {
6993
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6994
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6995
6996
            // Catch the case of huge resizing ratios here
6997
0
            if (nXReduced == 0)
6998
0
                nXReduced = 1;
6999
0
            if (nYReduced == 0)
7000
0
                nYReduced = 1;
7001
0
        }
7002
7003
0
        void *pData = CPLMalloc(cpl::fits_on<int>(
7004
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7005
7006
0
        const CPLErr eErr =
7007
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7008
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7009
0
        if (eErr != CE_None)
7010
0
        {
7011
0
            CPLFree(pData);
7012
0
            return eErr;
7013
0
        }
7014
7015
0
        GByte *pabyMaskData = nullptr;
7016
0
        if (poMaskBand)
7017
0
        {
7018
0
            pabyMaskData =
7019
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7020
0
            if (!pabyMaskData)
7021
0
            {
7022
0
                CPLFree(pData);
7023
0
                return CE_Failure;
7024
0
            }
7025
7026
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7027
0
                                     pabyMaskData, nXReduced, nYReduced,
7028
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
7029
0
            {
7030
0
                CPLFree(pData);
7031
0
                CPLFree(pabyMaskData);
7032
0
                return CE_Failure;
7033
0
            }
7034
0
        }
7035
7036
        /* this isn't the fastest way to do this, but is easier for now */
7037
0
        for (int iY = 0; iY < nYReduced; iY++)
7038
0
        {
7039
0
            for (int iX = 0; iX < nXReduced; iX++)
7040
0
            {
7041
0
                const int iOffset = iX + iY * nXReduced;
7042
0
                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7043
0
                    continue;
7044
7045
0
                bool bValid = true;
7046
0
                double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7047
0
                                               iOffset, sNoDataValues, bValid);
7048
0
                if (!bValid)
7049
0
                    continue;
7050
7051
0
                dfMin = std::min(dfMin, dfValue);
7052
0
                dfMax = std::max(dfMax, dfValue);
7053
7054
0
                nValidCount++;
7055
0
                if (dfMin == dfMax)
7056
0
                {
7057
0
                    if (nValidCount == 1)
7058
0
                        dfMean = dfMin;
7059
0
                }
7060
0
                else
7061
0
                {
7062
0
                    const double dfDelta = dfValue - dfMean;
7063
0
                    dfMean += dfDelta / nValidCount;
7064
0
                    dfM2 += dfDelta * (dfValue - dfMean);
7065
0
                }
7066
0
            }
7067
0
        }
7068
7069
0
        nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7070
7071
0
        CPLFree(pData);
7072
0
        CPLFree(pabyMaskData);
7073
0
    }
7074
7075
0
    else  // No arbitrary overviews.
7076
0
    {
7077
0
        if (!InitBlockInfo())
7078
0
            return CE_Failure;
7079
7080
        /* --------------------------------------------------------------------
7081
         */
7082
        /*      Figure out the ratio of blocks we will read to get an */
7083
        /*      approximate value. */
7084
        /* --------------------------------------------------------------------
7085
         */
7086
0
        int nSampleRate = 1;
7087
0
        if (bApproxOK)
7088
0
        {
7089
0
            nSampleRate = static_cast<int>(std::max(
7090
0
                1.0,
7091
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7092
            // We want to avoid probing only the first column of blocks for
7093
            // a square shaped raster, because it is not unlikely that it may
7094
            // be padding only (#6378)
7095
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7096
0
                nSampleRate += 1;
7097
0
        }
7098
0
        if (nSampleRate == 1)
7099
0
            bApproxOK = false;
7100
7101
        // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7102
        // for each block, and possibly for the whole raster.
7103
0
        if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7104
0
                            eDataType == GDT_UInt16))
7105
0
        {
7106
            // We can do integer computation on the whole raster in the Byte case
7107
            // only if the number of pixels explored is lower than
7108
            // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7109
            // Should be 99.99999% of cases.
7110
            // For GUInt16, this limits to raster of 4 giga pixels
7111
7112
0
            const bool bIntegerStats =
7113
0
                ((eDataType == GDT_UInt8 &&
7114
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7115
0
                          nSampleRate <
7116
0
                      GUINTBIG_MAX / (255U * 255U) /
7117
0
                          (static_cast<GUInt64>(nBlockXSize) *
7118
0
                           static_cast<GUInt64>(nBlockYSize))) ||
7119
0
                 (eDataType == GDT_UInt16 &&
7120
0
                  static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7121
0
                          nSampleRate <
7122
0
                      GUINTBIG_MAX / (65535U * 65535U) /
7123
0
                          (static_cast<GUInt64>(nBlockXSize) *
7124
0
                           static_cast<GUInt64>(nBlockYSize)))) &&
7125
                // Can be set to NO for easier debugging of the !bIntegerStats
7126
                // case which requires huge rasters to trigger
7127
0
                CPLTestBool(
7128
0
                    CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7129
7130
0
            const GUInt32 nMaxValueType =
7131
0
                (eDataType == GDT_UInt8) ? 255 : 65535;
7132
0
            GUInt32 nMin = nMaxValueType;
7133
0
            GUInt32 nMax = 0;
7134
0
            GUIntBig nSum = 0;
7135
0
            GUIntBig nSumSquare = 0;
7136
            // If no valid nodata, map to invalid value (256 for Byte)
7137
0
            const GUInt32 nNoDataValue =
7138
0
                (sNoDataValues.bGotNoDataValue &&
7139
0
                 sNoDataValues.dfNoDataValue >= 0 &&
7140
0
                 sNoDataValues.dfNoDataValue <= nMaxValueType &&
7141
0
                 fabs(sNoDataValues.dfNoDataValue -
7142
0
                      static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7143
0
                                           1e-10)) < 1e-10)
7144
0
                    ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7145
0
                    : nMaxValueType + 1;
7146
7147
0
            for (GIntBig iSampleBlock = 0;
7148
0
                 iSampleBlock <
7149
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7150
0
                 iSampleBlock += nSampleRate)
7151
0
            {
7152
0
                const int iYBlock =
7153
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
7154
0
                const int iXBlock =
7155
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
7156
7157
0
                GDALRasterBlock *const poBlock =
7158
0
                    GetLockedBlockRef(iXBlock, iYBlock);
7159
0
                if (poBlock == nullptr)
7160
0
                    return CE_Failure;
7161
7162
0
                void *const pData = poBlock->GetDataRef();
7163
7164
0
                int nXCheck = 0, nYCheck = 0;
7165
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7166
7167
0
                GUIntBig nBlockSum = 0;
7168
0
                GUIntBig nBlockSumSquare = 0;
7169
0
                GUIntBig nBlockSampleCount = 0;
7170
0
                GUIntBig nBlockValidCount = 0;
7171
0
                GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7172
0
                GUIntBig &nBlockSumSquareRef =
7173
0
                    bIntegerStats ? nSumSquare : nBlockSumSquare;
7174
0
                GUIntBig &nBlockSampleCountRef =
7175
0
                    bIntegerStats ? nSampleCount : nBlockSampleCount;
7176
0
                GUIntBig &nBlockValidCountRef =
7177
0
                    bIntegerStats ? nValidCount : nBlockValidCount;
7178
7179
0
                if (eDataType == GDT_UInt8)
7180
0
                {
7181
0
                    ComputeStatisticsInternal<
7182
0
                        GByte, /* COMPUTE_OTHER_STATS = */ true>::
7183
0
                        f(nXCheck, nBlockXSize, nYCheck,
7184
0
                          static_cast<const GByte *>(pData),
7185
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7186
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7187
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7188
0
                }
7189
0
                else
7190
0
                {
7191
0
                    ComputeStatisticsInternal<
7192
0
                        GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7193
0
                        f(nXCheck, nBlockXSize, nYCheck,
7194
0
                          static_cast<const GUInt16 *>(pData),
7195
0
                          nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7196
0
                          nMax, nBlockSumRef, nBlockSumSquareRef,
7197
0
                          nBlockSampleCountRef, nBlockValidCountRef);
7198
0
                }
7199
7200
0
                poBlock->DropLock();
7201
7202
0
                if (!bIntegerStats)
7203
0
                {
7204
0
                    nSampleCount += nBlockSampleCount;
7205
0
                    if (nBlockValidCount)
7206
0
                    {
7207
                        // Update the global mean and M2 (the difference of the
7208
                        // square to the mean) from the values of the block
7209
                        // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7210
0
                        const double dfBlockValidCount =
7211
0
                            static_cast<double>(nBlockValidCount);
7212
0
                        const double dfBlockMean =
7213
0
                            static_cast<double>(nBlockSum) / dfBlockValidCount;
7214
0
                        const double dfBlockM2 =
7215
0
                            static_cast<double>(
7216
0
                                GDALUInt128::Mul(nBlockSumSquare,
7217
0
                                                 nBlockValidCount) -
7218
0
                                GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7219
0
                            dfBlockValidCount;
7220
0
                        const double dfDelta = dfBlockMean - dfMean;
7221
0
                        const auto nNewValidCount =
7222
0
                            nValidCount + nBlockValidCount;
7223
0
                        const double dfNewValidCount =
7224
0
                            static_cast<double>(nNewValidCount);
7225
0
                        dfMean +=
7226
0
                            dfDelta * (dfBlockValidCount / dfNewValidCount);
7227
0
                        dfM2 +=
7228
0
                            dfBlockM2 + dfDelta * dfDelta *
7229
0
                                            static_cast<double>(nValidCount) *
7230
0
                                            dfBlockValidCount / dfNewValidCount;
7231
0
                        nValidCount = nNewValidCount;
7232
0
                    }
7233
0
                }
7234
7235
0
                if (!pfnProgress(static_cast<double>(iSampleBlock) /
7236
0
                                     (static_cast<double>(nBlocksPerRow) *
7237
0
                                      nBlocksPerColumn),
7238
0
                                 "Compute Statistics", pProgressData))
7239
0
                {
7240
0
                    ReportError(CE_Failure, CPLE_UserInterrupt,
7241
0
                                "User terminated");
7242
0
                    return CE_Failure;
7243
0
                }
7244
0
            }
7245
7246
0
            if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7247
0
            {
7248
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7249
0
                return CE_Failure;
7250
0
            }
7251
7252
0
            double dfStdDev = 0;
7253
0
            if (bIntegerStats)
7254
0
            {
7255
0
                if (nValidCount)
7256
0
                    dfMean = static_cast<double>(nSum) / nValidCount;
7257
7258
                // To avoid potential precision issues when doing the difference,
7259
                // we need to do that computation on 128 bit rather than casting
7260
                // to double
7261
0
                const GDALUInt128 nTmpForStdDev(
7262
0
                    GDALUInt128::Mul(nSumSquare, nValidCount) -
7263
0
                    GDALUInt128::Mul(nSum, nSum));
7264
0
                dfStdDev =
7265
0
                    nValidCount > 0
7266
0
                        ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7267
0
                        : 0.0;
7268
0
            }
7269
0
            else if (nValidCount > 0)
7270
0
            {
7271
0
                dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7272
0
            }
7273
7274
            /// Save computed information
7275
0
            if (nValidCount > 0)
7276
0
            {
7277
0
                if (bApproxOK)
7278
0
                {
7279
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7280
0
                }
7281
0
                else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7282
0
                {
7283
0
                    SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7284
0
                }
7285
0
                SetStatistics(nMin, nMax, dfMean, dfStdDev);
7286
0
            }
7287
7288
0
            SetValidPercent(nSampleCount, nValidCount);
7289
7290
            /* --------------------------------------------------------------------
7291
             */
7292
            /*      Record results. */
7293
            /* --------------------------------------------------------------------
7294
             */
7295
0
            if (pdfMin != nullptr)
7296
0
                *pdfMin = nValidCount ? nMin : 0;
7297
0
            if (pdfMax != nullptr)
7298
0
                *pdfMax = nValidCount ? nMax : 0;
7299
7300
0
            if (pdfMean != nullptr)
7301
0
                *pdfMean = dfMean;
7302
7303
0
            if (pdfStdDev != nullptr)
7304
0
                *pdfStdDev = dfStdDev;
7305
7306
0
            if (nValidCount > 0)
7307
0
                return CE_None;
7308
7309
0
            ReportError(CE_Failure, CPLE_AppDefined,
7310
0
                        "Failed to compute statistics, no valid pixels found "
7311
0
                        "in sampling.");
7312
0
            return CE_Failure;
7313
0
        }
7314
7315
0
        GByte *pabyMaskData = nullptr;
7316
0
        if (poMaskBand)
7317
0
        {
7318
0
            pabyMaskData = static_cast<GByte *>(
7319
0
                VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7320
0
            if (!pabyMaskData)
7321
0
            {
7322
0
                return CE_Failure;
7323
0
            }
7324
0
        }
7325
7326
0
        float fMin = std::numeric_limits<float>::infinity();
7327
0
        float fMax = -std::numeric_limits<float>::infinity();
7328
0
        const bool bFloat32Optim =
7329
0
            eDataType == GDT_Float32 && !pabyMaskData &&
7330
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7331
0
            CPLTestBool(
7332
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7333
7334
0
#if (defined(__x86_64__) || defined(_M_X64))
7335
0
        const bool bFloat64Optim =
7336
0
            eDataType == GDT_Float64 && !pabyMaskData &&
7337
0
            nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7338
0
            CPLTestBool(
7339
0
                CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7340
0
#endif
7341
7342
0
        for (GIntBig iSampleBlock = 0;
7343
0
             iSampleBlock <
7344
0
             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7345
0
             iSampleBlock += nSampleRate)
7346
0
        {
7347
0
            const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7348
0
            const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7349
7350
0
            int nXCheck = 0, nYCheck = 0;
7351
0
            GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7352
7353
0
            if (poMaskBand &&
7354
0
                poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7355
0
                                     iYBlock * nBlockYSize, nXCheck, nYCheck,
7356
0
                                     pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7357
0
                                     0, nBlockXSize, nullptr) != CE_None)
7358
0
            {
7359
0
                CPLFree(pabyMaskData);
7360
0
                return CE_Failure;
7361
0
            }
7362
7363
0
            GDALRasterBlock *const poBlock =
7364
0
                GetLockedBlockRef(iXBlock, iYBlock);
7365
0
            if (poBlock == nullptr)
7366
0
            {
7367
0
                CPLFree(pabyMaskData);
7368
0
                return CE_Failure;
7369
0
            }
7370
7371
0
            const void *const pData = poBlock->GetDataRef();
7372
7373
0
            if (bFloat32Optim)
7374
0
            {
7375
0
                const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7376
0
                                        !std::isnan(sNoDataValues.fNoDataValue);
7377
0
                double dfBlockMean = 0;
7378
0
                double dfBlockM2 = 0;
7379
0
                double dfBlockValidCount = 0;
7380
0
                for (int iY = 0; iY < nYCheck; iY++)
7381
0
                {
7382
0
                    const int iOffset = iY * nBlockXSize;
7383
0
                    if (dfBlockValidCount > 0 && fMin != fMax)
7384
0
                    {
7385
0
                        int iX = 0;
7386
0
#if (defined(__x86_64__) || defined(_M_X64))
7387
0
                        if (bHasNoData)
7388
0
                        {
7389
0
                            iX = ComputeStatisticsFloat32_SSE2<
7390
0
                                /* bCheckMinEqMax = */ false,
7391
0
                                /* bHasNoData = */ true>(
7392
0
                                static_cast<const float *>(pData) + iOffset,
7393
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7394
0
                                fMax, dfBlockMean, dfBlockM2,
7395
0
                                dfBlockValidCount);
7396
0
                        }
7397
0
                        else
7398
0
                        {
7399
0
                            iX = ComputeStatisticsFloat32_SSE2<
7400
0
                                /* bCheckMinEqMax = */ false,
7401
0
                                /* bHasNoData = */ false>(
7402
0
                                static_cast<const float *>(pData) + iOffset,
7403
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7404
0
                                fMax, dfBlockMean, dfBlockM2,
7405
0
                                dfBlockValidCount);
7406
0
                        }
7407
0
#endif
7408
0
                        for (; iX < nXCheck; iX++)
7409
0
                        {
7410
0
                            const float fValue =
7411
0
                                static_cast<const float *>(pData)[iOffset + iX];
7412
0
                            if (std::isnan(fValue) ||
7413
0
                                (bHasNoData &&
7414
0
                                 fValue == sNoDataValues.fNoDataValue))
7415
0
                                continue;
7416
0
                            fMin = std::min(fMin, fValue);
7417
0
                            fMax = std::max(fMax, fValue);
7418
0
                            dfBlockValidCount += 1.0;
7419
0
                            const double dfValue = static_cast<double>(fValue);
7420
0
                            const double dfDelta = dfValue - dfBlockMean;
7421
0
                            dfBlockMean += dfDelta / dfBlockValidCount;
7422
0
                            dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7423
0
                        }
7424
0
                    }
7425
0
                    else
7426
0
                    {
7427
0
                        int iX = 0;
7428
0
                        if (dfBlockValidCount == 0)
7429
0
                        {
7430
0
                            for (; iX < nXCheck; iX++)
7431
0
                            {
7432
0
                                const float fValue = static_cast<const float *>(
7433
0
                                    pData)[iOffset + iX];
7434
0
                                if (std::isnan(fValue) ||
7435
0
                                    (bHasNoData &&
7436
0
                                     fValue == sNoDataValues.fNoDataValue))
7437
0
                                    continue;
7438
0
                                fMin = std::min(fMin, fValue);
7439
0
                                fMax = std::max(fMax, fValue);
7440
0
                                dfBlockValidCount = 1;
7441
0
                                dfBlockMean = static_cast<double>(fValue);
7442
0
                                iX++;
7443
0
                                break;
7444
0
                            }
7445
0
                        }
7446
0
#if (defined(__x86_64__) || defined(_M_X64))
7447
0
                        if (bHasNoData)
7448
0
                        {
7449
0
                            iX = ComputeStatisticsFloat32_SSE2<
7450
0
                                /* bCheckMinEqMax = */ true,
7451
0
                                /* bHasNoData = */ true>(
7452
0
                                static_cast<const float *>(pData) + iOffset,
7453
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7454
0
                                fMax, dfBlockMean, dfBlockM2,
7455
0
                                dfBlockValidCount);
7456
0
                        }
7457
0
                        else
7458
0
                        {
7459
0
                            iX = ComputeStatisticsFloat32_SSE2<
7460
0
                                /* bCheckMinEqMax = */ true,
7461
0
                                /* bHasNoData = */ false>(
7462
0
                                static_cast<const float *>(pData) + iOffset,
7463
0
                                sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7464
0
                                fMax, dfBlockMean, dfBlockM2,
7465
0
                                dfBlockValidCount);
7466
0
                        }
7467
0
#endif
7468
0
                        for (; iX < nXCheck; iX++)
7469
0
                        {
7470
0
                            const float fValue =
7471
0
                                static_cast<const float *>(pData)[iOffset + iX];
7472
0
                            if (std::isnan(fValue) ||
7473
0
                                (bHasNoData &&
7474
0
                                 fValue == sNoDataValues.fNoDataValue))
7475
0
                                continue;
7476
0
                            fMin = std::min(fMin, fValue);
7477
0
                            fMax = std::max(fMax, fValue);
7478
0
                            dfBlockValidCount += 1.0;
7479
0
                            if (fMin != fMax)
7480
0
                            {
7481
0
                                const double dfValue =
7482
0
                                    static_cast<double>(fValue);
7483
0
                                const double dfDelta = dfValue - dfBlockMean;
7484
0
                                dfBlockMean += dfDelta / dfBlockValidCount;
7485
0
                                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7486
0
                            }
7487
0
                        }
7488
0
                    }
7489
0
                }
7490
7491
0
                if (dfBlockValidCount > 0)
7492
0
                {
7493
                    // Update the global mean and M2 (the difference of the
7494
                    // square to the mean) from the values of the block
7495
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7496
0
                    const auto nNewValidCount =
7497
0
                        nValidCount + static_cast<int>(dfBlockValidCount);
7498
0
                    dfM2 += dfBlockM2;
7499
0
                    if (dfBlockMean != dfMean)
7500
0
                    {
7501
0
                        if (nValidCount == 0)
7502
0
                        {
7503
0
                            dfMean = dfBlockMean;
7504
0
                        }
7505
0
                        else
7506
0
                        {
7507
0
                            const double dfDelta = dfBlockMean - dfMean;
7508
0
                            const double dfNewValidCount =
7509
0
                                static_cast<double>(nNewValidCount);
7510
0
                            dfMean +=
7511
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
7512
0
                            dfM2 += dfDelta * dfDelta *
7513
0
                                    static_cast<double>(nValidCount) *
7514
0
                                    dfBlockValidCount / dfNewValidCount;
7515
0
                        }
7516
0
                    }
7517
0
                    nValidCount = nNewValidCount;
7518
0
                }
7519
0
            }
7520
7521
0
#if (defined(__x86_64__) || defined(_M_X64))
7522
0
            else if (bFloat64Optim)
7523
0
            {
7524
0
                const bool bHasNoData =
7525
0
                    sNoDataValues.bGotNoDataValue &&
7526
0
                    !std::isnan(sNoDataValues.dfNoDataValue);
7527
0
                double dfBlockMean = 0;
7528
0
                double dfBlockM2 = 0;
7529
0
                double dfBlockValidCount = 0;
7530
0
                for (int iY = 0; iY < nYCheck; iY++)
7531
0
                {
7532
0
                    const int iOffset = iY * nBlockXSize;
7533
0
                    if (dfBlockValidCount != 0 && dfMin != dfMax)
7534
0
                    {
7535
0
                        int iX = 0;
7536
0
                        if (bHasNoData)
7537
0
                        {
7538
0
                            iX = ComputeStatisticsFloat64_SSE2<
7539
0
                                /* bCheckMinEqMax = */ false,
7540
0
                                /* bHasNoData = */ true>(
7541
0
                                static_cast<const double *>(pData) + iOffset,
7542
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7543
0
                                dfMax, dfBlockMean, dfBlockM2,
7544
0
                                dfBlockValidCount);
7545
0
                        }
7546
0
                        else
7547
0
                        {
7548
0
                            iX = ComputeStatisticsFloat64_SSE2<
7549
0
                                /* bCheckMinEqMax = */ false,
7550
0
                                /* bHasNoData = */ false>(
7551
0
                                static_cast<const double *>(pData) + iOffset,
7552
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7553
0
                                dfMax, dfBlockMean, dfBlockM2,
7554
0
                                dfBlockValidCount);
7555
0
                        }
7556
0
                        for (; iX < nXCheck; iX++)
7557
0
                        {
7558
0
                            const double dfValue = static_cast<const double *>(
7559
0
                                pData)[iOffset + iX];
7560
0
                            if (std::isnan(dfValue) ||
7561
0
                                (bHasNoData &&
7562
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7563
0
                                continue;
7564
0
                            dfMin = std::min(dfMin, dfValue);
7565
0
                            dfMax = std::max(dfMax, dfValue);
7566
0
                            dfBlockValidCount += 1.0;
7567
0
                            const double dfDelta = dfValue - dfBlockMean;
7568
0
                            dfBlockMean += dfDelta / dfBlockValidCount;
7569
0
                            dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7570
0
                        }
7571
0
                    }
7572
0
                    else
7573
0
                    {
7574
0
                        int iX = 0;
7575
0
                        if (dfBlockValidCount == 0)
7576
0
                        {
7577
0
                            for (; iX < nXCheck; iX++)
7578
0
                            {
7579
0
                                const double dfValue =
7580
0
                                    static_cast<const double *>(
7581
0
                                        pData)[iOffset + iX];
7582
0
                                if (std::isnan(dfValue) ||
7583
0
                                    (bHasNoData &&
7584
0
                                     dfValue == sNoDataValues.dfNoDataValue))
7585
0
                                    continue;
7586
0
                                dfMin = std::min(dfMin, dfValue);
7587
0
                                dfMax = std::max(dfMax, dfValue);
7588
0
                                dfBlockValidCount = 1;
7589
0
                                dfBlockMean = dfValue;
7590
0
                                iX++;
7591
0
                                break;
7592
0
                            }
7593
0
                        }
7594
0
                        if (bHasNoData)
7595
0
                        {
7596
0
                            iX = ComputeStatisticsFloat64_SSE2<
7597
0
                                /* bCheckMinEqMax = */ true,
7598
0
                                /* bHasNoData = */ true>(
7599
0
                                static_cast<const double *>(pData) + iOffset,
7600
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7601
0
                                dfMax, dfBlockMean, dfBlockM2,
7602
0
                                dfBlockValidCount);
7603
0
                        }
7604
0
                        else
7605
0
                        {
7606
0
                            iX = ComputeStatisticsFloat64_SSE2<
7607
0
                                /* bCheckMinEqMax = */ true,
7608
0
                                /* bHasNoData = */ false>(
7609
0
                                static_cast<const double *>(pData) + iOffset,
7610
0
                                sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7611
0
                                dfMax, dfBlockMean, dfBlockM2,
7612
0
                                dfBlockValidCount);
7613
0
                        }
7614
0
                        for (; iX < nXCheck; iX++)
7615
0
                        {
7616
0
                            const double dfValue = static_cast<const double *>(
7617
0
                                pData)[iOffset + iX];
7618
0
                            if (std::isnan(dfValue) ||
7619
0
                                (bHasNoData &&
7620
0
                                 dfValue == sNoDataValues.dfNoDataValue))
7621
0
                                continue;
7622
0
                            dfMin = std::min(dfMin, dfValue);
7623
0
                            dfMax = std::max(dfMax, dfValue);
7624
0
                            dfBlockValidCount += 1.0;
7625
0
                            if (dfMin != dfMax)
7626
0
                            {
7627
0
                                const double dfDelta = dfValue - dfBlockMean;
7628
0
                                dfBlockMean += dfDelta / dfBlockValidCount;
7629
0
                                dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7630
0
                            }
7631
0
                        }
7632
0
                    }
7633
0
                }
7634
7635
0
                if (dfBlockValidCount > 0)
7636
0
                {
7637
                    // Update the global mean and M2 (the difference of the
7638
                    // square to the mean) from the values of the block
7639
                    // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7640
0
                    const auto nNewValidCount =
7641
0
                        nValidCount + static_cast<int>(dfBlockValidCount);
7642
0
                    dfM2 += dfBlockM2;
7643
0
                    if (dfBlockMean != dfMean)
7644
0
                    {
7645
0
                        if (nValidCount == 0)
7646
0
                        {
7647
0
                            dfMean = dfBlockMean;
7648
0
                        }
7649
0
                        else
7650
0
                        {
7651
0
                            const double dfDelta = dfBlockMean - dfMean;
7652
0
                            const double dfNewValidCount =
7653
0
                                static_cast<double>(nNewValidCount);
7654
0
                            dfMean +=
7655
0
                                dfDelta * (dfBlockValidCount / dfNewValidCount);
7656
0
                            dfM2 += dfDelta * dfDelta *
7657
0
                                    static_cast<double>(nValidCount) *
7658
0
                                    dfBlockValidCount / dfNewValidCount;
7659
0
                        }
7660
0
                    }
7661
0
                    nValidCount = nNewValidCount;
7662
0
                }
7663
0
            }
7664
0
#endif  // (defined(__x86_64__) || defined(_M_X64))
7665
7666
0
            else
7667
0
            {
7668
                // This isn't the fastest way to do this, but is easier for now.
7669
0
                for (int iY = 0; iY < nYCheck; iY++)
7670
0
                {
7671
0
                    if (nValidCount && dfMin != dfMax)
7672
0
                    {
7673
0
                        for (int iX = 0; iX < nXCheck; iX++)
7674
0
                        {
7675
0
                            const GPtrDiff_t iOffset =
7676
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7677
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7678
0
                                continue;
7679
7680
0
                            bool bValid = true;
7681
0
                            double dfValue =
7682
0
                                GetPixelValue(eDataType, bSignedByte, pData,
7683
0
                                              iOffset, sNoDataValues, bValid);
7684
7685
0
                            if (!bValid)
7686
0
                                continue;
7687
7688
0
                            dfMin = std::min(dfMin, dfValue);
7689
0
                            dfMax = std::max(dfMax, dfValue);
7690
7691
0
                            nValidCount++;
7692
0
                            const double dfDelta = dfValue - dfMean;
7693
0
                            dfMean += dfDelta / nValidCount;
7694
0
                            dfM2 += dfDelta * (dfValue - dfMean);
7695
0
                        }
7696
0
                    }
7697
0
                    else
7698
0
                    {
7699
0
                        int iX = 0;
7700
0
                        if (nValidCount == 0)
7701
0
                        {
7702
0
                            for (; iX < nXCheck; iX++)
7703
0
                            {
7704
0
                                const GPtrDiff_t iOffset =
7705
0
                                    iX +
7706
0
                                    static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7707
0
                                if (pabyMaskData && pabyMaskData[iOffset] == 0)
7708
0
                                    continue;
7709
7710
0
                                bool bValid = true;
7711
0
                                double dfValue = GetPixelValue(
7712
0
                                    eDataType, bSignedByte, pData, iOffset,
7713
0
                                    sNoDataValues, bValid);
7714
7715
0
                                if (!bValid)
7716
0
                                    continue;
7717
7718
0
                                dfMin = dfValue;
7719
0
                                dfMax = dfValue;
7720
0
                                dfMean = dfValue;
7721
0
                                nValidCount = 1;
7722
0
                                iX++;
7723
0
                                break;
7724
0
                            }
7725
0
                        }
7726
0
                        for (; iX < nXCheck; iX++)
7727
0
                        {
7728
0
                            const GPtrDiff_t iOffset =
7729
0
                                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7730
0
                            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7731
0
                                continue;
7732
7733
0
                            bool bValid = true;
7734
0
                            double dfValue =
7735
0
                                GetPixelValue(eDataType, bSignedByte, pData,
7736
0
                                              iOffset, sNoDataValues, bValid);
7737
7738
0
                            if (!bValid)
7739
0
                                continue;
7740
7741
0
                            dfMin = std::min(dfMin, dfValue);
7742
0
                            dfMax = std::max(dfMax, dfValue);
7743
7744
0
                            nValidCount++;
7745
0
                            if (dfMin != dfMax)
7746
0
                            {
7747
0
                                const double dfDelta = dfValue - dfMean;
7748
0
                                dfMean += dfDelta / nValidCount;
7749
0
                                dfM2 += dfDelta * (dfValue - dfMean);
7750
0
                            }
7751
0
                        }
7752
0
                    }
7753
0
                }
7754
0
            }
7755
7756
0
            nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
7757
7758
0
            poBlock->DropLock();
7759
7760
0
            if (!pfnProgress(
7761
0
                    static_cast<double>(iSampleBlock) /
7762
0
                        (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
7763
0
                    "Compute Statistics", pProgressData))
7764
0
            {
7765
0
                ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7766
0
                CPLFree(pabyMaskData);
7767
0
                return CE_Failure;
7768
0
            }
7769
0
        }
7770
7771
0
        if (bFloat32Optim)
7772
0
        {
7773
0
            dfMin = static_cast<double>(fMin);
7774
0
            dfMax = static_cast<double>(fMax);
7775
0
        }
7776
0
        CPLFree(pabyMaskData);
7777
0
    }
7778
7779
0
    if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7780
0
    {
7781
0
        ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7782
0
        return CE_Failure;
7783
0
    }
7784
7785
    /* -------------------------------------------------------------------- */
7786
    /*      Save computed information.                                      */
7787
    /* -------------------------------------------------------------------- */
7788
0
    const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7789
7790
0
    if (nValidCount > 0)
7791
0
    {
7792
0
        if (bApproxOK)
7793
0
        {
7794
0
            SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7795
0
        }
7796
0
        else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7797
0
        {
7798
0
            SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7799
0
        }
7800
0
        SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7801
0
    }
7802
0
    else
7803
0
    {
7804
0
        dfMin = 0.0;
7805
0
        dfMax = 0.0;
7806
0
    }
7807
7808
0
    SetValidPercent(nSampleCount, nValidCount);
7809
7810
    /* -------------------------------------------------------------------- */
7811
    /*      Record results.                                                 */
7812
    /* -------------------------------------------------------------------- */
7813
0
    if (pdfMin != nullptr)
7814
0
        *pdfMin = dfMin;
7815
0
    if (pdfMax != nullptr)
7816
0
        *pdfMax = dfMax;
7817
7818
0
    if (pdfMean != nullptr)
7819
0
        *pdfMean = dfMean;
7820
7821
0
    if (pdfStdDev != nullptr)
7822
0
        *pdfStdDev = dfStdDev;
7823
7824
0
    if (nValidCount > 0)
7825
0
        return CE_None;
7826
7827
0
    ReportError(
7828
0
        CE_Failure, CPLE_AppDefined,
7829
0
        "Failed to compute statistics, no valid pixels found in sampling.");
7830
0
    return CE_Failure;
7831
0
}
7832
7833
/************************************************************************/
7834
/*                    GDALComputeRasterStatistics()                     */
7835
/************************************************************************/
7836
7837
/**
7838
 * \brief Compute image statistics.
7839
 *
7840
 * @see GDALRasterBand::ComputeStatistics()
7841
 */
7842
7843
CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7844
                                               int bApproxOK, double *pdfMin,
7845
                                               double *pdfMax, double *pdfMean,
7846
                                               double *pdfStdDev,
7847
                                               GDALProgressFunc pfnProgress,
7848
                                               void *pProgressData)
7849
7850
0
{
7851
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7852
7853
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7854
7855
0
    return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7856
0
                                     pdfStdDev, pfnProgress, pProgressData);
7857
0
}
7858
7859
/************************************************************************/
7860
/*                           SetStatistics()                            */
7861
/************************************************************************/
7862
7863
/**
7864
 * \brief Set statistics on band.
7865
 *
7866
 * This method can be used to store min/max/mean/standard deviation
7867
 * statistics on a raster band.
7868
 *
7869
 * The default implementation stores them as metadata, and will only work
7870
 * on formats that can save arbitrary metadata.  This method cannot detect
7871
 * whether metadata will be properly saved and so may return CE_None even
7872
 * if the statistics will never be saved.
7873
 *
7874
 * This method is the same as the C function GDALSetRasterStatistics().
7875
 *
7876
 * @param dfMin minimum pixel value.
7877
 *
7878
 * @param dfMax maximum pixel value.
7879
 *
7880
 * @param dfMean mean (average) of all pixel values.
7881
 *
7882
 * @param dfStdDev Standard deviation of all pixel values.
7883
 *
7884
 * @return CE_None on success or CE_Failure on failure.
7885
 */
7886
7887
CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7888
                                     double dfStdDev)
7889
7890
0
{
7891
0
    char szValue[128] = {0};
7892
7893
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7894
0
    SetMetadataItem("STATISTICS_MINIMUM", szValue);
7895
7896
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7897
0
    SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7898
7899
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7900
0
    SetMetadataItem("STATISTICS_MEAN", szValue);
7901
7902
0
    CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7903
0
    SetMetadataItem("STATISTICS_STDDEV", szValue);
7904
7905
0
    return CE_None;
7906
0
}
7907
7908
/************************************************************************/
7909
/*                      GDALSetRasterStatistics()                       */
7910
/************************************************************************/
7911
7912
/**
7913
 * \brief Set statistics on band.
7914
 *
7915
 * @see GDALRasterBand::SetStatistics()
7916
 */
7917
7918
CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7919
                                           double dfMax, double dfMean,
7920
                                           double dfStdDev)
7921
7922
0
{
7923
0
    VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7924
7925
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7926
0
    return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7927
0
}
7928
7929
/************************************************************************/
7930
/*                        ComputeRasterMinMax()                         */
7931
/************************************************************************/
7932
7933
template <class T, bool HAS_NODATA>
7934
static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7935
                          T *pMax)
7936
0
{
7937
0
    T min0 = *pMin;
7938
0
    T max0 = *pMax;
7939
0
    T min1 = *pMin;
7940
0
    T max1 = *pMax;
7941
0
    size_t i;
7942
0
    for (i = 0; i + 1 < nElts; i += 2)
7943
0
    {
7944
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7945
0
        {
7946
0
            min0 = std::min(min0, buffer[i]);
7947
0
            max0 = std::max(max0, buffer[i]);
7948
0
        }
7949
0
        if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7950
0
        {
7951
0
            min1 = std::min(min1, buffer[i + 1]);
7952
0
            max1 = std::max(max1, buffer[i + 1]);
7953
0
        }
7954
0
    }
7955
0
    T min = std::min(min0, min1);
7956
0
    T max = std::max(max0, max1);
7957
0
    if (i < nElts)
7958
0
    {
7959
0
        if (!HAS_NODATA || buffer[i] != nodataValue)
7960
0
        {
7961
0
            min = std::min(min, buffer[i]);
7962
0
            max = std::max(max, buffer[i]);
7963
0
        }
7964
0
    }
7965
0
    *pMin = min;
7966
0
    *pMax = max;
7967
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*)
7968
7969
template <GDALDataType eDataType, bool bSignedByte>
7970
static void
7971
ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7972
                     int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7973
                     const GByte *pabyMaskData, double &dfMin, double &dfMax)
7974
0
{
7975
0
    double dfLocalMin = dfMin;
7976
0
    double dfLocalMax = dfMax;
7977
7978
0
    for (int iY = 0; iY < nYCheck; iY++)
7979
0
    {
7980
0
        for (int iX = 0; iX < nXCheck; iX++)
7981
0
        {
7982
0
            const GPtrDiff_t iOffset =
7983
0
                iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7984
0
            if (pabyMaskData && pabyMaskData[iOffset] == 0)
7985
0
                continue;
7986
0
            bool bValid = true;
7987
0
            double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7988
0
                                           iOffset, sNoDataValues, bValid);
7989
0
            if (!bValid)
7990
0
                continue;
7991
7992
0
            dfLocalMin = std::min(dfLocalMin, dfValue);
7993
0
            dfLocalMax = std::max(dfLocalMax, dfValue);
7994
0
        }
7995
0
    }
7996
7997
0
    dfMin = dfLocalMin;
7998
0
    dfMax = dfLocalMax;
7999
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&)
8000
8001
static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8002
                                 bool bSignedByte, int nXCheck, int nYCheck,
8003
                                 int nBlockXSize,
8004
                                 const GDALNoDataValues &sNoDataValues,
8005
                                 const GByte *pabyMaskData, double &dfMin,
8006
                                 double &dfMax)
8007
0
{
8008
0
    switch (eDataType)
8009
0
    {
8010
0
        case GDT_Unknown:
8011
0
            CPLAssert(false);
8012
0
            break;
8013
0
        case GDT_UInt8:
8014
0
            if (bSignedByte)
8015
0
            {
8016
0
                ComputeMinMaxGeneric<GDT_UInt8, true>(
8017
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8018
0
                    pabyMaskData, dfMin, dfMax);
8019
0
            }
8020
0
            else
8021
0
            {
8022
0
                ComputeMinMaxGeneric<GDT_UInt8, false>(
8023
0
                    pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8024
0
                    pabyMaskData, dfMin, dfMax);
8025
0
            }
8026
0
            break;
8027
0
        case GDT_Int8:
8028
0
            ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8029
0
                                                  nBlockXSize, sNoDataValues,
8030
0
                                                  pabyMaskData, dfMin, dfMax);
8031
0
            break;
8032
0
        case GDT_UInt16:
8033
0
            ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8034
0
                                                    nBlockXSize, sNoDataValues,
8035
0
                                                    pabyMaskData, dfMin, dfMax);
8036
0
            break;
8037
0
        case GDT_Int16:
8038
0
            ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8039
0
                                                   nBlockXSize, sNoDataValues,
8040
0
                                                   pabyMaskData, dfMin, dfMax);
8041
0
            break;
8042
0
        case GDT_UInt32:
8043
0
            ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8044
0
                                                    nBlockXSize, sNoDataValues,
8045
0
                                                    pabyMaskData, dfMin, dfMax);
8046
0
            break;
8047
0
        case GDT_Int32:
8048
0
            ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8049
0
                                                   nBlockXSize, sNoDataValues,
8050
0
                                                   pabyMaskData, dfMin, dfMax);
8051
0
            break;
8052
0
        case GDT_UInt64:
8053
0
            ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8054
0
                                                    nBlockXSize, sNoDataValues,
8055
0
                                                    pabyMaskData, dfMin, dfMax);
8056
0
            break;
8057
0
        case GDT_Int64:
8058
0
            ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8059
0
                                                   nBlockXSize, sNoDataValues,
8060
0
                                                   pabyMaskData, dfMin, dfMax);
8061
0
            break;
8062
0
        case GDT_Float16:
8063
0
            ComputeMinMaxGeneric<GDT_Float16, false>(
8064
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8065
0
                pabyMaskData, dfMin, dfMax);
8066
0
            break;
8067
0
        case GDT_Float32:
8068
0
            ComputeMinMaxGeneric<GDT_Float32, false>(
8069
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8070
0
                pabyMaskData, dfMin, dfMax);
8071
0
            break;
8072
0
        case GDT_Float64:
8073
0
            ComputeMinMaxGeneric<GDT_Float64, false>(
8074
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8075
0
                pabyMaskData, dfMin, dfMax);
8076
0
            break;
8077
0
        case GDT_CInt16:
8078
0
            ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8079
0
                                                    nBlockXSize, sNoDataValues,
8080
0
                                                    pabyMaskData, dfMin, dfMax);
8081
0
            break;
8082
0
        case GDT_CInt32:
8083
0
            ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8084
0
                                                    nBlockXSize, sNoDataValues,
8085
0
                                                    pabyMaskData, dfMin, dfMax);
8086
0
            break;
8087
0
        case GDT_CFloat16:
8088
0
            ComputeMinMaxGeneric<GDT_CFloat16, false>(
8089
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8090
0
                pabyMaskData, dfMin, dfMax);
8091
0
            break;
8092
0
        case GDT_CFloat32:
8093
0
            ComputeMinMaxGeneric<GDT_CFloat32, false>(
8094
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8095
0
                pabyMaskData, dfMin, dfMax);
8096
0
            break;
8097
0
        case GDT_CFloat64:
8098
0
            ComputeMinMaxGeneric<GDT_CFloat64, false>(
8099
0
                pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8100
0
                pabyMaskData, dfMin, dfMax);
8101
0
            break;
8102
0
        case GDT_TypeCount:
8103
0
            CPLAssert(false);
8104
0
            break;
8105
0
    }
8106
0
}
8107
8108
static bool ComputeMinMaxGenericIterBlocks(
8109
    GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8110
    GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8111
    const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8112
    double &dfMin, double &dfMax)
8113
8114
0
{
8115
0
    GByte *pabyMaskData = nullptr;
8116
0
    int nBlockXSize, nBlockYSize;
8117
0
    poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8118
8119
0
    if (poMaskBand)
8120
0
    {
8121
0
        pabyMaskData =
8122
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8123
0
        if (!pabyMaskData)
8124
0
        {
8125
0
            return false;
8126
0
        }
8127
0
    }
8128
8129
0
    for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8130
0
         iSampleBlock += nSampleRate)
8131
0
    {
8132
0
        const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8133
0
        const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8134
8135
0
        int nXCheck = 0, nYCheck = 0;
8136
0
        poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8137
8138
0
        if (poMaskBand &&
8139
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8140
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8141
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8142
0
                                 nBlockXSize, nullptr) != CE_None)
8143
0
        {
8144
0
            CPLFree(pabyMaskData);
8145
0
            return false;
8146
0
        }
8147
8148
0
        GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8149
0
        if (poBlock == nullptr)
8150
0
        {
8151
0
            CPLFree(pabyMaskData);
8152
0
            return false;
8153
0
        }
8154
8155
0
        void *const pData = poBlock->GetDataRef();
8156
8157
0
        ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8158
0
                             nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8159
0
                             dfMax);
8160
8161
0
        poBlock->DropLock();
8162
0
    }
8163
8164
0
    CPLFree(pabyMaskData);
8165
0
    return true;
8166
0
}
8167
8168
/**
8169
 * \brief Compute the min/max values for a band.
8170
 *
8171
 * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8172
 * be trusted.  If it doesn't work, a subsample of blocks will be read to
8173
 * get an approximate min/max.  If the band has a nodata value it will
8174
 * be excluded from the minimum and maximum.
8175
 *
8176
 * If bApprox is FALSE, then all pixels will be read and used to compute
8177
 * an exact range.
8178
 *
8179
 * This method is the same as the C function GDALComputeRasterMinMax().
8180
 *
8181
 * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8182
 * FALSE.
8183
 * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8184
 * maximum (adfMinMax[1]) are returned.
8185
 *
8186
 * @return CE_None on success or CE_Failure on failure.
8187
 */
8188
8189
CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8190
0
{
8191
    /* -------------------------------------------------------------------- */
8192
    /*      Does the driver already know the min/max?                       */
8193
    /* -------------------------------------------------------------------- */
8194
0
    if (bApproxOK)
8195
0
    {
8196
0
        int bSuccessMin = FALSE;
8197
0
        int bSuccessMax = FALSE;
8198
8199
0
        double dfMin = GetMinimum(&bSuccessMin);
8200
0
        double dfMax = GetMaximum(&bSuccessMax);
8201
8202
0
        if (bSuccessMin && bSuccessMax)
8203
0
        {
8204
0
            adfMinMax[0] = dfMin;
8205
0
            adfMinMax[1] = dfMax;
8206
0
            return CE_None;
8207
0
        }
8208
0
    }
8209
8210
    /* -------------------------------------------------------------------- */
8211
    /*      If we have overview bands, use them for min/max.                */
8212
    /* -------------------------------------------------------------------- */
8213
    // cppcheck-suppress knownConditionTrueFalse
8214
0
    if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8215
0
    {
8216
0
        GDALRasterBand *poBand =
8217
0
            GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8218
8219
0
        if (poBand != this)
8220
0
            return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8221
0
    }
8222
8223
    /* -------------------------------------------------------------------- */
8224
    /*      Read actual data and compute minimum and maximum.               */
8225
    /* -------------------------------------------------------------------- */
8226
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8227
0
    GDALRasterBand *poMaskBand = nullptr;
8228
0
    if (!sNoDataValues.bGotNoDataValue)
8229
0
    {
8230
0
        const int l_nMaskFlags = GetMaskFlags();
8231
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8232
0
            GetColorInterpretation() != GCI_AlphaBand)
8233
0
        {
8234
0
            poMaskBand = GetMaskBand();
8235
0
        }
8236
0
    }
8237
8238
0
    if (!bApproxOK &&
8239
0
        (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8240
0
         eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8241
0
         eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8242
0
         eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8243
0
         eDataType == GDT_Float64) &&
8244
0
        !poMaskBand)
8245
0
    {
8246
0
        CPLErr eErr = ComputeRasterMinMaxLocation(
8247
0
            &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8248
0
        if (eErr == CE_Warning)
8249
0
        {
8250
0
            ReportError(CE_Failure, CPLE_AppDefined,
8251
0
                        "Failed to compute min/max, no valid pixels found in "
8252
0
                        "sampling.");
8253
0
            eErr = CE_Failure;
8254
0
        }
8255
0
        return eErr;
8256
0
    }
8257
8258
0
    bool bSignedByte = false;
8259
0
    if (eDataType == GDT_UInt8)
8260
0
    {
8261
0
        EnablePixelTypeSignedByteWarning(false);
8262
0
        const char *pszPixelType =
8263
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8264
0
        EnablePixelTypeSignedByteWarning(true);
8265
0
        bSignedByte =
8266
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8267
0
    }
8268
8269
0
    GDALRasterIOExtraArg sExtraArg;
8270
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8271
8272
0
    GUInt32 nMin = (eDataType == GDT_UInt8)
8273
0
                       ? 255
8274
0
                       : 65535;  // used for GByte & GUInt16 cases
8275
0
    GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
8276
0
    GInt16 nMinInt16 =
8277
0
        std::numeric_limits<GInt16>::max();  // used for GInt16 case
8278
0
    GInt16 nMaxInt16 =
8279
0
        std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
8280
0
    double dfMin =
8281
0
        std::numeric_limits<double>::infinity();  // used for generic code path
8282
0
    double dfMax =
8283
0
        -std::numeric_limits<double>::infinity();  // used for generic code path
8284
0
    const bool bUseOptimizedPath =
8285
0
        !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8286
0
                        eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8287
8288
0
    const auto ComputeMinMaxForBlock =
8289
0
        [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8290
0
         &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8291
0
                     int nYCheck)
8292
0
    {
8293
0
        if (eDataType == GDT_UInt8 && !bSignedByte)
8294
0
        {
8295
0
            const bool bHasNoData =
8296
0
                sNoDataValues.bGotNoDataValue &&
8297
0
                GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8298
0
                static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8299
0
                    sNoDataValues.dfNoDataValue;
8300
0
            const GUInt32 nNoDataValue =
8301
0
                bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8302
0
                           : 0;
8303
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8304
0
            ComputeStatisticsInternal<GByte,
8305
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8306
0
                f(nXCheck, nBufferWidth, nYCheck,
8307
0
                  static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8308
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8309
0
        }
8310
0
        else if (eDataType == GDT_UInt16)
8311
0
        {
8312
0
            const bool bHasNoData =
8313
0
                sNoDataValues.bGotNoDataValue &&
8314
0
                GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8315
0
                static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8316
0
                    sNoDataValues.dfNoDataValue;
8317
0
            const GUInt32 nNoDataValue =
8318
0
                bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8319
0
                           : 0;
8320
0
            GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
8321
0
            ComputeStatisticsInternal<GUInt16,
8322
0
                                      /* COMPUTE_OTHER_STATS = */ false>::
8323
0
                f(nXCheck, nBufferWidth, nYCheck,
8324
0
                  static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8325
0
                  nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8326
0
        }
8327
0
        else if (eDataType == GDT_Int16)
8328
0
        {
8329
0
            const bool bHasNoData =
8330
0
                sNoDataValues.bGotNoDataValue &&
8331
0
                GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8332
0
                static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8333
0
                    sNoDataValues.dfNoDataValue;
8334
0
            if (bHasNoData)
8335
0
            {
8336
0
                const int16_t nNoDataValue =
8337
0
                    static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8338
0
                for (int iY = 0; iY < nYCheck; iY++)
8339
0
                {
8340
0
                    ComputeMinMax<int16_t, true>(
8341
0
                        static_cast<const int16_t *>(pData) +
8342
0
                            static_cast<size_t>(iY) * nBufferWidth,
8343
0
                        nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8344
0
                }
8345
0
            }
8346
0
            else
8347
0
            {
8348
0
                for (int iY = 0; iY < nYCheck; iY++)
8349
0
                {
8350
0
                    ComputeMinMax<int16_t, false>(
8351
0
                        static_cast<const int16_t *>(pData) +
8352
0
                            static_cast<size_t>(iY) * nBufferWidth,
8353
0
                        nXCheck, 0, &nMinInt16, &nMaxInt16);
8354
0
                }
8355
0
            }
8356
0
        }
8357
0
    };
8358
8359
0
    if (bApproxOK && HasArbitraryOverviews())
8360
0
    {
8361
        /* --------------------------------------------------------------------
8362
         */
8363
        /*      Figure out how much the image should be reduced to get an */
8364
        /*      approximate value. */
8365
        /* --------------------------------------------------------------------
8366
         */
8367
0
        double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8368
0
                                  nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8369
8370
0
        int nXReduced = nRasterXSize;
8371
0
        int nYReduced = nRasterYSize;
8372
0
        if (dfReduction > 1.0)
8373
0
        {
8374
0
            nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8375
0
            nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8376
8377
            // Catch the case of huge resizing ratios here
8378
0
            if (nXReduced == 0)
8379
0
                nXReduced = 1;
8380
0
            if (nYReduced == 0)
8381
0
                nYReduced = 1;
8382
0
        }
8383
8384
0
        void *const pData = CPLMalloc(cpl::fits_on<int>(
8385
0
            GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8386
8387
0
        const CPLErr eErr =
8388
0
            IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8389
0
                      nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8390
0
        if (eErr != CE_None)
8391
0
        {
8392
0
            CPLFree(pData);
8393
0
            return eErr;
8394
0
        }
8395
8396
0
        GByte *pabyMaskData = nullptr;
8397
0
        if (poMaskBand)
8398
0
        {
8399
0
            pabyMaskData =
8400
0
                static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8401
0
            if (!pabyMaskData)
8402
0
            {
8403
0
                CPLFree(pData);
8404
0
                return CE_Failure;
8405
0
            }
8406
8407
0
            if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8408
0
                                     pabyMaskData, nXReduced, nYReduced,
8409
0
                                     GDT_UInt8, 0, 0, nullptr) != CE_None)
8410
0
            {
8411
0
                CPLFree(pData);
8412
0
                CPLFree(pabyMaskData);
8413
0
                return CE_Failure;
8414
0
            }
8415
0
        }
8416
8417
0
        if (bUseOptimizedPath)
8418
0
        {
8419
0
            ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8420
0
        }
8421
0
        else
8422
0
        {
8423
0
            ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8424
0
                                 nYReduced, nXReduced, sNoDataValues,
8425
0
                                 pabyMaskData, dfMin, dfMax);
8426
0
        }
8427
8428
0
        CPLFree(pData);
8429
0
        CPLFree(pabyMaskData);
8430
0
    }
8431
8432
0
    else  // No arbitrary overviews
8433
0
    {
8434
0
        if (!InitBlockInfo())
8435
0
            return CE_Failure;
8436
8437
        /* --------------------------------------------------------------------
8438
         */
8439
        /*      Figure out the ratio of blocks we will read to get an */
8440
        /*      approximate value. */
8441
        /* --------------------------------------------------------------------
8442
         */
8443
0
        int nSampleRate = 1;
8444
8445
0
        if (bApproxOK)
8446
0
        {
8447
0
            nSampleRate = static_cast<int>(std::max(
8448
0
                1.0,
8449
0
                sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8450
            // We want to avoid probing only the first column of blocks for
8451
            // a square shaped raster, because it is not unlikely that it may
8452
            // be padding only (#6378).
8453
0
            if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8454
0
                nSampleRate += 1;
8455
0
        }
8456
8457
0
        if (bUseOptimizedPath)
8458
0
        {
8459
0
            for (GIntBig iSampleBlock = 0;
8460
0
                 iSampleBlock <
8461
0
                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8462
0
                 iSampleBlock += nSampleRate)
8463
0
            {
8464
0
                const int iYBlock =
8465
0
                    static_cast<int>(iSampleBlock / nBlocksPerRow);
8466
0
                const int iXBlock =
8467
0
                    static_cast<int>(iSampleBlock % nBlocksPerRow);
8468
8469
0
                GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8470
0
                if (poBlock == nullptr)
8471
0
                    return CE_Failure;
8472
8473
0
                void *const pData = poBlock->GetDataRef();
8474
8475
0
                int nXCheck = 0, nYCheck = 0;
8476
0
                GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8477
8478
0
                ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8479
8480
0
                poBlock->DropLock();
8481
8482
0
                if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8483
0
                    nMax == 255)
8484
0
                    break;
8485
0
            }
8486
0
        }
8487
0
        else
8488
0
        {
8489
0
            const GIntBig nTotalBlocks =
8490
0
                static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8491
0
            if (!ComputeMinMaxGenericIterBlocks(
8492
0
                    this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8493
0
                    nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8494
0
            {
8495
0
                return CE_Failure;
8496
0
            }
8497
0
        }
8498
0
    }
8499
8500
0
    if (bUseOptimizedPath)
8501
0
    {
8502
0
        if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8503
0
        {
8504
0
            dfMin = nMin;
8505
0
            dfMax = nMax;
8506
0
        }
8507
0
        else if (eDataType == GDT_Int16)
8508
0
        {
8509
0
            dfMin = nMinInt16;
8510
0
            dfMax = nMaxInt16;
8511
0
        }
8512
0
    }
8513
8514
0
    if (dfMin > dfMax)
8515
0
    {
8516
0
        adfMinMax[0] = 0;
8517
0
        adfMinMax[1] = 0;
8518
0
        ReportError(
8519
0
            CE_Failure, CPLE_AppDefined,
8520
0
            "Failed to compute min/max, no valid pixels found in sampling.");
8521
0
        return CE_Failure;
8522
0
    }
8523
8524
0
    adfMinMax[0] = dfMin;
8525
0
    adfMinMax[1] = dfMax;
8526
8527
0
    return CE_None;
8528
0
}
8529
8530
/************************************************************************/
8531
/*                      GDALComputeRasterMinMax()                       */
8532
/************************************************************************/
8533
8534
/**
8535
 * \brief Compute the min/max values for a band.
8536
 *
8537
 * @see GDALRasterBand::ComputeRasterMinMax()
8538
 *
8539
 * @note Prior to GDAL 3.6, this function returned void
8540
 */
8541
8542
CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8543
                                           double adfMinMax[2])
8544
8545
0
{
8546
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8547
8548
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8549
0
    return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8550
0
}
8551
8552
/************************************************************************/
8553
/*                    ComputeRasterMinMaxLocation()                     */
8554
/************************************************************************/
8555
8556
/**
8557
 * \brief Compute the min/max values for a band, and their location.
8558
 *
8559
 * Pixels whose value matches the nodata value or are masked by the mask
8560
 * band are ignored.
8561
 *
8562
 * If the minimum or maximum value is hit in several locations, it is not
8563
 * specified which one will be returned.
8564
 *
8565
 * @param[out] pdfMin Pointer to the minimum value.
8566
 * @param[out] pdfMax Pointer to the maximum value.
8567
 * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8568
 * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8569
 * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8570
 * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8571
 *
8572
 * @return CE_None in case of success, CE_Warning if there are no valid values,
8573
 *         CE_Failure in case of error.
8574
 *
8575
 * @since GDAL 3.11
8576
 */
8577
8578
CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8579
                                                   double *pdfMax, int *pnMinX,
8580
                                                   int *pnMinY, int *pnMaxX,
8581
                                                   int *pnMaxY)
8582
0
{
8583
0
    int nMinX = -1;
8584
0
    int nMinY = -1;
8585
0
    int nMaxX = -1;
8586
0
    int nMaxY = -1;
8587
0
    double dfMin = std::numeric_limits<double>::infinity();
8588
0
    double dfMax = -std::numeric_limits<double>::infinity();
8589
0
    if (pdfMin)
8590
0
        *pdfMin = dfMin;
8591
0
    if (pdfMax)
8592
0
        *pdfMax = dfMax;
8593
0
    if (pnMinX)
8594
0
        *pnMinX = nMinX;
8595
0
    if (pnMinY)
8596
0
        *pnMinY = nMinY;
8597
0
    if (pnMaxX)
8598
0
        *pnMaxX = nMaxX;
8599
0
    if (pnMaxY)
8600
0
        *pnMaxY = nMaxY;
8601
8602
0
    if (GDALDataTypeIsComplex(eDataType))
8603
0
    {
8604
0
        CPLError(CE_Failure, CPLE_NotSupported,
8605
0
                 "Complex data type not supported");
8606
0
        return CE_Failure;
8607
0
    }
8608
8609
0
    if (!InitBlockInfo())
8610
0
        return CE_Failure;
8611
8612
0
    GDALNoDataValues sNoDataValues(this, eDataType);
8613
0
    GDALRasterBand *poMaskBand = nullptr;
8614
0
    if (!sNoDataValues.bGotNoDataValue)
8615
0
    {
8616
0
        const int l_nMaskFlags = GetMaskFlags();
8617
0
        if (l_nMaskFlags != GMF_ALL_VALID &&
8618
0
            GetColorInterpretation() != GCI_AlphaBand)
8619
0
        {
8620
0
            poMaskBand = GetMaskBand();
8621
0
        }
8622
0
    }
8623
8624
0
    bool bSignedByte = false;
8625
0
    if (eDataType == GDT_UInt8)
8626
0
    {
8627
0
        EnablePixelTypeSignedByteWarning(false);
8628
0
        const char *pszPixelType =
8629
0
            GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8630
0
        EnablePixelTypeSignedByteWarning(true);
8631
0
        bSignedByte =
8632
0
            pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8633
0
    }
8634
8635
0
    GByte *pabyMaskData = nullptr;
8636
0
    if (poMaskBand)
8637
0
    {
8638
0
        pabyMaskData =
8639
0
            static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8640
0
        if (!pabyMaskData)
8641
0
        {
8642
0
            return CE_Failure;
8643
0
        }
8644
0
    }
8645
8646
0
    const GIntBig nTotalBlocks =
8647
0
        static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8648
0
    bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8649
0
    bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8650
0
    for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8651
0
    {
8652
0
        const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8653
0
        const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8654
8655
0
        int nXCheck = 0, nYCheck = 0;
8656
0
        GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8657
8658
0
        if (poMaskBand &&
8659
0
            poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8660
0
                                 iYBlock * nBlockYSize, nXCheck, nYCheck,
8661
0
                                 pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8662
0
                                 nBlockXSize, nullptr) != CE_None)
8663
0
        {
8664
0
            CPLFree(pabyMaskData);
8665
0
            return CE_Failure;
8666
0
        }
8667
8668
0
        GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8669
0
        if (poBlock == nullptr)
8670
0
        {
8671
0
            CPLFree(pabyMaskData);
8672
0
            return CE_Failure;
8673
0
        }
8674
8675
0
        void *const pData = poBlock->GetDataRef();
8676
8677
0
        if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8678
0
        {
8679
0
            for (int iY = 0; iY < nYCheck; ++iY)
8680
0
            {
8681
0
                for (int iX = 0; iX < nXCheck; ++iX)
8682
0
                {
8683
0
                    const GPtrDiff_t iOffset =
8684
0
                        iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8685
0
                    if (pabyMaskData && pabyMaskData[iOffset] == 0)
8686
0
                        continue;
8687
0
                    bool bValid = true;
8688
0
                    double dfValue =
8689
0
                        GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8690
0
                                      sNoDataValues, bValid);
8691
0
                    if (!bValid)
8692
0
                        continue;
8693
0
                    if (dfValue < dfMin)
8694
0
                    {
8695
0
                        dfMin = dfValue;
8696
0
                        nMinX = iXBlock * nBlockXSize + iX;
8697
0
                        nMinY = iYBlock * nBlockYSize + iY;
8698
0
                    }
8699
0
                    if (dfValue > dfMax)
8700
0
                    {
8701
0
                        dfMax = dfValue;
8702
0
                        nMaxX = iXBlock * nBlockXSize + iX;
8703
0
                        nMaxY = iYBlock * nBlockYSize + iY;
8704
0
                    }
8705
0
                }
8706
0
            }
8707
0
        }
8708
0
        else
8709
0
        {
8710
0
            size_t pos_min = 0;
8711
0
            size_t pos_max = 0;
8712
0
            const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8713
0
            if (bNeedsMin && bNeedsMax)
8714
0
            {
8715
0
                std::tie(pos_min, pos_max) = gdal::minmax_element(
8716
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8717
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
8718
0
                    sNoDataValues.dfNoDataValue);
8719
0
            }
8720
0
            else if (bNeedsMin)
8721
0
            {
8722
0
                pos_min = gdal::min_element(
8723
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8724
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
8725
0
                    sNoDataValues.dfNoDataValue);
8726
0
            }
8727
0
            else if (bNeedsMax)
8728
0
            {
8729
0
                pos_max = gdal::max_element(
8730
0
                    pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8731
0
                    eEffectiveDT, sNoDataValues.bGotNoDataValue,
8732
0
                    sNoDataValues.dfNoDataValue);
8733
0
            }
8734
8735
0
            if (bNeedsMin)
8736
0
            {
8737
0
                const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8738
0
                const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8739
0
                bool bValid = true;
8740
0
                const double dfMinValueBlock =
8741
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_min,
8742
0
                                  sNoDataValues, bValid);
8743
0
                if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
8744
0
                {
8745
0
                    dfMin = dfMinValueBlock;
8746
0
                    nMinX = iXBlock * nBlockXSize + nMinXBlock;
8747
0
                    nMinY = iYBlock * nBlockYSize + nMinYBlock;
8748
0
                }
8749
0
            }
8750
8751
0
            if (bNeedsMax)
8752
0
            {
8753
0
                const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
8754
0
                const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
8755
0
                bool bValid = true;
8756
0
                const double dfMaxValueBlock =
8757
0
                    GetPixelValue(eDataType, bSignedByte, pData, pos_max,
8758
0
                                  sNoDataValues, bValid);
8759
0
                if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
8760
0
                {
8761
0
                    dfMax = dfMaxValueBlock;
8762
0
                    nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
8763
0
                    nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
8764
0
                }
8765
0
            }
8766
0
        }
8767
8768
0
        poBlock->DropLock();
8769
8770
0
        if (eDataType == GDT_UInt8)
8771
0
        {
8772
0
            if (bNeedsMin && dfMin == 0)
8773
0
            {
8774
0
                bNeedsMin = false;
8775
0
            }
8776
0
            if (bNeedsMax && dfMax == 255)
8777
0
            {
8778
0
                bNeedsMax = false;
8779
0
            }
8780
0
            if (!bNeedsMin && !bNeedsMax)
8781
0
            {
8782
0
                break;
8783
0
            }
8784
0
        }
8785
0
    }
8786
8787
0
    CPLFree(pabyMaskData);
8788
8789
0
    if (pdfMin)
8790
0
        *pdfMin = dfMin;
8791
0
    if (pdfMax)
8792
0
        *pdfMax = dfMax;
8793
0
    if (pnMinX)
8794
0
        *pnMinX = nMinX;
8795
0
    if (pnMinY)
8796
0
        *pnMinY = nMinY;
8797
0
    if (pnMaxX)
8798
0
        *pnMaxX = nMaxX;
8799
0
    if (pnMaxY)
8800
0
        *pnMaxY = nMaxY;
8801
0
    return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8802
0
                                                                  : CE_None;
8803
0
}
8804
8805
/************************************************************************/
8806
/*                    GDALComputeRasterMinMaxLocation()                 */
8807
/************************************************************************/
8808
8809
/**
8810
 * \brief Compute the min/max values for a band, and their location.
8811
 *
8812
 * @see GDALRasterBand::ComputeRasterMinMax()
8813
 * @since GDAL 3.11
8814
 */
8815
8816
CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8817
                                       double *pdfMax, int *pnMinX, int *pnMinY,
8818
                                       int *pnMaxX, int *pnMaxY)
8819
8820
0
{
8821
0
    VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8822
8823
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8824
0
    return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8825
0
                                               pnMaxX, pnMaxY);
8826
0
}
8827
8828
/************************************************************************/
8829
/*                        SetDefaultHistogram()                         */
8830
/************************************************************************/
8831
8832
/* FIXME : add proper documentation */
8833
/**
8834
 * \brief Set default histogram.
8835
 *
8836
 * This method is the same as the C function GDALSetDefaultHistogram() and
8837
 * GDALSetDefaultHistogramEx()
8838
 */
8839
CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8840
                                           double /* dfMax */,
8841
                                           int /* nBuckets */,
8842
                                           GUIntBig * /* panHistogram */)
8843
8844
0
{
8845
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8846
0
        ReportError(CE_Failure, CPLE_NotSupported,
8847
0
                    "SetDefaultHistogram() not implemented for this format.");
8848
8849
0
    return CE_Failure;
8850
0
}
8851
8852
/************************************************************************/
8853
/*                      GDALSetDefaultHistogram()                       */
8854
/************************************************************************/
8855
8856
/**
8857
 * \brief Set default histogram.
8858
 *
8859
 * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8860
 * 2 billion.
8861
 *
8862
 * @see GDALRasterBand::SetDefaultHistogram()
8863
 * @see GDALSetRasterHistogramEx()
8864
 */
8865
8866
CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8867
                                           double dfMax, int nBuckets,
8868
                                           int *panHistogram)
8869
8870
0
{
8871
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8872
8873
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8874
8875
0
    GUIntBig *panHistogramTemp =
8876
0
        static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8877
0
    if (panHistogramTemp == nullptr)
8878
0
    {
8879
0
        poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8880
0
                            "Out of memory in GDALSetDefaultHistogram().");
8881
0
        return CE_Failure;
8882
0
    }
8883
8884
0
    for (int i = 0; i < nBuckets; ++i)
8885
0
    {
8886
0
        panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8887
0
    }
8888
8889
0
    const CPLErr eErr =
8890
0
        poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8891
8892
0
    CPLFree(panHistogramTemp);
8893
8894
0
    return eErr;
8895
0
}
8896
8897
/************************************************************************/
8898
/*                     GDALSetDefaultHistogramEx()                      */
8899
/************************************************************************/
8900
8901
/**
8902
 * \brief Set default histogram.
8903
 *
8904
 * @see GDALRasterBand::SetDefaultHistogram()
8905
 *
8906
 */
8907
8908
CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8909
                                             double dfMin, double dfMax,
8910
                                             int nBuckets,
8911
                                             GUIntBig *panHistogram)
8912
8913
0
{
8914
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8915
8916
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8917
0
    return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8918
0
}
8919
8920
/************************************************************************/
8921
/*                           GetDefaultRAT()                            */
8922
/************************************************************************/
8923
8924
/**
8925
 * \brief Fetch default Raster Attribute Table.
8926
 *
8927
 * A RAT will be returned if there is a default one associated with the
8928
 * band, otherwise NULL is returned.  The returned RAT is owned by the
8929
 * band and should not be deleted by the application.
8930
 *
8931
 * This method is the same as the C function GDALGetDefaultRAT().
8932
 *
8933
 * @return NULL, or a pointer to an internal RAT owned by the band.
8934
 */
8935
8936
GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8937
8938
0
{
8939
0
    return nullptr;
8940
0
}
8941
8942
/************************************************************************/
8943
/*                         GDALGetDefaultRAT()                          */
8944
/************************************************************************/
8945
8946
/**
8947
 * \brief Fetch default Raster Attribute Table.
8948
 *
8949
 * @see GDALRasterBand::GetDefaultRAT()
8950
 */
8951
8952
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8953
8954
0
{
8955
0
    VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8956
8957
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8958
0
    return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8959
0
}
8960
8961
/************************************************************************/
8962
/*                           SetDefaultRAT()                            */
8963
/************************************************************************/
8964
8965
/**
8966
 * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8967
 * \brief Set default Raster Attribute Table.
8968
 *
8969
 * Associates a default RAT with the band.  If not implemented for the
8970
 * format a CPLE_NotSupported error will be issued.  If successful a copy
8971
 * of the RAT is made, the original remains owned by the caller.
8972
 *
8973
 * This method is the same as the C function GDALSetDefaultRAT().
8974
 *
8975
 * @param poRAT the RAT to assign to the band.
8976
 *
8977
 * @return CE_None on success or CE_Failure if unsupported or otherwise
8978
 * failing.
8979
 */
8980
8981
/**/
8982
/**/
8983
8984
CPLErr
8985
GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8986
0
{
8987
0
    if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8988
0
    {
8989
0
        CPLPushErrorHandler(CPLQuietErrorHandler);
8990
0
        ReportError(CE_Failure, CPLE_NotSupported,
8991
0
                    "SetDefaultRAT() not implemented for this format.");
8992
0
        CPLPopErrorHandler();
8993
0
    }
8994
0
    return CE_Failure;
8995
0
}
8996
8997
/************************************************************************/
8998
/*                         GDALSetDefaultRAT()                          */
8999
/************************************************************************/
9000
9001
/**
9002
 * \brief Set default Raster Attribute Table.
9003
 *
9004
 * @see GDALRasterBand::GDALSetDefaultRAT()
9005
 */
9006
9007
CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9008
                                     GDALRasterAttributeTableH hRAT)
9009
9010
0
{
9011
0
    VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9012
9013
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9014
9015
0
    return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9016
0
}
9017
9018
/************************************************************************/
9019
/*                            GetMaskBand()                             */
9020
/************************************************************************/
9021
9022
/**
9023
 * \brief Return the mask band associated with the band.
9024
 *
9025
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9026
 * that returns one of four default implementations :
9027
 * <ul>
9028
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9029
 * </li>
9030
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9031
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9032
 * GMF_NODATA | GMF_PER_DATASET.
9033
 * </li>
9034
 * <li>If the band has a nodata value set, an instance of the new
9035
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9036
 * GMF_NODATA.
9037
 * </li>
9038
 * <li>If there is no nodata value, but the dataset has an alpha band that seems
9039
 * to apply to this band (specific rules yet to be determined) and that is of
9040
 * type GDT_UInt8 then that alpha band will be returned, and the flags
9041
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9042
 * </li>
9043
 * <li>If neither of the above apply, an instance of the new
9044
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9045
 * pixels. The null flags will return GMF_ALL_VALID.
9046
 * </li>
9047
 * </ul>
9048
 *
9049
 * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9050
 * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9051
 *
9052
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9053
 * dataset, with the same name as the main dataset and suffixed with .msk,
9054
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9055
 * main dataset.
9056
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9057
 * level, where xx matches the band number of a band of the main dataset. The
9058
 * value of those items is a combination of the flags GMF_ALL_VALID,
9059
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9060
 * a band, then the other rules explained above will be used to generate a
9061
 * on-the-fly mask band.
9062
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9063
 *
9064
 * This method is the same as the C function GDALGetMaskBand().
9065
 *
9066
 * @return a valid mask band.
9067
 *
9068
 *
9069
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9070
 *
9071
 */
9072
GDALRasterBand *GDALRasterBand::GetMaskBand()
9073
9074
0
{
9075
0
    const auto HasNoData = [this]()
9076
0
    {
9077
0
        int bHaveNoDataRaw = FALSE;
9078
0
        bool bHaveNoData = false;
9079
0
        if (eDataType == GDT_Int64)
9080
0
        {
9081
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
9082
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9083
0
        }
9084
0
        else if (eDataType == GDT_UInt64)
9085
0
        {
9086
0
            CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9087
0
            bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9088
0
        }
9089
0
        else
9090
0
        {
9091
0
            const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
9092
0
            if (bHaveNoDataRaw &&
9093
0
                GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9094
0
            {
9095
0
                bHaveNoData = true;
9096
0
            }
9097
0
        }
9098
0
        return bHaveNoData;
9099
0
    };
9100
9101
0
    if (poMask != nullptr)
9102
0
    {
9103
0
        if (poMask.IsOwned())
9104
0
        {
9105
0
            if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9106
0
            {
9107
0
                if (HasNoData())
9108
0
                {
9109
0
                    InvalidateMaskBand();
9110
0
                }
9111
0
            }
9112
0
            else if (auto poNoDataMaskBand =
9113
0
                         dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9114
0
            {
9115
0
                int bHaveNoDataRaw = FALSE;
9116
0
                bool bIsSame = false;
9117
0
                if (eDataType == GDT_Int64)
9118
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9119
0
                                  GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9120
0
                              bHaveNoDataRaw;
9121
0
                else if (eDataType == GDT_UInt64)
9122
0
                    bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9123
0
                                  GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9124
0
                              bHaveNoDataRaw;
9125
0
                else
9126
0
                {
9127
0
                    const double dfNoDataValue =
9128
0
                        GetNoDataValue(&bHaveNoDataRaw);
9129
0
                    if (bHaveNoDataRaw)
9130
0
                    {
9131
0
                        bIsSame =
9132
0
                            std::isnan(dfNoDataValue)
9133
0
                                ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9134
0
                                : poNoDataMaskBand->m_dfNoDataValue ==
9135
0
                                      dfNoDataValue;
9136
0
                    }
9137
0
                }
9138
0
                if (!bIsSame)
9139
0
                    InvalidateMaskBand();
9140
0
            }
9141
0
        }
9142
9143
0
        if (poMask)
9144
0
            return poMask.get();
9145
0
    }
9146
9147
    /* -------------------------------------------------------------------- */
9148
    /*      Check for a mask in a .msk file.                                */
9149
    /* -------------------------------------------------------------------- */
9150
0
    if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9151
0
    {
9152
0
        poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9153
0
        if (poMask != nullptr)
9154
0
        {
9155
0
            nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9156
0
            return poMask.get();
9157
0
        }
9158
0
    }
9159
9160
    /* -------------------------------------------------------------------- */
9161
    /*      Check for NODATA_VALUES metadata.                               */
9162
    /* -------------------------------------------------------------------- */
9163
0
    if (poDS != nullptr)
9164
0
    {
9165
0
        const char *pszGDALNoDataValues =
9166
0
            poDS->GetMetadataItem("NODATA_VALUES");
9167
0
        if (pszGDALNoDataValues != nullptr)
9168
0
        {
9169
0
            char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9170
0
                pszGDALNoDataValues, " ", FALSE, FALSE);
9171
9172
            // Make sure we have as many values as bands.
9173
0
            if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9174
0
                poDS->GetRasterCount() != 0)
9175
0
            {
9176
                // Make sure that all bands have the same data type
9177
                // This is clearly not a fundamental condition, just a
9178
                // condition to make implementation easier.
9179
0
                GDALDataType eDT = GDT_Unknown;
9180
0
                int i = 0;  // Used after for.
9181
0
                for (; i < poDS->GetRasterCount(); ++i)
9182
0
                {
9183
0
                    if (i == 0)
9184
0
                        eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9185
0
                    else if (eDT !=
9186
0
                             poDS->GetRasterBand(i + 1)->GetRasterDataType())
9187
0
                    {
9188
0
                        break;
9189
0
                    }
9190
0
                }
9191
0
                if (i == poDS->GetRasterCount())
9192
0
                {
9193
0
                    nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9194
0
                    try
9195
0
                    {
9196
0
                        poMask.reset(
9197
0
                            std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9198
0
                    }
9199
0
                    catch (const std::bad_alloc &)
9200
0
                    {
9201
0
                        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9202
0
                        poMask.reset();
9203
0
                    }
9204
0
                    CSLDestroy(papszGDALNoDataValues);
9205
0
                    return poMask.get();
9206
0
                }
9207
0
                else
9208
0
                {
9209
0
                    ReportError(CE_Warning, CPLE_AppDefined,
9210
0
                                "All bands should have the same type in "
9211
0
                                "order the NODATA_VALUES metadata item "
9212
0
                                "to be used as a mask.");
9213
0
                }
9214
0
            }
9215
0
            else
9216
0
            {
9217
0
                ReportError(
9218
0
                    CE_Warning, CPLE_AppDefined,
9219
0
                    "NODATA_VALUES metadata item doesn't have the same number "
9220
0
                    "of values as the number of bands.  "
9221
0
                    "Ignoring it for mask.");
9222
0
            }
9223
9224
0
            CSLDestroy(papszGDALNoDataValues);
9225
0
        }
9226
0
    }
9227
9228
    /* -------------------------------------------------------------------- */
9229
    /*      Check for nodata case.                                          */
9230
    /* -------------------------------------------------------------------- */
9231
0
    if (HasNoData())
9232
0
    {
9233
0
        nMaskFlags = GMF_NODATA;
9234
0
        try
9235
0
        {
9236
0
            poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9237
0
        }
9238
0
        catch (const std::bad_alloc &)
9239
0
        {
9240
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9241
0
            poMask.reset();
9242
0
        }
9243
0
        return poMask.get();
9244
0
    }
9245
9246
    /* -------------------------------------------------------------------- */
9247
    /*      Check for alpha case.                                           */
9248
    /* -------------------------------------------------------------------- */
9249
0
    if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9250
0
        this == poDS->GetRasterBand(1) &&
9251
0
        poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9252
0
    {
9253
0
        if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9254
0
        {
9255
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9256
0
            poMask.resetNotOwned(poDS->GetRasterBand(2));
9257
0
            return poMask.get();
9258
0
        }
9259
0
        else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9260
0
        {
9261
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9262
0
            try
9263
0
            {
9264
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9265
0
                    poDS->GetRasterBand(2)));
9266
0
            }
9267
0
            catch (const std::bad_alloc &)
9268
0
            {
9269
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9270
0
                poMask.reset();
9271
0
            }
9272
0
            return poMask.get();
9273
0
        }
9274
0
    }
9275
9276
0
    if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9277
0
        (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9278
0
         this == poDS->GetRasterBand(3)) &&
9279
0
        poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9280
0
    {
9281
0
        if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9282
0
        {
9283
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9284
0
            poMask.resetNotOwned(poDS->GetRasterBand(4));
9285
0
            return poMask.get();
9286
0
        }
9287
0
        else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9288
0
        {
9289
0
            nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9290
0
            try
9291
0
            {
9292
0
                poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9293
0
                    poDS->GetRasterBand(4)));
9294
0
            }
9295
0
            catch (const std::bad_alloc &)
9296
0
            {
9297
0
                CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9298
0
                poMask.reset();
9299
0
            }
9300
0
            return poMask.get();
9301
0
        }
9302
0
    }
9303
9304
    /* -------------------------------------------------------------------- */
9305
    /*      Fallback to all valid case.                                     */
9306
    /* -------------------------------------------------------------------- */
9307
0
    nMaskFlags = GMF_ALL_VALID;
9308
0
    try
9309
0
    {
9310
0
        poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9311
0
    }
9312
0
    catch (const std::bad_alloc &)
9313
0
    {
9314
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9315
0
        poMask.reset();
9316
0
    }
9317
9318
0
    return poMask.get();
9319
0
}
9320
9321
/************************************************************************/
9322
/*                          GDALGetMaskBand()                           */
9323
/************************************************************************/
9324
9325
/**
9326
 * \brief Return the mask band associated with the band.
9327
 *
9328
 * @see GDALRasterBand::GetMaskBand()
9329
 */
9330
9331
GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9332
9333
0
{
9334
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9335
9336
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9337
0
    return poBand->GetMaskBand();
9338
0
}
9339
9340
/************************************************************************/
9341
/*                            GetMaskFlags()                            */
9342
/************************************************************************/
9343
9344
/**
9345
 * \brief Return the status flags of the mask band associated with the band.
9346
 *
9347
 * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9348
 * the following available definitions that may be extended in the future:
9349
 * <ul>
9350
 * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9351
 * 255. When used this will normally be the only flag set.
9352
 * </li>
9353
 * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9354
 * dataset.
9355
 * </li>
9356
 * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9357
 * and may have values other than 0 and 255.
9358
 * </li>
9359
 * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9360
 * nodata values. (mutually exclusive of GMF_ALPHA)
9361
 * </li>
9362
 * </ul>
9363
 *
9364
 * The GDALRasterBand class includes a default implementation of GetMaskBand()
9365
 * that returns one of four default implementations:
9366
 * <ul>
9367
 * <li>If a corresponding .msk file exists it will be used for the mask band.
9368
 * </li>
9369
 * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9370
 * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9371
 * GMF_NODATA | GMF_PER_DATASET.
9372
 * </li>
9373
 * <li>If the band has a nodata value set, an instance of the new
9374
 * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9375
 * GMF_NODATA.
9376
 * </li>
9377
 * <li>If there is no nodata value, but the dataset has an alpha band that
9378
 * seems to apply to this band (specific rules yet to be determined) and that is
9379
 * of type GDT_UInt8 then that alpha band will be returned, and the flags
9380
 * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9381
 * </li>
9382
 * <li>If neither of the above apply, an instance of the new
9383
 * GDALAllValidRasterBand class will be returned that has 255 values for all
9384
 * pixels. The null flags will return GMF_ALL_VALID.
9385
 * </li>
9386
 * </ul>
9387
 *
9388
 * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9389
 * dataset, with the same name as the main dataset and suffixed with .msk,
9390
 * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9391
 * main dataset.
9392
 * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9393
 * level, where xx matches the band number of a band of the main dataset. The
9394
 * value of those items is a combination of the flags GMF_ALL_VALID,
9395
 * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9396
 * a band, then the other rules explained above will be used to generate a
9397
 * on-the-fly mask band.
9398
 * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9399
 *
9400
 * This method is the same as the C function GDALGetMaskFlags().
9401
 *
9402
 *
9403
 * @return a valid mask band.
9404
 *
9405
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9406
 *
9407
 */
9408
int GDALRasterBand::GetMaskFlags()
9409
9410
0
{
9411
    // If we don't have a band yet, force this now so that the masks value
9412
    // will be initialized.
9413
9414
0
    if (poMask == nullptr)
9415
0
        GetMaskBand();
9416
9417
0
    return nMaskFlags;
9418
0
}
9419
9420
/************************************************************************/
9421
/*                          GDALGetMaskFlags()                          */
9422
/************************************************************************/
9423
9424
/**
9425
 * \brief Return the status flags of the mask band associated with the band.
9426
 *
9427
 * @see GDALRasterBand::GetMaskFlags()
9428
 */
9429
9430
int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9431
9432
0
{
9433
0
    VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9434
9435
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9436
0
    return poBand->GetMaskFlags();
9437
0
}
9438
9439
/************************************************************************/
9440
/*                         InvalidateMaskBand()                         */
9441
/************************************************************************/
9442
9443
//! @cond Doxygen_Suppress
9444
void GDALRasterBand::InvalidateMaskBand()
9445
0
{
9446
0
    poMask.reset();
9447
0
    nMaskFlags = 0;
9448
0
}
9449
9450
//! @endcond
9451
9452
/************************************************************************/
9453
/*                           CreateMaskBand()                           */
9454
/************************************************************************/
9455
9456
/**
9457
 * \brief Adds a mask band to the current band
9458
 *
9459
 * The default implementation of the CreateMaskBand() method is implemented
9460
 * based on similar rules to the .ovr handling implemented using the
9461
 * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9462
 * be created with the same basename as the original file, and it will have
9463
 * as many bands as the original image (or just one for GMF_PER_DATASET).
9464
 * The mask images will be deflate compressed tiled images with the same
9465
 * block size as the original image if possible.
9466
 * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9467
 * level, where xx matches the band number of a band of the main dataset. The
9468
 * value of those items will be the one of the nFlagsIn parameter.
9469
 *
9470
 * Note that if you got a mask band with a previous call to GetMaskBand(),
9471
 * it might be invalidated by CreateMaskBand(). So you have to call
9472
 * GetMaskBand() again.
9473
 *
9474
 * This method is the same as the C function GDALCreateMaskBand().
9475
 *
9476
 *
9477
 * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9478
 *
9479
 * @return CE_None on success or CE_Failure on an error.
9480
 *
9481
 * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9482
 * @see GDALDataset::CreateMaskBand()
9483
 *
9484
 */
9485
9486
CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9487
9488
0
{
9489
0
    if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9490
0
    {
9491
0
        const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9492
0
        if (eErr != CE_None)
9493
0
            return eErr;
9494
9495
0
        InvalidateMaskBand();
9496
9497
0
        return CE_None;
9498
0
    }
9499
9500
0
    ReportError(CE_Failure, CPLE_NotSupported,
9501
0
                "CreateMaskBand() not supported for this band.");
9502
9503
0
    return CE_Failure;
9504
0
}
9505
9506
/************************************************************************/
9507
/*                         GDALCreateMaskBand()                         */
9508
/************************************************************************/
9509
9510
/**
9511
 * \brief Adds a mask band to the current band
9512
 *
9513
 * @see GDALRasterBand::CreateMaskBand()
9514
 */
9515
9516
CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9517
9518
0
{
9519
0
    VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9520
9521
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9522
0
    return poBand->CreateMaskBand(nFlags);
9523
0
}
9524
9525
/************************************************************************/
9526
/*                            IsMaskBand()                              */
9527
/************************************************************************/
9528
9529
/**
9530
 * \brief Returns whether a band is a mask band.
9531
 *
9532
 * Mask band must be understood in the broad term: it can be a per-dataset
9533
 * mask band, an alpha band, or an implicit mask band.
9534
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9535
 *
9536
 * This method is the same as the C function GDALIsMaskBand().
9537
 *
9538
 * @return true if the band is a mask band.
9539
 *
9540
 * @see GDALDataset::CreateMaskBand()
9541
 *
9542
 * @since GDAL 3.5.0
9543
 *
9544
 */
9545
9546
bool GDALRasterBand::IsMaskBand() const
9547
0
{
9548
    // The GeoTIFF driver, among others, override this method to
9549
    // also handle external .msk bands.
9550
0
    return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9551
0
           GCI_AlphaBand;
9552
0
}
9553
9554
/************************************************************************/
9555
/*                            GDALIsMaskBand()                          */
9556
/************************************************************************/
9557
9558
/**
9559
 * \brief Returns whether a band is a mask band.
9560
 *
9561
 * Mask band must be understood in the broad term: it can be a per-dataset
9562
 * mask band, an alpha band, or an implicit mask band.
9563
 * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9564
 *
9565
 * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9566
 *
9567
 * @return true if the band is a mask band.
9568
 *
9569
 * @see GDALRasterBand::IsMaskBand()
9570
 *
9571
 * @since GDAL 3.5.0
9572
 *
9573
 */
9574
9575
bool GDALIsMaskBand(GDALRasterBandH hBand)
9576
9577
0
{
9578
0
    VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9579
9580
0
    const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9581
0
    return poBand->IsMaskBand();
9582
0
}
9583
9584
/************************************************************************/
9585
/*                         GetMaskValueRange()                          */
9586
/************************************************************************/
9587
9588
/**
9589
 * \brief Returns the range of values that a mask band can take.
9590
 *
9591
 * @return the range of values that a mask band can take.
9592
 *
9593
 * @since GDAL 3.5.0
9594
 *
9595
 */
9596
9597
GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9598
0
{
9599
0
    return GMVR_UNKNOWN;
9600
0
}
9601
9602
/************************************************************************/
9603
/*                    GetIndexColorTranslationTo()                      */
9604
/************************************************************************/
9605
9606
/**
9607
 * \brief Compute translation table for color tables.
9608
 *
9609
 * When the raster band has a palette index, it may be useful to compute
9610
 * the "translation" of this palette to the palette of another band.
9611
 * The translation tries to do exact matching first, and then approximate
9612
 * matching if no exact matching is possible.
9613
 * This method returns a table such that table[i] = j where i is an index
9614
 * of the 'this' rasterband and j the corresponding index for the reference
9615
 * rasterband.
9616
 *
9617
 * This method is thought as internal to GDAL and is used for drivers
9618
 * like RPFTOC.
9619
 *
9620
 * The implementation only supports 1-byte palette rasterbands.
9621
 *
9622
 * @param poReferenceBand the raster band
9623
 * @param pTranslationTable an already allocated translation table (at least 256
9624
 * bytes), or NULL to let the method allocate it
9625
 * @param pApproximateMatching a pointer to a flag that is set if the matching
9626
 *                              is approximate. May be NULL.
9627
 *
9628
 * @return a translation table if the two bands are palette index and that they
9629
 * do not match or NULL in other cases. The table must be freed with CPLFree if
9630
 * NULL was passed for pTranslationTable.
9631
 */
9632
9633
unsigned char *
9634
GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9635
                                           unsigned char *pTranslationTable,
9636
                                           int *pApproximateMatching)
9637
0
{
9638
0
    if (poReferenceBand == nullptr)
9639
0
        return nullptr;
9640
9641
    // cppcheck-suppress knownConditionTrueFalse
9642
0
    if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9643
        // cppcheck-suppress knownConditionTrueFalse
9644
0
        GetColorInterpretation() == GCI_PaletteIndex &&
9645
0
        poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
9646
0
        GetRasterDataType() == GDT_UInt8)
9647
0
    {
9648
0
        const GDALColorTable *srcColorTable = GetColorTable();
9649
0
        GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9650
0
        if (srcColorTable != nullptr && destColorTable != nullptr)
9651
0
        {
9652
0
            const int nEntries = srcColorTable->GetColorEntryCount();
9653
0
            const int nRefEntries = destColorTable->GetColorEntryCount();
9654
9655
0
            int bHasNoDataValueSrc = FALSE;
9656
0
            double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9657
0
            if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9658
0
                  dfNoDataValueSrc <= 255 &&
9659
0
                  dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9660
0
                bHasNoDataValueSrc = FALSE;
9661
0
            const int noDataValueSrc =
9662
0
                bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
9663
9664
0
            int bHasNoDataValueRef = FALSE;
9665
0
            const double dfNoDataValueRef =
9666
0
                poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
9667
0
            if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
9668
0
                  dfNoDataValueRef <= 255 &&
9669
0
                  dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
9670
0
                bHasNoDataValueRef = FALSE;
9671
0
            const int noDataValueRef =
9672
0
                bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
9673
9674
0
            bool samePalette = false;
9675
9676
0
            if (pApproximateMatching)
9677
0
                *pApproximateMatching = FALSE;
9678
9679
0
            if (nEntries == nRefEntries &&
9680
0
                bHasNoDataValueSrc == bHasNoDataValueRef &&
9681
0
                (bHasNoDataValueSrc == FALSE ||
9682
0
                 noDataValueSrc == noDataValueRef))
9683
0
            {
9684
0
                samePalette = true;
9685
0
                for (int i = 0; i < nEntries; ++i)
9686
0
                {
9687
0
                    if (noDataValueSrc == i)
9688
0
                        continue;
9689
0
                    const GDALColorEntry *entry =
9690
0
                        srcColorTable->GetColorEntry(i);
9691
0
                    const GDALColorEntry *entryRef =
9692
0
                        destColorTable->GetColorEntry(i);
9693
0
                    if (entry->c1 != entryRef->c1 ||
9694
0
                        entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
9695
0
                    {
9696
0
                        samePalette = false;
9697
0
                    }
9698
0
                }
9699
0
            }
9700
9701
0
            if (!samePalette)
9702
0
            {
9703
0
                if (pTranslationTable == nullptr)
9704
0
                {
9705
0
                    pTranslationTable = static_cast<unsigned char *>(
9706
0
                        VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
9707
0
                    if (pTranslationTable == nullptr)
9708
0
                        return nullptr;
9709
0
                }
9710
9711
                // Trying to remap the product palette on the subdataset
9712
                // palette.
9713
0
                for (int i = 0; i < nEntries; ++i)
9714
0
                {
9715
0
                    if (bHasNoDataValueSrc && bHasNoDataValueRef &&
9716
0
                        noDataValueSrc == i)
9717
0
                        continue;
9718
0
                    const GDALColorEntry *entry =
9719
0
                        srcColorTable->GetColorEntry(i);
9720
0
                    bool bMatchFound = false;
9721
0
                    for (int j = 0; j < nRefEntries; ++j)
9722
0
                    {
9723
0
                        if (bHasNoDataValueRef && noDataValueRef == j)
9724
0
                            continue;
9725
0
                        const GDALColorEntry *entryRef =
9726
0
                            destColorTable->GetColorEntry(j);
9727
0
                        if (entry->c1 == entryRef->c1 &&
9728
0
                            entry->c2 == entryRef->c2 &&
9729
0
                            entry->c3 == entryRef->c3)
9730
0
                        {
9731
0
                            pTranslationTable[i] =
9732
0
                                static_cast<unsigned char>(j);
9733
0
                            bMatchFound = true;
9734
0
                            break;
9735
0
                        }
9736
0
                    }
9737
0
                    if (!bMatchFound)
9738
0
                    {
9739
                        // No exact match. Looking for closest color now.
9740
0
                        int best_j = 0;
9741
0
                        int best_distance = 0;
9742
0
                        if (pApproximateMatching)
9743
0
                            *pApproximateMatching = TRUE;
9744
0
                        for (int j = 0; j < nRefEntries; ++j)
9745
0
                        {
9746
0
                            const GDALColorEntry *entryRef =
9747
0
                                destColorTable->GetColorEntry(j);
9748
0
                            int distance = (entry->c1 - entryRef->c1) *
9749
0
                                               (entry->c1 - entryRef->c1) +
9750
0
                                           (entry->c2 - entryRef->c2) *
9751
0
                                               (entry->c2 - entryRef->c2) +
9752
0
                                           (entry->c3 - entryRef->c3) *
9753
0
                                               (entry->c3 - entryRef->c3);
9754
0
                            if (j == 0 || distance < best_distance)
9755
0
                            {
9756
0
                                best_j = j;
9757
0
                                best_distance = distance;
9758
0
                            }
9759
0
                        }
9760
0
                        pTranslationTable[i] =
9761
0
                            static_cast<unsigned char>(best_j);
9762
0
                    }
9763
0
                }
9764
0
                if (bHasNoDataValueRef && bHasNoDataValueSrc)
9765
0
                    pTranslationTable[noDataValueSrc] =
9766
0
                        static_cast<unsigned char>(noDataValueRef);
9767
9768
0
                return pTranslationTable;
9769
0
            }
9770
0
        }
9771
0
    }
9772
0
    return nullptr;
9773
0
}
9774
9775
/************************************************************************/
9776
/*                         SetFlushBlockErr()                           */
9777
/************************************************************************/
9778
9779
/**
9780
 * \brief Store that an error occurred while writing a dirty block.
9781
 *
9782
 * This function stores the fact that an error occurred while writing a dirty
9783
 * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
9784
 * flushed when the block cache get full, it is not convenient/possible to
9785
 * report that a dirty block could not be written correctly. This function
9786
 * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
9787
 * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
9788
 * places where the user can easily match the error with the relevant dataset.
9789
 */
9790
9791
void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
9792
0
{
9793
0
    eFlushBlockErr = eErr;
9794
0
}
9795
9796
/************************************************************************/
9797
/*                         IncDirtyBlocks()                             */
9798
/************************************************************************/
9799
9800
/**
9801
 * \brief Increment/decrement the number of dirty blocks
9802
 */
9803
9804
void GDALRasterBand::IncDirtyBlocks(int nInc)
9805
0
{
9806
0
    if (poBandBlockCache)
9807
0
        poBandBlockCache->IncDirtyBlocks(nInc);
9808
0
}
9809
9810
/************************************************************************/
9811
/*                            ReportError()                             */
9812
/************************************************************************/
9813
9814
#ifndef DOXYGEN_XML
9815
/**
9816
 * \brief Emits an error related to a raster band.
9817
 *
9818
 * This function is a wrapper for regular CPLError(). The only difference
9819
 * with CPLError() is that it prepends the error message with the dataset
9820
 * name and the band number.
9821
 *
9822
 * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9823
 * @param err_no the error number (CPLE_*) from cpl_error.h.
9824
 * @param fmt a printf() style format string.  Any additional arguments
9825
 * will be treated as arguments to fill in this format in a manner
9826
 * similar to printf().
9827
 *
9828
 */
9829
9830
void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9831
                                 const char *fmt, ...) const
9832
0
{
9833
0
    va_list args;
9834
9835
0
    va_start(args, fmt);
9836
9837
0
    const char *pszDSName = poDS ? poDS->GetDescription() : "";
9838
0
    pszDSName = CPLGetFilename(pszDSName);
9839
0
    if (pszDSName[0] != '\0')
9840
0
    {
9841
0
        CPLError(eErrClass, err_no, "%s",
9842
0
                 CPLString()
9843
0
                     .Printf("%s, band %d: ", pszDSName, GetBand())
9844
0
                     .append(CPLString().vPrintf(fmt, args))
9845
0
                     .c_str());
9846
0
    }
9847
0
    else
9848
0
    {
9849
0
        CPLErrorV(eErrClass, err_no, fmt, args);
9850
0
    }
9851
9852
0
    va_end(args);
9853
0
}
9854
#endif
9855
9856
/************************************************************************/
9857
/*                           GetVirtualMemAuto()                        */
9858
/************************************************************************/
9859
9860
/** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9861
 *
9862
 * Only supported on Linux and Unix systems with mmap() for now.
9863
 *
9864
 * This method allows creating a virtual memory object for a GDALRasterBand,
9865
 * that exposes the whole image data as a virtual array.
9866
 *
9867
 * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9868
 * specialized implementation, such as for raw files, may also directly use
9869
 * mechanisms of the operating system to create a view of the underlying file
9870
 * into virtual memory ( CPLVirtualMemFileMapNew() )
9871
 *
9872
 * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9873
 * offer a specialized implementation with direct file mapping, provided that
9874
 * some requirements are met :
9875
 *   - for all drivers, the dataset must be backed by a "real" file in the file
9876
 *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9877
 *     must match the native ordering of the CPU.
9878
 *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9879
 * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9880
 * the file in sequential order, and be equally spaced (which is generally the
9881
 * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9882
 * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9883
 *
9884
 * The pointer returned remains valid until CPLVirtualMemFree() is called.
9885
 * CPLVirtualMemFree() must be called before the raster band object is
9886
 * destroyed.
9887
 *
9888
 * If p is such a pointer and base_type the type matching
9889
 * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9890
 * accessed with
9891
 * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9892
 *
9893
 * This method is the same as the C GDALGetVirtualMemAuto() function.
9894
 *
9895
 * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9896
 * read/write the band.
9897
 *
9898
 * @param pnPixelSpace Output parameter giving the byte offset from the start of
9899
 * one pixel value in the buffer to the start of the next pixel value within a
9900
 * scanline.
9901
 *
9902
 * @param pnLineSpace Output parameter giving the byte offset from the start of
9903
 * one scanline in the buffer to the start of the next.
9904
 *
9905
 * @param papszOptions NULL terminated list of options.
9906
 *                     If a specialized implementation exists, defining
9907
 * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9908
 * used. On the contrary, defining
9909
 * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9910
 * being used (thus only allowing efficient implementations to be used). When
9911
 * requiring or falling back to the default implementation, the following
9912
 *                     options are available : CACHE_SIZE (in bytes, defaults to
9913
 * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9914
 * to FALSE)
9915
 *
9916
 * @return a virtual memory object that must be unreferenced by
9917
 * CPLVirtualMemFree(), or NULL in case of failure.
9918
 *
9919
 */
9920
9921
CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9922
                                                 int *pnPixelSpace,
9923
                                                 GIntBig *pnLineSpace,
9924
                                                 char **papszOptions)
9925
0
{
9926
0
    const char *pszImpl = CSLFetchNameValueDef(
9927
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9928
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9929
0
        EQUAL(pszImpl, "FALSE"))
9930
0
    {
9931
0
        return nullptr;
9932
0
    }
9933
9934
0
    const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9935
0
    const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9936
0
    if (pnPixelSpace)
9937
0
        *pnPixelSpace = nPixelSpace;
9938
0
    if (pnLineSpace)
9939
0
        *pnLineSpace = nLineSpace;
9940
0
    const size_t nCacheSize =
9941
0
        atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9942
0
    const size_t nPageSizeHint =
9943
0
        atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9944
0
    const bool bSingleThreadUsage = CPLTestBool(
9945
0
        CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9946
0
    return GDALRasterBandGetVirtualMem(
9947
0
        GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9948
0
        nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9949
0
        nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9950
0
        papszOptions);
9951
0
}
9952
9953
/************************************************************************/
9954
/*                         GDALGetVirtualMemAuto()                      */
9955
/************************************************************************/
9956
9957
/**
9958
 * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9959
 *
9960
 * @see GDALRasterBand::GetVirtualMemAuto()
9961
 */
9962
9963
CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9964
                                     int *pnPixelSpace, GIntBig *pnLineSpace,
9965
                                     CSLConstList papszOptions)
9966
0
{
9967
0
    VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9968
9969
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9970
9971
0
    return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9972
0
                                     const_cast<char **>(papszOptions));
9973
0
}
9974
9975
/************************************************************************/
9976
/*                        GDALGetDataCoverageStatus()                   */
9977
/************************************************************************/
9978
9979
/**
9980
 * \brief Get the coverage status of a sub-window of the raster.
9981
 *
9982
 * Returns whether a sub-window of the raster contains only data, only empty
9983
 * blocks or a mix of both. This function can be used to determine quickly
9984
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9985
 * be sparse.
9986
 *
9987
 * Empty blocks are blocks that are generally not physically present in the
9988
 * file, and when read through GDAL, contain only pixels whose value is the
9989
 * nodata value when it is set, or whose value is 0 when the nodata value is
9990
 * not set.
9991
 *
9992
 * The query is done in an efficient way without reading the actual pixel
9993
 * values. If not possible, or not implemented at all by the driver,
9994
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9995
 * be returned.
9996
 *
9997
 * The values that can be returned by the function are the following,
9998
 * potentially combined with the binary or operator :
9999
 * <ul>
10000
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10001
 * GetDataCoverageStatus(). This flag should be returned together with
10002
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10003
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10004
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10005
 * the queried window. This is typically identified by the concept of missing
10006
 * block in formats that supports it.
10007
 * </li>
10008
 * </ul>
10009
 *
10010
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10011
 * should be interpreted more as hint of potential presence of data. For example
10012
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10013
 * nodata value), instead of using the missing block mechanism,
10014
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10015
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10016
 *
10017
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10018
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10019
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10020
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10021
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10022
 * the function will exit, so that you can potentially refine the requested area
10023
 * to find which particular region(s) have missing blocks.
10024
 *
10025
 * @see GDALRasterBand::GetDataCoverageStatus()
10026
 *
10027
 * @param hBand raster band
10028
 *
10029
 * @param nXOff The pixel offset to the top left corner of the region
10030
 * of the band to be queried. This would be zero to start from the left side.
10031
 *
10032
 * @param nYOff The line offset to the top left corner of the region
10033
 * of the band to be queried. This would be zero to start from the top.
10034
 *
10035
 * @param nXSize The width of the region of the band to be queried in pixels.
10036
 *
10037
 * @param nYSize The height of the region of the band to be queried in lines.
10038
 *
10039
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10040
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10041
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10042
 * as the computation of the coverage matches the mask, the computation will be
10043
 * stopped. *pdfDataPct will not be valid in that case.
10044
 *
10045
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10046
 * to the (approximate) percentage in [0,100] of pixels in the queried
10047
 * sub-window that have valid values. The implementation might not always be
10048
 * able to compute it, in which case it will be set to a negative value.
10049
 *
10050
 * @return a binary-or'ed combination of possible values
10051
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10052
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10053
 */
10054
10055
int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10056
                                          int nYOff, int nXSize, int nYSize,
10057
                                          int nMaskFlagStop, double *pdfDataPct)
10058
0
{
10059
0
    VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10060
0
                      GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10061
10062
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10063
10064
0
    return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10065
0
                                         nMaskFlagStop, pdfDataPct);
10066
0
}
10067
10068
/************************************************************************/
10069
/*                          GetDataCoverageStatus()                     */
10070
/************************************************************************/
10071
10072
/**
10073
 * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10074
 *                                           int nYOff,
10075
 *                                           int nXSize,
10076
 *                                           int nYSize,
10077
 *                                           int nMaskFlagStop,
10078
 *                                           double* pdfDataPct)
10079
 * \brief Get the coverage status of a sub-window of the raster.
10080
 *
10081
 * Returns whether a sub-window of the raster contains only data, only empty
10082
 * blocks or a mix of both. This function can be used to determine quickly
10083
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10084
 * be sparse.
10085
 *
10086
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10087
 * value when it is set, or whose value is 0 when the nodata value is not set.
10088
 *
10089
 * The query is done in an efficient way without reading the actual pixel
10090
 * values. If not possible, or not implemented at all by the driver,
10091
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10092
 * be returned.
10093
 *
10094
 * The values that can be returned by the function are the following,
10095
 * potentially combined with the binary or operator :
10096
 * <ul>
10097
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10098
 * GetDataCoverageStatus(). This flag should be returned together with
10099
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10100
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10101
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10102
 * the queried window. This is typically identified by the concept of missing
10103
 * block in formats that supports it.
10104
 * </li>
10105
 * </ul>
10106
 *
10107
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10108
 * should be interpreted more as hint of potential presence of data. For example
10109
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10110
 * nodata value), instead of using the missing block mechanism,
10111
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10112
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10113
 *
10114
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10115
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10116
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10117
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10118
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10119
 * the function will exit, so that you can potentially refine the requested area
10120
 * to find which particular region(s) have missing blocks.
10121
 *
10122
 * @see GDALGetDataCoverageStatus()
10123
 *
10124
 * @param nXOff The pixel offset to the top left corner of the region
10125
 * of the band to be queried. This would be zero to start from the left side.
10126
 *
10127
 * @param nYOff The line offset to the top left corner of the region
10128
 * of the band to be queried. This would be zero to start from the top.
10129
 *
10130
 * @param nXSize The width of the region of the band to be queried in pixels.
10131
 *
10132
 * @param nYSize The height of the region of the band to be queried in lines.
10133
 *
10134
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10135
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10136
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10137
 * as the computation of the coverage matches the mask, the computation will be
10138
 * stopped. *pdfDataPct will not be valid in that case.
10139
 *
10140
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10141
 * to the (approximate) percentage in [0,100] of pixels in the queried
10142
 * sub-window that have valid values. The implementation might not always be
10143
 * able to compute it, in which case it will be set to a negative value.
10144
 *
10145
 * @return a binary-or'ed combination of possible values
10146
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10147
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10148
 */
10149
10150
/**
10151
 * \brief Get the coverage status of a sub-window of the raster.
10152
 *
10153
 * Returns whether a sub-window of the raster contains only data, only empty
10154
 * blocks or a mix of both. This function can be used to determine quickly
10155
 * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10156
 * be sparse.
10157
 *
10158
 * Empty blocks are blocks that contain only pixels whose value is the nodata
10159
 * value when it is set, or whose value is 0 when the nodata value is not set.
10160
 *
10161
 * The query is done in an efficient way without reading the actual pixel
10162
 * values. If not possible, or not implemented at all by the driver,
10163
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10164
 * be returned.
10165
 *
10166
 * The values that can be returned by the function are the following,
10167
 * potentially combined with the binary or operator :
10168
 * <ul>
10169
 * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10170
 * GetDataCoverageStatus(). This flag should be returned together with
10171
 * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10172
 * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10173
 * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10174
 * the queried window. This is typically identified by the concept of missing
10175
 * block in formats that supports it.
10176
 * </li>
10177
 * </ul>
10178
 *
10179
 * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10180
 * should be interpreted more as hint of potential presence of data. For example
10181
 * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10182
 * nodata value), instead of using the missing block mechanism,
10183
 * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10184
 * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10185
 *
10186
 * The nMaskFlagStop should be generally set to 0. It can be set to a
10187
 * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10188
 * the function as soon as the computed mask matches the nMaskFlagStop. For
10189
 * example, you can issue a request on the whole raster with nMaskFlagStop =
10190
 * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10191
 * the function will exit, so that you can potentially refine the requested area
10192
 * to find which particular region(s) have missing blocks.
10193
 *
10194
 * @see GDALGetDataCoverageStatus()
10195
 *
10196
 * @param nXOff The pixel offset to the top left corner of the region
10197
 * of the band to be queried. This would be zero to start from the left side.
10198
 *
10199
 * @param nYOff The line offset to the top left corner of the region
10200
 * of the band to be queried. This would be zero to start from the top.
10201
 *
10202
 * @param nXSize The width of the region of the band to be queried in pixels.
10203
 *
10204
 * @param nYSize The height of the region of the band to be queried in lines.
10205
 *
10206
 * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10207
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10208
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10209
 * as the computation of the coverage matches the mask, the computation will be
10210
 * stopped. *pdfDataPct will not be valid in that case.
10211
 *
10212
 * @param pdfDataPct Optional output parameter whose pointed value will be set
10213
 * to the (approximate) percentage in [0,100] of pixels in the queried
10214
 * sub-window that have valid values. The implementation might not always be
10215
 * able to compute it, in which case it will be set to a negative value.
10216
 *
10217
 * @return a binary-or'ed combination of possible values
10218
 * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10219
 * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10220
 */
10221
10222
int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10223
                                          int nYSize, int nMaskFlagStop,
10224
                                          double *pdfDataPct)
10225
0
{
10226
0
    if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
10227
0
        nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
10228
0
        nYOff + nYSize > nRasterYSize)
10229
0
    {
10230
0
        CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10231
0
        if (pdfDataPct)
10232
0
            *pdfDataPct = 0.0;
10233
0
        return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10234
0
               GDAL_DATA_COVERAGE_STATUS_EMPTY;
10235
0
    }
10236
0
    return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10237
0
                                  pdfDataPct);
10238
0
}
10239
10240
/************************************************************************/
10241
/*                         IGetDataCoverageStatus()                     */
10242
/************************************************************************/
10243
10244
int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10245
                                           int /*nXSize*/, int /*nYSize*/,
10246
                                           int /*nMaskFlagStop*/,
10247
                                           double *pdfDataPct)
10248
0
{
10249
0
    if (pdfDataPct != nullptr)
10250
0
        *pdfDataPct = 100.0;
10251
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10252
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
10253
0
}
10254
10255
//! @cond Doxygen_Suppress
10256
/************************************************************************/
10257
/*                          EnterReadWrite()                            */
10258
/************************************************************************/
10259
10260
int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10261
0
{
10262
0
    if (poDS != nullptr)
10263
0
        return poDS->EnterReadWrite(eRWFlag);
10264
0
    return FALSE;
10265
0
}
10266
10267
/************************************************************************/
10268
/*                         LeaveReadWrite()                             */
10269
/************************************************************************/
10270
10271
void GDALRasterBand::LeaveReadWrite()
10272
0
{
10273
0
    if (poDS != nullptr)
10274
0
        poDS->LeaveReadWrite();
10275
0
}
10276
10277
/************************************************************************/
10278
/*                           InitRWLock()                               */
10279
/************************************************************************/
10280
10281
void GDALRasterBand::InitRWLock()
10282
0
{
10283
0
    if (poDS != nullptr)
10284
0
        poDS->InitRWLock();
10285
0
}
10286
10287
//! @endcond
10288
10289
// clang-format off
10290
10291
/**
10292
 * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10293
 * \brief Set metadata.
10294
 *
10295
 * CAUTION: depending on the format, older values of the updated information
10296
 * might still be found in the file in a "ghost" state, even if no longer
10297
 * accessible through the GDAL API. This is for example the case of the GTiff
10298
 * format (this is not a exhaustive list)
10299
 *
10300
 * The C function GDALSetMetadata() does the same thing as this method.
10301
 *
10302
 * @param papszMetadata the metadata in name=value string list format to
10303
 * apply.
10304
 * @param pszDomain the domain of interest.  Use "" or NULL for the default
10305
 * domain.
10306
 * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10307
 * metadata has been accepted, but is likely not maintained persistently
10308
 * by the underlying object between sessions.
10309
 */
10310
10311
/**
10312
 * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10313
 * \brief Set single metadata item.
10314
 *
10315
 * CAUTION: depending on the format, older values of the updated information
10316
 * might still be found in the file in a "ghost" state, even if no longer
10317
 * accessible through the GDAL API. This is for example the case of the GTiff
10318
 * format (this is not a exhaustive list)
10319
 *
10320
 * The C function GDALSetMetadataItem() does the same thing as this method.
10321
 *
10322
 * @param pszName the key for the metadata item to fetch.
10323
 * @param pszValue the value to assign to the key.
10324
 * @param pszDomain the domain to set within, use NULL for the default domain.
10325
 *
10326
 * @return CE_None on success, or an error code on failure.
10327
 */
10328
10329
// clang-format on
10330
10331
//! @cond Doxygen_Suppress
10332
/************************************************************************/
10333
/*                    EnablePixelTypeSignedByteWarning()                */
10334
/************************************************************************/
10335
10336
void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10337
0
{
10338
0
    m_bEnablePixelTypeSignedByteWarning = b;
10339
0
}
10340
10341
void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10342
0
{
10343
0
    GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10344
0
}
10345
10346
//! @endcond
10347
10348
/************************************************************************/
10349
/*                           GetMetadataItem()                          */
10350
/************************************************************************/
10351
10352
const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10353
                                            const char *pszDomain)
10354
0
{
10355
    // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10356
0
    if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10357
0
        pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10358
0
        EQUAL(pszName, "PIXELTYPE"))
10359
0
    {
10360
0
        CPLError(CE_Warning, CPLE_AppDefined,
10361
0
                 "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10362
0
                 "used to signal signed 8-bit raster. Change your code to "
10363
0
                 "test for the new GDT_Int8 data type instead.");
10364
0
    }
10365
0
    return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10366
0
}
10367
10368
/************************************************************************/
10369
/*                            WindowIterator                            */
10370
/************************************************************************/
10371
10372
//! @cond Doxygen_Suppress
10373
10374
GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10375
                                               int nRasterYSize,
10376
                                               int nBlockXSize, int nBlockYSize,
10377
                                               int nRow, int nCol)
10378
0
    : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10379
0
      m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10380
0
      m_col(nCol)
10381
0
{
10382
0
}
10383
10384
bool GDALRasterBand::WindowIterator::operator==(
10385
    const WindowIterator &other) const
10386
0
{
10387
0
    return m_row == other.m_row && m_col == other.m_col &&
10388
0
           m_nRasterXSize == other.m_nRasterXSize &&
10389
0
           m_nRasterYSize == other.m_nRasterYSize &&
10390
0
           m_nBlockXSize == other.m_nBlockXSize &&
10391
0
           m_nBlockYSize == other.m_nBlockYSize;
10392
0
}
10393
10394
bool GDALRasterBand::WindowIterator::operator!=(
10395
    const WindowIterator &other) const
10396
0
{
10397
0
    return !(*this == other);
10398
0
}
10399
10400
GDALRasterBand::WindowIterator::value_type
10401
GDALRasterBand::WindowIterator::operator*() const
10402
0
{
10403
0
    GDALRasterWindow ret;
10404
0
    ret.nXOff = m_col * m_nBlockXSize;
10405
0
    ret.nYOff = m_row * m_nBlockYSize;
10406
0
    ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10407
0
    ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10408
10409
0
    return ret;
10410
0
}
10411
10412
GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10413
0
{
10414
0
    m_col++;
10415
0
    if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10416
0
    {
10417
0
        m_col = 0;
10418
0
        m_row++;
10419
0
    }
10420
0
    return *this;
10421
0
}
10422
10423
GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10424
    const GDALRasterBand &band, size_t maxSize)
10425
0
    : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
10426
0
      m_nBlockXSize(-1), m_nBlockYSize(-1)
10427
0
{
10428
#ifdef CSA_BUILD
10429
    assert(this);
10430
#endif
10431
0
    int nXSize, nYSize;
10432
10433
0
    CPLErrorStateBackuper state(CPLQuietErrorHandler);
10434
0
    band.GetBlockSize(&nXSize, &nYSize);
10435
0
    if (nXSize < 1 || nYSize < 0)
10436
0
    {
10437
        // If invalid block size is reported, assume scanlines
10438
0
        nXSize = m_nRasterXSize;
10439
0
        nYSize = 1;
10440
0
    }
10441
10442
0
    if (maxSize == 0)
10443
0
    {
10444
0
        m_nBlockXSize = nXSize;
10445
0
        m_nBlockYSize = nYSize;
10446
0
        return;
10447
0
    }
10448
10449
0
    const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10450
0
    const double dfBlocksPerChunk =
10451
0
        static_cast<double>(maxSize) /
10452
0
        (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10453
10454
0
    if (dfBlocksPerChunk < dfBlocksPerRow)
10455
0
    {
10456
0
        m_nBlockXSize = static_cast<int>(std::min<double>(
10457
0
            m_nRasterXSize,
10458
0
            nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10459
0
        m_nBlockYSize = nYSize;
10460
0
    }
10461
0
    else
10462
0
    {
10463
0
        m_nBlockXSize = m_nRasterXSize;
10464
0
        m_nBlockYSize = static_cast<int>(std::min<double>(
10465
0
            m_nRasterYSize,
10466
0
            nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10467
0
    }
10468
    if constexpr (sizeof(size_t) < sizeof(uint64_t))
10469
    {
10470
        if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10471
        {
10472
            nXSize = m_nRasterXSize;
10473
            nYSize = 1;
10474
        }
10475
    }
10476
0
}
10477
10478
GDALRasterBand::WindowIterator
10479
GDALRasterBand::WindowIteratorWrapper::begin() const
10480
0
{
10481
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10482
0
                          m_nBlockYSize, 0, 0);
10483
0
}
10484
10485
GDALRasterBand::WindowIterator
10486
GDALRasterBand::WindowIteratorWrapper::end() const
10487
0
{
10488
0
    return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10489
0
                          m_nBlockYSize,
10490
0
                          DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10491
0
}
10492
10493
uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10494
0
{
10495
0
    return static_cast<uint64_t>(
10496
0
               cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10497
0
           static_cast<uint64_t>(
10498
0
               cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10499
0
}
10500
10501
//! @endcond
10502
10503
/** Return an object whose begin() and end() methods can be used to iterate
10504
 *  over GDALRasterWindow objects that are aligned with blocks in this raster
10505
 *  band. The iteration order is from left to right, then from top to bottom.
10506
 *
10507
\code{.cpp}
10508
    std::vector<double> pixelValues;
10509
    for (const auto& window : poBand->IterateWindows()) {
10510
        CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10511
                                         window.nXSize, window.nYSize);
10512
        // check eErr
10513
    }
10514
\endcode
10515
 *
10516
 *
10517
 *  @param maxSize The maximum number of pixels in each window. If set to
10518
 *         zero (the default), or a number smaller than the block size,
10519
 *         the window size will be the same as the block size.
10520
 *  @since GDAL 3.12
10521
 */
10522
GDALRasterBand::WindowIteratorWrapper
10523
GDALRasterBand::IterateWindows(size_t maxSize) const
10524
0
{
10525
0
    return WindowIteratorWrapper(*this, maxSize);
10526
0
}
10527
10528
/************************************************************************/
10529
/*                     GDALMDArrayFromRasterBand                        */
10530
/************************************************************************/
10531
10532
class GDALMDArrayFromRasterBand final : public GDALMDArray
10533
{
10534
    CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10535
10536
    GDALDataset *m_poDS;
10537
    GDALRasterBand *m_poBand;
10538
    GDALExtendedDataType m_dt;
10539
    std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10540
    std::string m_osUnit;
10541
    std::vector<GByte> m_pabyNoData{};
10542
    std::shared_ptr<GDALMDArray> m_varX{};
10543
    std::shared_ptr<GDALMDArray> m_varY{};
10544
    std::string m_osFilename{};
10545
10546
    bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10547
                   const size_t *count, const GInt64 *arrayStep,
10548
                   const GPtrDiff_t *bufferStride,
10549
                   const GDALExtendedDataType &bufferDataType,
10550
                   void *pBuffer) const;
10551
10552
  protected:
10553
    GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10554
0
        : GDALAbstractMDArray(std::string(),
10555
0
                              std::string(poDS->GetDescription()) +
10556
0
                                  CPLSPrintf(" band %d", poBand->GetBand())),
10557
0
          GDALMDArray(std::string(),
10558
0
                      std::string(poDS->GetDescription()) +
10559
0
                          CPLSPrintf(" band %d", poBand->GetBand())),
10560
0
          m_poDS(poDS), m_poBand(poBand),
10561
0
          m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10562
0
          m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10563
0
    {
10564
0
        m_poDS->Reference();
10565
10566
0
        int bHasNoData = false;
10567
0
        if (m_poBand->GetRasterDataType() == GDT_Int64)
10568
0
        {
10569
0
            const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10570
0
            if (bHasNoData)
10571
0
            {
10572
0
                m_pabyNoData.resize(m_dt.GetSize());
10573
0
                GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10574
0
                                m_dt.GetNumericDataType(), 0, 1);
10575
0
            }
10576
0
        }
10577
0
        else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10578
0
        {
10579
0
            const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10580
0
            if (bHasNoData)
10581
0
            {
10582
0
                m_pabyNoData.resize(m_dt.GetSize());
10583
0
                GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10584
0
                                m_dt.GetNumericDataType(), 0, 1);
10585
0
            }
10586
0
        }
10587
0
        else
10588
0
        {
10589
0
            const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10590
0
            if (bHasNoData)
10591
0
            {
10592
0
                m_pabyNoData.resize(m_dt.GetSize());
10593
0
                GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10594
0
                                m_dt.GetNumericDataType(), 0, 1);
10595
0
            }
10596
0
        }
10597
10598
0
        const int nXSize = poBand->GetXSize();
10599
0
        const int nYSize = poBand->GetYSize();
10600
10601
0
        auto poSRS = m_poDS->GetSpatialRef();
10602
0
        std::string osTypeY;
10603
0
        std::string osTypeX;
10604
0
        std::string osDirectionY;
10605
0
        std::string osDirectionX;
10606
0
        if (poSRS && poSRS->GetAxesCount() == 2)
10607
0
        {
10608
0
            const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10609
0
            OGRAxisOrientation eOrientation1 = OAO_Other;
10610
0
            poSRS->GetAxis(nullptr, 0, &eOrientation1);
10611
0
            OGRAxisOrientation eOrientation2 = OAO_Other;
10612
0
            poSRS->GetAxis(nullptr, 1, &eOrientation2);
10613
0
            if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10614
0
            {
10615
0
                if (mapping == std::vector<int>{1, 2})
10616
0
                {
10617
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10618
0
                    osDirectionY = "NORTH";
10619
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10620
0
                    osDirectionX = "EAST";
10621
0
                }
10622
0
            }
10623
0
            else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
10624
0
            {
10625
0
                if (mapping == std::vector<int>{2, 1})
10626
0
                {
10627
0
                    osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10628
0
                    osDirectionY = "NORTH";
10629
0
                    osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10630
0
                    osDirectionX = "EAST";
10631
0
                }
10632
0
            }
10633
0
        }
10634
10635
0
        m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
10636
0
                      "/", "Y", osTypeY, osDirectionY, nYSize),
10637
0
                  std::make_shared<GDALDimensionWeakIndexingVar>(
10638
0
                      "/", "X", osTypeX, osDirectionX, nXSize)};
10639
10640
0
        GDALGeoTransform gt;
10641
0
        if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
10642
0
        {
10643
0
            m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
10644
0
                                                        gt[0], gt[1], 0.5);
10645
0
            m_dims[1]->SetIndexingVariable(m_varX);
10646
10647
0
            m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
10648
0
                                                        gt[3], gt[5], 0.5);
10649
0
            m_dims[0]->SetIndexingVariable(m_varY);
10650
0
        }
10651
0
    }
10652
10653
    bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
10654
               const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10655
               const GDALExtendedDataType &bufferDataType,
10656
               void *pDstBuffer) const override;
10657
10658
    bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
10659
                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10660
                const GDALExtendedDataType &bufferDataType,
10661
                const void *pSrcBuffer) override
10662
0
    {
10663
0
        return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
10664
0
                         bufferStride, bufferDataType,
10665
0
                         const_cast<void *>(pSrcBuffer));
10666
0
    }
10667
10668
  public:
10669
    ~GDALMDArrayFromRasterBand() override
10670
0
    {
10671
0
        m_poDS->ReleaseRef();
10672
0
    }
10673
10674
    static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
10675
                                               GDALRasterBand *poBand)
10676
0
    {
10677
0
        auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
10678
0
            new GDALMDArrayFromRasterBand(poDS, poBand)));
10679
0
        array->SetSelf(array);
10680
0
        return array;
10681
0
    }
10682
10683
    bool IsWritable() const override
10684
0
    {
10685
0
        return m_poDS->GetAccess() == GA_Update;
10686
0
    }
10687
10688
    const std::string &GetFilename() const override
10689
0
    {
10690
0
        return m_osFilename;
10691
0
    }
10692
10693
    const std::vector<std::shared_ptr<GDALDimension>> &
10694
    GetDimensions() const override
10695
0
    {
10696
0
        return m_dims;
10697
0
    }
10698
10699
    const GDALExtendedDataType &GetDataType() const override
10700
0
    {
10701
0
        return m_dt;
10702
0
    }
10703
10704
    const std::string &GetUnit() const override
10705
0
    {
10706
0
        return m_osUnit;
10707
0
    }
10708
10709
    const void *GetRawNoDataValue() const override
10710
0
    {
10711
0
        return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
10712
0
    }
10713
10714
    double GetOffset(bool *pbHasOffset,
10715
                     GDALDataType *peStorageType) const override
10716
0
    {
10717
0
        int bHasOffset = false;
10718
0
        double dfRes = m_poBand->GetOffset(&bHasOffset);
10719
0
        if (pbHasOffset)
10720
0
            *pbHasOffset = CPL_TO_BOOL(bHasOffset);
10721
0
        if (peStorageType)
10722
0
            *peStorageType = GDT_Unknown;
10723
0
        return dfRes;
10724
0
    }
10725
10726
    double GetScale(bool *pbHasScale,
10727
                    GDALDataType *peStorageType) const override
10728
0
    {
10729
0
        int bHasScale = false;
10730
0
        double dfRes = m_poBand->GetScale(&bHasScale);
10731
0
        if (pbHasScale)
10732
0
            *pbHasScale = CPL_TO_BOOL(bHasScale);
10733
0
        if (peStorageType)
10734
0
            *peStorageType = GDT_Unknown;
10735
0
        return dfRes;
10736
0
    }
10737
10738
    std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
10739
0
    {
10740
0
        auto poSrcSRS = m_poDS->GetSpatialRef();
10741
0
        if (!poSrcSRS)
10742
0
            return nullptr;
10743
0
        auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
10744
10745
0
        auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
10746
0
        constexpr int iYDim = 0;
10747
0
        constexpr int iXDim = 1;
10748
0
        for (auto &m : axisMapping)
10749
0
        {
10750
0
            if (m == 1)
10751
0
                m = iXDim + 1;
10752
0
            else if (m == 2)
10753
0
                m = iYDim + 1;
10754
0
            else
10755
0
                m = 0;
10756
0
        }
10757
0
        poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
10758
0
        return poSRS;
10759
0
    }
10760
10761
    std::vector<GUInt64> GetBlockSize() const override
10762
0
    {
10763
0
        int nBlockXSize = 0;
10764
0
        int nBlockYSize = 0;
10765
0
        m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
10766
0
        return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
10767
0
                                    static_cast<GUInt64>(nBlockXSize)};
10768
0
    }
10769
10770
    std::vector<std::shared_ptr<GDALAttribute>>
10771
    GetAttributes(CSLConstList) const override
10772
0
    {
10773
0
        std::vector<std::shared_ptr<GDALAttribute>> res;
10774
0
        auto papszMD = m_poBand->GetMetadata();
10775
0
        for (auto iter = papszMD; iter && iter[0]; ++iter)
10776
0
        {
10777
0
            char *pszKey = nullptr;
10778
0
            const char *pszValue = CPLParseNameValue(*iter, &pszKey);
10779
0
            if (pszKey && pszValue)
10780
0
            {
10781
0
                res.emplace_back(
10782
0
                    std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
10783
0
            }
10784
0
            CPLFree(pszKey);
10785
0
        }
10786
0
        return res;
10787
0
    }
10788
};
10789
10790
bool GDALMDArrayFromRasterBand::IRead(
10791
    const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
10792
    const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
10793
    void *pDstBuffer) const
10794
0
{
10795
0
    return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
10796
0
                     bufferDataType, pDstBuffer);
10797
0
}
10798
10799
/************************************************************************/
10800
/*                            ReadWrite()                               */
10801
/************************************************************************/
10802
10803
bool GDALMDArrayFromRasterBand::ReadWrite(
10804
    GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10805
    const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10806
    const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10807
0
{
10808
0
    constexpr size_t iDimX = 1;
10809
0
    constexpr size_t iDimY = 0;
10810
0
    return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10811
0
                                  arrayStartIdx, count, arrayStep, bufferStride,
10812
0
                                  bufferDataType, pBuffer);
10813
0
}
10814
10815
/************************************************************************/
10816
/*                       GDALMDRasterIOFromBand()                       */
10817
/************************************************************************/
10818
10819
bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10820
                            size_t iDimX, size_t iDimY,
10821
                            const GUInt64 *arrayStartIdx, const size_t *count,
10822
                            const GInt64 *arrayStep,
10823
                            const GPtrDiff_t *bufferStride,
10824
                            const GDALExtendedDataType &bufferDataType,
10825
                            void *pBuffer)
10826
0
{
10827
0
    const auto eDT(bufferDataType.GetNumericDataType());
10828
0
    const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10829
0
    const int nX =
10830
0
        arrayStep[iDimX] > 0
10831
0
            ? static_cast<int>(arrayStartIdx[iDimX])
10832
0
            : static_cast<int>(arrayStartIdx[iDimX] -
10833
0
                               (count[iDimX] - 1) * -arrayStep[iDimX]);
10834
0
    const int nY =
10835
0
        arrayStep[iDimY] > 0
10836
0
            ? static_cast<int>(arrayStartIdx[iDimY])
10837
0
            : static_cast<int>(arrayStartIdx[iDimY] -
10838
0
                               (count[iDimY] - 1) * -arrayStep[iDimY]);
10839
0
    const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10840
0
    const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10841
0
    GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10842
0
    int nStrideXSign = 1;
10843
0
    if (arrayStep[iDimX] < 0)
10844
0
    {
10845
0
        pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10846
0
        nStrideXSign = -1;
10847
0
    }
10848
0
    int nStrideYSign = 1;
10849
0
    if (arrayStep[iDimY] < 0)
10850
0
    {
10851
0
        pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10852
0
        nStrideYSign = -1;
10853
0
    }
10854
10855
0
    return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10856
0
                            static_cast<int>(count[iDimX]),
10857
0
                            static_cast<int>(count[iDimY]), eDT,
10858
0
                            static_cast<GSpacing>(
10859
0
                                nStrideXSign * bufferStride[iDimX] * nDTSize),
10860
0
                            static_cast<GSpacing>(
10861
0
                                nStrideYSign * bufferStride[iDimY] * nDTSize),
10862
0
                            nullptr) == CE_None;
10863
0
}
10864
10865
/************************************************************************/
10866
/*                            AsMDArray()                               */
10867
/************************************************************************/
10868
10869
/** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10870
 *
10871
 * The band must be linked to a GDALDataset. If this dataset is not already
10872
 * marked as shared, it will be, so that the returned array holds a reference
10873
 * to it.
10874
 *
10875
 * If the dataset has a geotransform attached, the X and Y dimensions of the
10876
 * returned array will have an associated indexing variable.
10877
 *
10878
 * This is the same as the C function GDALRasterBandAsMDArray().
10879
 *
10880
 * The "reverse" method is GDALMDArray::AsClassicDataset().
10881
 *
10882
 * @return a new array, or nullptr.
10883
 *
10884
 * @since GDAL 3.1
10885
 */
10886
std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10887
0
{
10888
0
    if (!poDS)
10889
0
    {
10890
0
        CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10891
0
        return nullptr;
10892
0
    }
10893
0
    if (!poDS->GetShared())
10894
0
    {
10895
0
        poDS->MarkAsShared();
10896
0
    }
10897
0
    return GDALMDArrayFromRasterBand::Create(
10898
0
        poDS, const_cast<GDALRasterBand *>(this));
10899
0
}
10900
10901
/************************************************************************/
10902
/*                             InterpolateAtPoint()                     */
10903
/************************************************************************/
10904
10905
/**
10906
 * \brief Interpolates the value between pixels using a resampling algorithm,
10907
 * taking pixel/line coordinates as input.
10908
 *
10909
 * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10910
 * @param dfLine line coordinate as a double, where interpolation should be done.
10911
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10912
 * @param pdfRealValue pointer to real part of interpolated value
10913
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10914
 *
10915
 * @return CE_None on success, or an error code on failure.
10916
 * @since GDAL 3.10
10917
 */
10918
10919
CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10920
                                          GDALRIOResampleAlg eInterpolation,
10921
                                          double *pdfRealValue,
10922
                                          double *pdfImagValue) const
10923
0
{
10924
0
    if (eInterpolation != GRIORA_NearestNeighbour &&
10925
0
        eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10926
0
        eInterpolation != GRIORA_CubicSpline)
10927
0
    {
10928
0
        CPLError(CE_Failure, CPLE_AppDefined,
10929
0
                 "Only nearest, bilinear, cubic and cubicspline interpolation "
10930
0
                 "methods "
10931
0
                 "allowed");
10932
10933
0
        return CE_Failure;
10934
0
    }
10935
10936
0
    GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10937
0
    if (!m_poPointsCache)
10938
0
        m_poPointsCache = new GDALDoublePointsCache();
10939
10940
0
    const bool res =
10941
0
        GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10942
0
                               dfPixel, dfLine, pdfRealValue, pdfImagValue);
10943
10944
0
    return res ? CE_None : CE_Failure;
10945
0
}
10946
10947
/************************************************************************/
10948
/*                        GDALRasterInterpolateAtPoint()                */
10949
/************************************************************************/
10950
10951
/**
10952
 * \brief Interpolates the value between pixels using
10953
 * a resampling algorithm
10954
 *
10955
 * @see GDALRasterBand::InterpolateAtPoint()
10956
 * @since GDAL 3.10
10957
 */
10958
10959
CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10960
                                    double dfLine,
10961
                                    GDALRIOResampleAlg eInterpolation,
10962
                                    double *pdfRealValue, double *pdfImagValue)
10963
0
{
10964
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10965
10966
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10967
0
    return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10968
0
                                      pdfRealValue, pdfImagValue);
10969
0
}
10970
10971
/************************************************************************/
10972
/*                    InterpolateAtGeolocation()                        */
10973
/************************************************************************/
10974
10975
/**
10976
 * \brief Interpolates the value between pixels using a resampling algorithm,
10977
 * taking georeferenced coordinates as input.
10978
 *
10979
 * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10980
 * must be in the "natural" SRS of the dataset, that is the one returned by
10981
 * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10982
 * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10983
 * array (generally WGS 84) if there is a geolocation array.
10984
 * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10985
 * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10986
 * be a easting, and dfGeolocY a northing.
10987
 *
10988
 * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10989
 * expressed in that CRS, and that tuple must be conformant with the
10990
 * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10991
 * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10992
 * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10993
 * before calling this method, and in that case, dfGeolocX must be a longitude
10994
 * or an easting value, and dfGeolocX a latitude or a northing value.
10995
 *
10996
 * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10997
 * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10998
 * it for details on how that transformation is done.
10999
 *
11000
 * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11001
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11002
 * where interpolation should be done.
11003
 * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11004
 * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11005
 * where interpolation should be done.
11006
 * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11007
 * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11008
 * @param pdfRealValue pointer to real part of interpolated value
11009
 * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11010
 * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11011
 *
11012
 * @return CE_None on success, or an error code on failure.
11013
 * @since GDAL 3.11
11014
 */
11015
11016
CPLErr GDALRasterBand::InterpolateAtGeolocation(
11017
    double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11018
    GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11019
    double *pdfImagValue, CSLConstList papszTransformerOptions) const
11020
0
{
11021
0
    double dfPixel;
11022
0
    double dfLine;
11023
0
    if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11024
0
                                     &dfLine,
11025
0
                                     papszTransformerOptions) != CE_None)
11026
0
    {
11027
0
        return CE_Failure;
11028
0
    }
11029
0
    return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11030
0
                              pdfImagValue);
11031
0
}
11032
11033
/************************************************************************/
11034
/*                  GDALRasterInterpolateAtGeolocation()                */
11035
/************************************************************************/
11036
11037
/**
11038
 * \brief Interpolates the value between pixels using a resampling algorithm,
11039
 * taking georeferenced coordinates as input.
11040
 *
11041
 * @see GDALRasterBand::InterpolateAtGeolocation()
11042
 * @since GDAL 3.11
11043
 */
11044
11045
CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11046
                                          double dfGeolocX, double dfGeolocY,
11047
                                          OGRSpatialReferenceH hSRS,
11048
                                          GDALRIOResampleAlg eInterpolation,
11049
                                          double *pdfRealValue,
11050
                                          double *pdfImagValue,
11051
                                          CSLConstList papszTransformerOptions)
11052
0
{
11053
0
    VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11054
11055
0
    GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11056
0
    return poBand->InterpolateAtGeolocation(
11057
0
        dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11058
0
        eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11059
0
}
11060
11061
/************************************************************************/
11062
/*                    GDALRasterBand::SplitRasterIO()                   */
11063
/************************************************************************/
11064
11065
//! @cond Doxygen_Suppress
11066
11067
/** Implements IRasterIO() by dividing the request in 2.
11068
 *
11069
 * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11070
 *
11071
 * Return CE_Warning if the split could not be done, CE_None in case of
11072
 * success and CE_Failure in case of error.
11073
 *
11074
 * @since 3.12
11075
 */
11076
CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11077
                                     [[maybe_unused]] int nXSize,
11078
                                     [[maybe_unused]] int nYSize, void *pData,
11079
                                     int nBufXSize, int nBufYSize,
11080
                                     GDALDataType eBufType,
11081
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
11082
                                     GDALRasterIOExtraArg *psExtraArg)
11083
0
{
11084
0
    CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11085
11086
0
    GByte *pabyData = static_cast<GByte *>(pData);
11087
0
    if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11088
0
    {
11089
0
        GDALRasterIOExtraArg sArg;
11090
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11091
0
        const int nHalfHeight = nBufYSize / 2;
11092
11093
0
        sArg.pfnProgress = GDALScaledProgress;
11094
0
        sArg.pProgressData = GDALCreateScaledProgress(
11095
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11096
0
        if (sArg.pProgressData == nullptr)
11097
0
            sArg.pfnProgress = nullptr;
11098
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11099
0
                                pabyData, nBufXSize, nHalfHeight, eBufType,
11100
0
                                nPixelSpace, nLineSpace, &sArg);
11101
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11102
11103
0
        if (eErr == CE_None)
11104
0
        {
11105
0
            sArg.pfnProgress = GDALScaledProgress;
11106
0
            sArg.pProgressData = GDALCreateScaledProgress(
11107
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11108
0
            if (sArg.pProgressData == nullptr)
11109
0
                sArg.pfnProgress = nullptr;
11110
0
            eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11111
0
                             nBufYSize - nHalfHeight,
11112
0
                             pabyData + nHalfHeight * nLineSpace, nBufXSize,
11113
0
                             nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11114
0
                             nLineSpace, &sArg);
11115
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11116
0
        }
11117
0
        return eErr;
11118
0
    }
11119
0
    else if (nBufXSize >= 2)
11120
0
    {
11121
0
        GDALRasterIOExtraArg sArg;
11122
0
        INIT_RASTERIO_EXTRA_ARG(sArg);
11123
0
        const int nHalfWidth = nBufXSize / 2;
11124
11125
0
        sArg.pfnProgress = GDALScaledProgress;
11126
0
        sArg.pProgressData = GDALCreateScaledProgress(
11127
0
            0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11128
0
        if (sArg.pProgressData == nullptr)
11129
0
            sArg.pfnProgress = nullptr;
11130
0
        CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11131
0
                                pabyData, nHalfWidth, nBufYSize, eBufType,
11132
0
                                nPixelSpace, nLineSpace, &sArg);
11133
0
        GDALDestroyScaledProgress(sArg.pProgressData);
11134
11135
0
        if (eErr == CE_None)
11136
0
        {
11137
0
            sArg.pfnProgress = GDALScaledProgress;
11138
0
            sArg.pProgressData = GDALCreateScaledProgress(
11139
0
                0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11140
0
            if (sArg.pProgressData == nullptr)
11141
0
                sArg.pfnProgress = nullptr;
11142
0
            eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11143
0
                             nBufXSize - nHalfWidth, nBufYSize,
11144
0
                             pabyData + nHalfWidth * nPixelSpace,
11145
0
                             nBufXSize - nHalfWidth, nBufYSize, eBufType,
11146
0
                             nPixelSpace, nLineSpace, &sArg);
11147
0
            GDALDestroyScaledProgress(sArg.pProgressData);
11148
0
        }
11149
0
        return eErr;
11150
0
    }
11151
11152
0
    return CE_Warning;
11153
0
}
11154
11155
//! @endcond
11156
11157
/************************************************************************/
11158
/*                         ThrowIfNotSameDimensions()                   */
11159
/************************************************************************/
11160
11161
//! @cond Doxygen_Suppress
11162
/* static */
11163
void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11164
                                              const GDALRasterBand &second)
11165
0
{
11166
0
    if (first.GetXSize() != second.GetXSize() ||
11167
0
        first.GetYSize() != second.GetYSize())
11168
0
    {
11169
0
        throw std::runtime_error("Bands do not have the same dimensions");
11170
0
    }
11171
0
}
11172
11173
//! @endcond
11174
11175
/************************************************************************/
11176
/*                          GDALRasterBandUnaryOp()                     */
11177
/************************************************************************/
11178
11179
/** Apply a unary operation on this band.
11180
 *
11181
 * The resulting band is lazy evaluated. A reference is taken on the input
11182
 * dataset.
11183
 *
11184
 * @since 3.12
11185
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11186
 */
11187
GDALComputedRasterBandH
11188
GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11189
                      GDALRasterAlgebraUnaryOperation eOp)
11190
0
{
11191
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11192
0
    GDALComputedRasterBand::Operation cppOp{};
11193
0
    switch (eOp)
11194
0
    {
11195
0
        case GRAUO_LOGICAL_NOT:
11196
0
            return new GDALComputedRasterBand(
11197
0
                GDALComputedRasterBand::Operation::OP_NE,
11198
0
                *(GDALRasterBand::FromHandle(hBand)), true);
11199
0
        case GRAUO_ABS:
11200
0
            cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11201
0
            break;
11202
0
        case GRAUO_SQRT:
11203
0
            cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11204
0
            break;
11205
0
        case GRAUO_LOG:
11206
0
#ifndef HAVE_MUPARSER
11207
0
            CPLError(
11208
0
                CE_Failure, CPLE_NotSupported,
11209
0
                "log(band) not available on a GDAL build without muparser");
11210
0
            return nullptr;
11211
#else
11212
            cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11213
            break;
11214
#endif
11215
0
        case GRAUO_LOG10:
11216
0
            cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11217
0
            break;
11218
0
    }
11219
0
    return new GDALComputedRasterBand(cppOp,
11220
0
                                      *(GDALRasterBand::FromHandle(hBand)));
11221
0
}
11222
11223
/************************************************************************/
11224
/*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
11225
/************************************************************************/
11226
11227
static GDALComputedRasterBand::Operation
11228
ConvertGDALRasterAlgebraBinaryOperationToCpp(
11229
    GDALRasterAlgebraBinaryOperation eOp)
11230
0
{
11231
0
    switch (eOp)
11232
0
    {
11233
0
        case GRABO_ADD:
11234
0
            return GDALComputedRasterBand::Operation::OP_ADD;
11235
0
        case GRABO_SUB:
11236
0
            return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11237
0
        case GRABO_MUL:
11238
0
            return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11239
0
        case GRABO_DIV:
11240
0
            return GDALComputedRasterBand::Operation::OP_DIVIDE;
11241
0
        case GRABO_GT:
11242
0
            return GDALComputedRasterBand::Operation::OP_GT;
11243
0
        case GRABO_GE:
11244
0
            return GDALComputedRasterBand::Operation::OP_GE;
11245
0
        case GRABO_LT:
11246
0
            return GDALComputedRasterBand::Operation::OP_LT;
11247
0
        case GRABO_LE:
11248
0
            return GDALComputedRasterBand::Operation::OP_LE;
11249
0
        case GRABO_EQ:
11250
0
            return GDALComputedRasterBand::Operation::OP_EQ;
11251
0
        case GRABO_NE:
11252
0
            break;
11253
0
        case GRABO_LOGICAL_AND:
11254
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11255
0
        case GRABO_LOGICAL_OR:
11256
0
            return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11257
0
        case GRABO_POW:
11258
0
            return GDALComputedRasterBand::Operation::OP_POW;
11259
0
    }
11260
0
    return GDALComputedRasterBand::Operation::OP_NE;
11261
0
}
11262
11263
/************************************************************************/
11264
/*                     GDALRasterBandBinaryOpBand()                     */
11265
/************************************************************************/
11266
11267
/** Apply a binary operation on this band with another one.
11268
 *
11269
 * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11270
 * "hBand1 - hBand2".
11271
 *
11272
 * The resulting band is lazy evaluated. A reference is taken on both input
11273
 * datasets.
11274
 *
11275
 * @since 3.12
11276
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11277
 */
11278
GDALComputedRasterBandH
11279
GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11280
                           GDALRasterAlgebraBinaryOperation eOp,
11281
                           GDALRasterBandH hOtherBand)
11282
0
{
11283
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11284
0
    VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11285
0
#ifndef HAVE_MUPARSER
11286
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11287
0
    {
11288
0
        CPLError(
11289
0
            CE_Failure, CPLE_NotSupported,
11290
0
            "Band comparison operators not available on a GDAL build without "
11291
0
            "muparser");
11292
0
        return nullptr;
11293
0
    }
11294
0
    else if (eOp == GRABO_POW)
11295
0
    {
11296
0
        CPLError(
11297
0
            CE_Failure, CPLE_NotSupported,
11298
0
            "pow(band, band) not available on a GDAL build without muparser");
11299
0
        return nullptr;
11300
0
    }
11301
0
#endif
11302
0
    auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11303
0
    auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11304
0
    try
11305
0
    {
11306
0
        GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11307
0
    }
11308
0
    catch (const std::exception &e)
11309
0
    {
11310
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11311
0
        return nullptr;
11312
0
    }
11313
0
    return new GDALComputedRasterBand(
11314
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11315
0
        secondBand);
11316
0
}
11317
11318
/************************************************************************/
11319
/*                     GDALRasterBandBinaryOpDouble()                   */
11320
/************************************************************************/
11321
11322
/** Apply a binary operation on this band with a constant
11323
 *
11324
 * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11325
 * "hBand - constant".
11326
 *
11327
 * The resulting band is lazy evaluated. A reference is taken on the input
11328
 * dataset.
11329
 *
11330
 * @since 3.12
11331
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11332
 */
11333
GDALComputedRasterBandH
11334
GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11335
                             GDALRasterAlgebraBinaryOperation eOp,
11336
                             double constant)
11337
0
{
11338
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11339
0
#ifndef HAVE_MUPARSER
11340
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11341
0
    {
11342
0
        CPLError(
11343
0
            CE_Failure, CPLE_NotSupported,
11344
0
            "Band comparison operators not available on a GDAL build without "
11345
0
            "muparser");
11346
0
        return nullptr;
11347
0
    }
11348
0
#endif
11349
0
    return new GDALComputedRasterBand(
11350
0
        ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11351
0
        *(GDALRasterBand::FromHandle(hBand)), constant);
11352
0
}
11353
11354
/************************************************************************/
11355
/*                   GDALRasterBandBinaryOpDoubleToBand()               */
11356
/************************************************************************/
11357
11358
/** Apply a binary operation on the constant with this band
11359
 *
11360
 * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11361
 * "constant - hBand".
11362
 *
11363
 * The resulting band is lazy evaluated. A reference is taken on the input
11364
 * dataset.
11365
 *
11366
 * @since 3.12
11367
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11368
 */
11369
GDALComputedRasterBandH
11370
GDALRasterBandBinaryOpDoubleToBand(double constant,
11371
                                   GDALRasterAlgebraBinaryOperation eOp,
11372
                                   GDALRasterBandH hBand)
11373
0
{
11374
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
11375
0
#ifndef HAVE_MUPARSER
11376
0
    if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11377
0
    {
11378
0
        CPLError(
11379
0
            CE_Failure, CPLE_NotSupported,
11380
0
            "Band comparison operators not available on a GDAL build without "
11381
0
            "muparser");
11382
0
        return nullptr;
11383
0
    }
11384
0
#endif
11385
0
    switch (eOp)
11386
0
    {
11387
0
        case GRABO_ADD:
11388
0
        case GRABO_MUL:
11389
0
        {
11390
0
            return new GDALComputedRasterBand(
11391
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11392
0
                *(GDALRasterBand::FromHandle(hBand)), constant);
11393
0
        }
11394
11395
0
        case GRABO_DIV:
11396
0
        case GRABO_GT:
11397
0
        case GRABO_GE:
11398
0
        case GRABO_LT:
11399
0
        case GRABO_LE:
11400
0
        case GRABO_EQ:
11401
0
        case GRABO_NE:
11402
0
        case GRABO_LOGICAL_AND:
11403
0
        case GRABO_LOGICAL_OR:
11404
0
        case GRABO_POW:
11405
0
        {
11406
0
            return new GDALComputedRasterBand(
11407
0
                ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11408
0
                *(GDALRasterBand::FromHandle(hBand)));
11409
0
        }
11410
11411
0
        case GRABO_SUB:
11412
0
        {
11413
0
            break;
11414
0
        }
11415
0
    }
11416
11417
0
    return new GDALComputedRasterBand(
11418
0
        GDALComputedRasterBand::Operation::OP_ADD,
11419
0
        GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11420
0
                               *(GDALRasterBand::FromHandle(hBand)), -1.0),
11421
0
        constant);
11422
0
}
11423
11424
/************************************************************************/
11425
/*                           operator+()                                */
11426
/************************************************************************/
11427
11428
/** Add this band with another one.
11429
 *
11430
 * The resulting band is lazy evaluated. A reference is taken on both input
11431
 * datasets.
11432
 *
11433
 * @since 3.12
11434
 * @throw std::runtime_error if both bands do not have the same dimensions.
11435
 */
11436
GDALComputedRasterBand
11437
GDALRasterBand::operator+(const GDALRasterBand &other) const
11438
0
{
11439
0
    ThrowIfNotSameDimensions(*this, other);
11440
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11441
0
                                  *this, other);
11442
0
}
11443
11444
/************************************************************************/
11445
/*                           operator+()                                */
11446
/************************************************************************/
11447
11448
/** Add this band with a constant.
11449
 *
11450
 * The resulting band is lazy evaluated. A reference is taken on the input
11451
 * dataset.
11452
 *
11453
 * @since 3.12
11454
 */
11455
GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11456
0
{
11457
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11458
0
                                  *this, constant);
11459
0
}
11460
11461
/************************************************************************/
11462
/*                           operator+()                                */
11463
/************************************************************************/
11464
11465
/** Add a band with a constant.
11466
 *
11467
 * The resulting band is lazy evaluated. A reference is taken on the input
11468
 * dataset.
11469
 *
11470
 * @since 3.12
11471
 */
11472
GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11473
0
{
11474
0
    return other + constant;
11475
0
}
11476
11477
/************************************************************************/
11478
/*                           operator-()                                */
11479
/************************************************************************/
11480
11481
/** Return a band whose value is the opposite value of the band for each
11482
 * pixel.
11483
 *
11484
 * The resulting band is lazy evaluated. A reference is taken on the input
11485
 * dataset.
11486
 *
11487
 * @since 3.12
11488
 */
11489
GDALComputedRasterBand GDALRasterBand::operator-() const
11490
0
{
11491
0
    return 0 - *this;
11492
0
}
11493
11494
/************************************************************************/
11495
/*                           operator-()                                */
11496
/************************************************************************/
11497
11498
/** Subtract this band with another one.
11499
 *
11500
 * The resulting band is lazy evaluated. A reference is taken on both input
11501
 * datasets.
11502
 *
11503
 * @since 3.12
11504
 * @throw std::runtime_error if both bands do not have the same dimensions.
11505
 */
11506
GDALComputedRasterBand
11507
GDALRasterBand::operator-(const GDALRasterBand &other) const
11508
0
{
11509
0
    ThrowIfNotSameDimensions(*this, other);
11510
0
    return GDALComputedRasterBand(
11511
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11512
0
}
11513
11514
/************************************************************************/
11515
/*                           operator-()                                */
11516
/************************************************************************/
11517
11518
/** Subtract this band with a constant.
11519
 *
11520
 * The resulting band is lazy evaluated. A reference is taken on the input
11521
 * dataset.
11522
 *
11523
 * @since 3.12
11524
 */
11525
GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11526
0
{
11527
0
    return GDALComputedRasterBand(
11528
0
        GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11529
0
}
11530
11531
/************************************************************************/
11532
/*                           operator-()                                */
11533
/************************************************************************/
11534
11535
/** Subtract a constant with a band.
11536
 *
11537
 * The resulting band is lazy evaluated. A reference is taken on the input
11538
 * dataset.
11539
 *
11540
 * @since 3.12
11541
 */
11542
GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11543
0
{
11544
0
    return other * (-1.0) + constant;
11545
0
}
11546
11547
/************************************************************************/
11548
/*                           operator*()                                */
11549
/************************************************************************/
11550
11551
/** Multiply this band with another one.
11552
 *
11553
 * The resulting band is lazy evaluated. A reference is taken on both input
11554
 * datasets.
11555
 *
11556
 * @since 3.12
11557
 * @throw std::runtime_error if both bands do not have the same dimensions.
11558
 */
11559
GDALComputedRasterBand
11560
GDALRasterBand::operator*(const GDALRasterBand &other) const
11561
0
{
11562
0
    ThrowIfNotSameDimensions(*this, other);
11563
0
    return GDALComputedRasterBand(
11564
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11565
0
}
11566
11567
/************************************************************************/
11568
/*                           operator*()                                */
11569
/************************************************************************/
11570
11571
/** Multiply this band by a constant.
11572
 *
11573
 * The resulting band is lazy evaluated. A reference is taken on the input
11574
 * dataset.
11575
 *
11576
 * @since 3.12
11577
 */
11578
GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11579
0
{
11580
0
    return GDALComputedRasterBand(
11581
0
        GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11582
0
}
11583
11584
/************************************************************************/
11585
/*                           operator*()                                */
11586
/************************************************************************/
11587
11588
/** Multiply a band with a constant.
11589
 *
11590
 * The resulting band is lazy evaluated. A reference is taken on the input
11591
 * dataset.
11592
 *
11593
 * @since 3.12
11594
 */
11595
GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
11596
0
{
11597
0
    return other * constant;
11598
0
}
11599
11600
/************************************************************************/
11601
/*                           operator/()                                */
11602
/************************************************************************/
11603
11604
/** Divide this band with another one.
11605
 *
11606
 * The resulting band is lazy evaluated. A reference is taken on both input
11607
 * datasets.
11608
 *
11609
 * @since 3.12
11610
 * @throw std::runtime_error if both bands do not have the same dimensions.
11611
 */
11612
GDALComputedRasterBand
11613
GDALRasterBand::operator/(const GDALRasterBand &other) const
11614
0
{
11615
0
    ThrowIfNotSameDimensions(*this, other);
11616
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11617
0
                                  *this, other);
11618
0
}
11619
11620
/************************************************************************/
11621
/*                           operator/()                                */
11622
/************************************************************************/
11623
11624
/** Divide this band by a constant.
11625
 *
11626
 * The resulting band is lazy evaluated. A reference is taken on the input
11627
 * dataset.
11628
 *
11629
 * @since 3.12
11630
 */
11631
GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
11632
0
{
11633
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11634
0
                                  *this, constant);
11635
0
}
11636
11637
/************************************************************************/
11638
/*                           operator/()                                */
11639
/************************************************************************/
11640
11641
/** Divide a constant by a band.
11642
 *
11643
 * The resulting band is lazy evaluated. A reference is taken on the input
11644
 * dataset.
11645
 *
11646
 * @since 3.12
11647
 */
11648
GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
11649
0
{
11650
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11651
0
                                  constant, other);
11652
0
}
11653
11654
/************************************************************************/
11655
/*                          ThrowIfNotMuparser()                        */
11656
/************************************************************************/
11657
11658
#ifndef HAVE_MUPARSER
11659
static GDALComputedRasterBand ThrowIfNotMuparser()
11660
0
{
11661
0
    throw std::runtime_error("Operator not available on a "
11662
0
                             "GDAL build without muparser");
11663
0
}
11664
#endif
11665
11666
/************************************************************************/
11667
/*                           operator>()                                */
11668
/************************************************************************/
11669
11670
/** Return a band whose value is 1 if the pixel value of the left operand
11671
 * is greater than the pixel value of the right operand.
11672
 *
11673
 * The resulting band is lazy evaluated. A reference is taken on the input
11674
 * dataset.
11675
 *
11676
 * @since 3.12
11677
 */
11678
GDALComputedRasterBand
11679
GDALRasterBand::operator>(const GDALRasterBand &other) const
11680
0
{
11681
0
#ifndef HAVE_MUPARSER
11682
0
    (void)other;
11683
0
    return ThrowIfNotMuparser();
11684
#else
11685
    ThrowIfNotSameDimensions(*this, other);
11686
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11687
                                  *this, other);
11688
#endif
11689
0
}
11690
11691
/************************************************************************/
11692
/*                           operator>()                                */
11693
/************************************************************************/
11694
11695
/** Return a band whose value is 1 if the pixel value of the left operand
11696
 * is greater than the constant.
11697
 *
11698
 * The resulting band is lazy evaluated. A reference is taken on the input
11699
 * dataset.
11700
 *
11701
 * @since 3.12
11702
 */
11703
GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
11704
0
{
11705
0
#ifndef HAVE_MUPARSER
11706
0
    (void)constant;
11707
0
    return ThrowIfNotMuparser();
11708
#else
11709
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11710
                                  *this, constant);
11711
#endif
11712
0
}
11713
11714
/************************************************************************/
11715
/*                           operator>()                                */
11716
/************************************************************************/
11717
11718
/** Return a band whose value is 1 if the constant is greater than the pixel
11719
 * value of the right operand.
11720
 *
11721
 * The resulting band is lazy evaluated. A reference is taken on the input
11722
 * dataset.
11723
 *
11724
 * @since 3.12
11725
 */
11726
GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
11727
0
{
11728
0
#ifndef HAVE_MUPARSER
11729
0
    (void)constant;
11730
0
    (void)other;
11731
0
    return ThrowIfNotMuparser();
11732
#else
11733
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11734
                                  constant, other);
11735
#endif
11736
0
}
11737
11738
/************************************************************************/
11739
/*                           operator>=()                               */
11740
/************************************************************************/
11741
11742
/** Return a band whose value is 1 if the pixel value of the left operand
11743
 * is greater or equal to the pixel value of the right operand.
11744
 *
11745
 * The resulting band is lazy evaluated. A reference is taken on the input
11746
 * dataset.
11747
 *
11748
 * @since 3.12
11749
 */
11750
GDALComputedRasterBand
11751
GDALRasterBand::operator>=(const GDALRasterBand &other) const
11752
0
{
11753
0
#ifndef HAVE_MUPARSER
11754
0
    (void)other;
11755
0
    return ThrowIfNotMuparser();
11756
#else
11757
    ThrowIfNotSameDimensions(*this, other);
11758
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11759
                                  *this, other);
11760
#endif
11761
0
}
11762
11763
/************************************************************************/
11764
/*                           operator>=()                               */
11765
/************************************************************************/
11766
11767
/** Return a band whose value is 1 if the pixel value of the left operand
11768
 * is greater or equal to the constant.
11769
 *
11770
 * The resulting band is lazy evaluated. A reference is taken on the input
11771
 * dataset.
11772
 *
11773
 * @since 3.12
11774
 */
11775
GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
11776
0
{
11777
0
#ifndef HAVE_MUPARSER
11778
0
    (void)constant;
11779
0
    return ThrowIfNotMuparser();
11780
#else
11781
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11782
                                  *this, constant);
11783
#endif
11784
0
}
11785
11786
/************************************************************************/
11787
/*                           operator>=()                               */
11788
/************************************************************************/
11789
11790
/** Return a band whose value is 1 if the constant is greater or equal to
11791
 * the pixel value of the right operand.
11792
 *
11793
 * The resulting band is lazy evaluated. A reference is taken on the input
11794
 * dataset.
11795
 *
11796
 * @since 3.12
11797
 */
11798
GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
11799
0
{
11800
0
#ifndef HAVE_MUPARSER
11801
0
    (void)constant;
11802
0
    (void)other;
11803
0
    return ThrowIfNotMuparser();
11804
#else
11805
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11806
                                  constant, other);
11807
#endif
11808
0
}
11809
11810
/************************************************************************/
11811
/*                           operator<()                                */
11812
/************************************************************************/
11813
11814
/** Return a band whose value is 1 if the pixel value of the left operand
11815
 * is lesser than the pixel value of the right operand.
11816
 *
11817
 * The resulting band is lazy evaluated. A reference is taken on the input
11818
 * dataset.
11819
 *
11820
 * @since 3.12
11821
 */
11822
GDALComputedRasterBand
11823
GDALRasterBand::operator<(const GDALRasterBand &other) const
11824
0
{
11825
0
#ifndef HAVE_MUPARSER
11826
0
    (void)other;
11827
0
    return ThrowIfNotMuparser();
11828
#else
11829
    ThrowIfNotSameDimensions(*this, other);
11830
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11831
                                  *this, other);
11832
#endif
11833
0
}
11834
11835
/************************************************************************/
11836
/*                           operator<()                                */
11837
/************************************************************************/
11838
11839
/** Return a band whose value is 1 if the pixel value of the left operand
11840
 * is lesser than the constant.
11841
 *
11842
 * The resulting band is lazy evaluated. A reference is taken on the input
11843
 * dataset.
11844
 *
11845
 * @since 3.12
11846
 */
11847
GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11848
0
{
11849
0
#ifndef HAVE_MUPARSER
11850
0
    (void)constant;
11851
0
    return ThrowIfNotMuparser();
11852
#else
11853
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11854
                                  *this, constant);
11855
#endif
11856
0
}
11857
11858
/************************************************************************/
11859
/*                           operator<()                                */
11860
/************************************************************************/
11861
11862
/** Return a band whose value is 1 if the constant is lesser than the pixel
11863
 * value of the right operand.
11864
 *
11865
 * The resulting band is lazy evaluated. A reference is taken on the input
11866
 * dataset.
11867
 *
11868
 * @since 3.12
11869
 */
11870
GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11871
0
{
11872
0
#ifndef HAVE_MUPARSER
11873
0
    (void)constant;
11874
0
    (void)other;
11875
0
    return ThrowIfNotMuparser();
11876
#else
11877
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11878
                                  constant, other);
11879
#endif
11880
0
}
11881
11882
/************************************************************************/
11883
/*                           operator<=()                               */
11884
/************************************************************************/
11885
11886
/** Return a band whose value is 1 if the pixel value of the left operand
11887
 * is lesser or equal to the pixel value of the right operand.
11888
 *
11889
 * The resulting band is lazy evaluated. A reference is taken on the input
11890
 * dataset.
11891
 *
11892
 * @since 3.12
11893
 */
11894
GDALComputedRasterBand
11895
GDALRasterBand::operator<=(const GDALRasterBand &other) const
11896
0
{
11897
0
#ifndef HAVE_MUPARSER
11898
0
    (void)other;
11899
0
    return ThrowIfNotMuparser();
11900
#else
11901
    ThrowIfNotSameDimensions(*this, other);
11902
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11903
                                  *this, other);
11904
#endif
11905
0
}
11906
11907
/************************************************************************/
11908
/*                           operator<=()                               */
11909
/************************************************************************/
11910
11911
/** Return a band whose value is 1 if the pixel value of the left operand
11912
 * is lesser or equal to the constant.
11913
 *
11914
 * The resulting band is lazy evaluated. A reference is taken on the input
11915
 * dataset.
11916
 *
11917
 * @since 3.12
11918
 */
11919
GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11920
0
{
11921
0
#ifndef HAVE_MUPARSER
11922
0
    (void)constant;
11923
0
    return ThrowIfNotMuparser();
11924
#else
11925
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11926
                                  *this, constant);
11927
#endif
11928
0
}
11929
11930
/************************************************************************/
11931
/*                           operator<=()                               */
11932
/************************************************************************/
11933
11934
/** Return a band whose value is 1 if the constant is lesser or equal to
11935
 * the pixel value of the right operand.
11936
 *
11937
 * The resulting band is lazy evaluated. A reference is taken on the input
11938
 * dataset.
11939
 *
11940
 * @since 3.12
11941
 */
11942
GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11943
0
{
11944
0
#ifndef HAVE_MUPARSER
11945
0
    (void)constant;
11946
0
    (void)other;
11947
0
    return ThrowIfNotMuparser();
11948
#else
11949
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11950
                                  constant, other);
11951
#endif
11952
0
}
11953
11954
/************************************************************************/
11955
/*                           operator==()                               */
11956
/************************************************************************/
11957
11958
/** Return a band whose value is 1 if the pixel value of the left operand
11959
 * is equal to the pixel value of the right operand.
11960
 *
11961
 * The resulting band is lazy evaluated. A reference is taken on the input
11962
 * dataset.
11963
 *
11964
 * @since 3.12
11965
 */
11966
GDALComputedRasterBand
11967
GDALRasterBand::operator==(const GDALRasterBand &other) const
11968
0
{
11969
0
#ifndef HAVE_MUPARSER
11970
0
    (void)other;
11971
0
    return ThrowIfNotMuparser();
11972
#else
11973
    ThrowIfNotSameDimensions(*this, other);
11974
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11975
                                  *this, other);
11976
#endif
11977
0
}
11978
11979
/************************************************************************/
11980
/*                           operator==()                               */
11981
/************************************************************************/
11982
11983
/** Return a band whose value is 1 if the pixel value of the left operand
11984
 * is equal to the constant.
11985
 *
11986
 * The resulting band is lazy evaluated. A reference is taken on the input
11987
 * dataset.
11988
 *
11989
 * @since 3.12
11990
 */
11991
GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11992
0
{
11993
0
#ifndef HAVE_MUPARSER
11994
0
    (void)constant;
11995
0
    return ThrowIfNotMuparser();
11996
#else
11997
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11998
                                  *this, constant);
11999
#endif
12000
0
}
12001
12002
/************************************************************************/
12003
/*                           operator==()                               */
12004
/************************************************************************/
12005
12006
/** Return a band whose value is 1 if the constant is equal to
12007
 * the pixel value of the right operand.
12008
 *
12009
 * The resulting band is lazy evaluated. A reference is taken on the input
12010
 * dataset.
12011
 *
12012
 * @since 3.12
12013
 */
12014
GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12015
0
{
12016
0
#ifndef HAVE_MUPARSER
12017
0
    (void)constant;
12018
0
    (void)other;
12019
0
    return ThrowIfNotMuparser();
12020
#else
12021
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12022
                                  constant, other);
12023
#endif
12024
0
}
12025
12026
/************************************************************************/
12027
/*                           operator!=()                               */
12028
/************************************************************************/
12029
12030
/** Return a band whose value is 1 if the pixel value of the left operand
12031
 * is different from the pixel value of the right operand.
12032
 *
12033
 * The resulting band is lazy evaluated. A reference is taken on the input
12034
 * dataset.
12035
 *
12036
 * @since 3.12
12037
 */
12038
GDALComputedRasterBand
12039
GDALRasterBand::operator!=(const GDALRasterBand &other) const
12040
0
{
12041
0
#ifndef HAVE_MUPARSER
12042
0
    (void)other;
12043
0
    return ThrowIfNotMuparser();
12044
#else
12045
    ThrowIfNotSameDimensions(*this, other);
12046
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12047
                                  *this, other);
12048
#endif
12049
0
}
12050
12051
/************************************************************************/
12052
/*                           operator!=()                               */
12053
/************************************************************************/
12054
12055
/** Return a band whose value is 1 if the pixel value of the left operand
12056
 * is different from the constant.
12057
 *
12058
 * The resulting band is lazy evaluated. A reference is taken on the input
12059
 * dataset.
12060
 *
12061
 * @since 3.12
12062
 */
12063
GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12064
0
{
12065
0
#ifndef HAVE_MUPARSER
12066
0
    (void)constant;
12067
0
    return ThrowIfNotMuparser();
12068
#else
12069
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12070
                                  *this, constant);
12071
#endif
12072
0
}
12073
12074
/************************************************************************/
12075
/*                           operator!=()                               */
12076
/************************************************************************/
12077
12078
/** Return a band whose value is 1 if the constant is different from
12079
 * the pixel value of the right operand.
12080
 *
12081
 * The resulting band is lazy evaluated. A reference is taken on the input
12082
 * dataset.
12083
 *
12084
 * @since 3.12
12085
 */
12086
GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12087
0
{
12088
0
#ifndef HAVE_MUPARSER
12089
0
    (void)constant;
12090
0
    (void)other;
12091
0
    return ThrowIfNotMuparser();
12092
#else
12093
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12094
                                  constant, other);
12095
#endif
12096
0
}
12097
12098
#if defined(__GNUC__)
12099
#pragma GCC diagnostic push
12100
#pragma GCC diagnostic ignored "-Weffc++"
12101
#endif
12102
12103
/************************************************************************/
12104
/*                           operator&&()                               */
12105
/************************************************************************/
12106
12107
/** Return a band whose value is 1 if the pixel value of the left and right
12108
 * operands is true.
12109
 *
12110
 * The resulting band is lazy evaluated. A reference is taken on the input
12111
 * dataset.
12112
 *
12113
 * @since 3.12
12114
 */
12115
GDALComputedRasterBand
12116
GDALRasterBand::operator&&(const GDALRasterBand &other) const
12117
0
{
12118
0
#ifndef HAVE_MUPARSER
12119
0
    (void)other;
12120
0
    return ThrowIfNotMuparser();
12121
#else
12122
    ThrowIfNotSameDimensions(*this, other);
12123
    return GDALComputedRasterBand(
12124
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12125
#endif
12126
0
}
12127
12128
/************************************************************************/
12129
/*                           operator&&()                               */
12130
/************************************************************************/
12131
12132
/** Return a band whose value is 1 if the pixel value of the left operand
12133
 * is true, as well as the constant
12134
 *
12135
 * The resulting band is lazy evaluated. A reference is taken on the input
12136
 * dataset.
12137
 *
12138
 * @since 3.12
12139
 */
12140
GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12141
0
{
12142
0
#ifndef HAVE_MUPARSER
12143
0
    (void)constant;
12144
0
    return ThrowIfNotMuparser();
12145
#else
12146
    return GDALComputedRasterBand(
12147
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12148
#endif
12149
0
}
12150
12151
/************************************************************************/
12152
/*                           operator&&()                               */
12153
/************************************************************************/
12154
12155
/** Return a band whose value is 1 if the constant is true, as well as
12156
 * the pixel value of the right operand.
12157
 *
12158
 * The resulting band is lazy evaluated. A reference is taken on the input
12159
 * dataset.
12160
 *
12161
 * @since 3.12
12162
 */
12163
GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12164
0
{
12165
0
#ifndef HAVE_MUPARSER
12166
0
    (void)constant;
12167
0
    (void)other;
12168
0
    return ThrowIfNotMuparser();
12169
#else
12170
    return GDALComputedRasterBand(
12171
        GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12172
#endif
12173
0
}
12174
12175
/************************************************************************/
12176
/*                           operator||()                               */
12177
/************************************************************************/
12178
12179
/** Return a band whose value is 1 if the pixel value of the left or right
12180
 * operands is true.
12181
 *
12182
 * The resulting band is lazy evaluated. A reference is taken on the input
12183
 * dataset.
12184
 *
12185
 * @since 3.12
12186
 */
12187
GDALComputedRasterBand
12188
GDALRasterBand::operator||(const GDALRasterBand &other) const
12189
0
{
12190
0
#ifndef HAVE_MUPARSER
12191
0
    (void)other;
12192
0
    return ThrowIfNotMuparser();
12193
#else
12194
    ThrowIfNotSameDimensions(*this, other);
12195
    return GDALComputedRasterBand(
12196
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12197
#endif
12198
0
}
12199
12200
/************************************************************************/
12201
/*                           operator||()                               */
12202
/************************************************************************/
12203
12204
/** Return a band whose value is 1 if the pixel value of the left operand
12205
 * is true, or if the constant is true
12206
 *
12207
 * The resulting band is lazy evaluated. A reference is taken on the input
12208
 * dataset.
12209
 *
12210
 * @since 3.12
12211
 */
12212
GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12213
0
{
12214
0
#ifndef HAVE_MUPARSER
12215
0
    (void)constant;
12216
0
    return ThrowIfNotMuparser();
12217
#else
12218
    return GDALComputedRasterBand(
12219
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12220
#endif
12221
0
}
12222
12223
/************************************************************************/
12224
/*                           operator||()                               */
12225
/************************************************************************/
12226
12227
/** Return a band whose value is 1 if the constant is true, or
12228
 * the pixel value of the right operand is true
12229
 *
12230
 * The resulting band is lazy evaluated. A reference is taken on the input
12231
 * dataset.
12232
 *
12233
 * @since 3.12
12234
 */
12235
GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12236
0
{
12237
0
#ifndef HAVE_MUPARSER
12238
0
    (void)constant;
12239
0
    (void)other;
12240
0
    return ThrowIfNotMuparser();
12241
#else
12242
    return GDALComputedRasterBand(
12243
        GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12244
#endif
12245
0
}
12246
12247
#if defined(__GNUC__)
12248
#pragma GCC diagnostic pop
12249
#endif
12250
12251
/************************************************************************/
12252
/*                            operator!()                               */
12253
/************************************************************************/
12254
12255
/** Return a band whose value is the logical negation of the pixel value
12256
 *
12257
 * The resulting band is lazy evaluated. A reference is taken on the input
12258
 * dataset.
12259
 *
12260
 * @since 3.12
12261
 */
12262
GDALComputedRasterBand GDALRasterBand::operator!() const
12263
0
{
12264
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12265
0
                                  *this, true);
12266
0
}
12267
12268
namespace gdal
12269
{
12270
12271
/************************************************************************/
12272
/*                           IfThenElse()                               */
12273
/************************************************************************/
12274
12275
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12276
 * is not zero, or the one from elseBand otherwise.
12277
 *
12278
 * Variants of this method exits where thenBand and/or elseBand can be double
12279
 * values.
12280
 *
12281
 * The resulting band is lazy evaluated. A reference is taken on the input
12282
 * datasets.
12283
 *
12284
 * This method is the same as the C function GDALRasterBandIfThenElse()
12285
 *
12286
 * @since 3.12
12287
 */
12288
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12289
                                  const GDALRasterBand &thenBand,
12290
                                  const GDALRasterBand &elseBand)
12291
0
{
12292
0
#ifndef HAVE_MUPARSER
12293
0
    (void)condBand;
12294
0
    (void)thenBand;
12295
0
    (void)elseBand;
12296
0
    return ThrowIfNotMuparser();
12297
#else
12298
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12299
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12300
    return GDALComputedRasterBand(
12301
        GDALComputedRasterBand::Operation::OP_TERNARY,
12302
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12303
#endif
12304
0
}
12305
12306
//! @cond Doxygen_Suppress
12307
12308
/************************************************************************/
12309
/*                           IfThenElse()                               */
12310
/************************************************************************/
12311
12312
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12313
 * is not zero, or the one from elseBand otherwise.
12314
 *
12315
 * The resulting band is lazy evaluated. A reference is taken on the input
12316
 * datasets.
12317
 *
12318
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12319
 * with thenBand = (condBand * 0) + thenValue
12320
 *
12321
 * @since 3.12
12322
 */
12323
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12324
                                  double thenValue,
12325
                                  const GDALRasterBand &elseBand)
12326
0
{
12327
0
#ifndef HAVE_MUPARSER
12328
0
    (void)condBand;
12329
0
    (void)thenValue;
12330
0
    (void)elseBand;
12331
0
    return ThrowIfNotMuparser();
12332
#else
12333
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12334
    auto thenBand =
12335
        (condBand * 0)
12336
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12337
        thenValue;
12338
    return GDALComputedRasterBand(
12339
        GDALComputedRasterBand::Operation::OP_TERNARY,
12340
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12341
#endif
12342
0
}
12343
12344
/************************************************************************/
12345
/*                           IfThenElse()                               */
12346
/************************************************************************/
12347
12348
/** Return a band whose value is thenBand if the corresponding pixel in condBand
12349
 * is not zero, or the one from elseValue otherwise.
12350
 *
12351
 * The resulting band is lazy evaluated. A reference is taken on the input
12352
 * datasets.
12353
 *
12354
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12355
 * with elseBand = (condBand * 0) + elseValue
12356
12357
 * @since 3.12
12358
 */
12359
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12360
                                  const GDALRasterBand &thenBand,
12361
                                  double elseValue)
12362
0
{
12363
0
#ifndef HAVE_MUPARSER
12364
0
    (void)condBand;
12365
0
    (void)thenBand;
12366
0
    (void)elseValue;
12367
0
    return ThrowIfNotMuparser();
12368
#else
12369
    GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12370
    auto elseBand =
12371
        (condBand * 0)
12372
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12373
        elseValue;
12374
    return GDALComputedRasterBand(
12375
        GDALComputedRasterBand::Operation::OP_TERNARY,
12376
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12377
#endif
12378
0
}
12379
12380
/************************************************************************/
12381
/*                           IfThenElse()                               */
12382
/************************************************************************/
12383
12384
/** Return a band whose value is thenValue if the corresponding pixel in condBand
12385
 * is not zero, or the one from elseValue otherwise.
12386
 *
12387
 * The resulting band is lazy evaluated. A reference is taken on the input
12388
 * datasets.
12389
 *
12390
 * This method is the same as the C function GDALRasterBandIfThenElse(),
12391
 * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12392
 *
12393
 * @since 3.12
12394
 */
12395
GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12396
                                  double thenValue, double elseValue)
12397
0
{
12398
0
#ifndef HAVE_MUPARSER
12399
0
    (void)condBand;
12400
0
    (void)thenValue;
12401
0
    (void)elseValue;
12402
0
    return ThrowIfNotMuparser();
12403
#else
12404
    auto thenBand =
12405
        (condBand * 0)
12406
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12407
        thenValue;
12408
    auto elseBand =
12409
        (condBand * 0)
12410
            .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12411
        elseValue;
12412
    return GDALComputedRasterBand(
12413
        GDALComputedRasterBand::Operation::OP_TERNARY,
12414
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12415
#endif
12416
0
}
12417
12418
//! @endcond
12419
12420
}  // namespace gdal
12421
12422
/************************************************************************/
12423
/*                     GDALRasterBandIfThenElse()                       */
12424
/************************************************************************/
12425
12426
/** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12427
 * is not zero, or the one from hElseBand otherwise.
12428
 *
12429
 * The resulting band is lazy evaluated. A reference is taken on the input
12430
 * datasets.
12431
 *
12432
 * This function is the same as the C++ method gdal::IfThenElse()
12433
 *
12434
 * @since 3.12
12435
 */
12436
GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12437
                                                 GDALRasterBandH hThenBand,
12438
                                                 GDALRasterBandH hElseBand)
12439
0
{
12440
0
    VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12441
0
    VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12442
0
    VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12443
0
#ifndef HAVE_MUPARSER
12444
0
    CPLError(CE_Failure, CPLE_NotSupported,
12445
0
             "Band comparison operators not available on a GDAL build without "
12446
0
             "muparser");
12447
0
    return nullptr;
12448
#else
12449
12450
    auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12451
    auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12452
    auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12453
    try
12454
    {
12455
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12456
        GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12457
    }
12458
    catch (const std::exception &e)
12459
    {
12460
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12461
        return nullptr;
12462
    }
12463
    return new GDALComputedRasterBand(
12464
        GDALComputedRasterBand::Operation::OP_TERNARY,
12465
        std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12466
#endif
12467
0
}
12468
12469
/************************************************************************/
12470
/*                       GDALRasterBand::AsType()                       */
12471
/************************************************************************/
12472
12473
/** Cast this band to another type.
12474
 *
12475
 * The resulting band is lazy evaluated. A reference is taken on the input
12476
 * dataset.
12477
 *
12478
 * This method is the same as the C function GDALRasterBandAsDataType()
12479
 *
12480
 * @since 3.12
12481
 */
12482
GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12483
0
{
12484
0
    if (dt == GDT_Unknown)
12485
0
    {
12486
0
        throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12487
0
    }
12488
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12489
0
                                  *this, dt);
12490
0
}
12491
12492
/************************************************************************/
12493
/*                       GDALRasterBandAsDataType()                     */
12494
/************************************************************************/
12495
12496
/** Cast this band to another type.
12497
 *
12498
 * The resulting band is lazy evaluated. A reference is taken on the input
12499
 * dataset.
12500
 *
12501
 * This function is the same as the C++ method GDALRasterBand::AsType()
12502
 *
12503
 * @since 3.12
12504
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12505
 */
12506
GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12507
                                                 GDALDataType eDT)
12508
0
{
12509
0
    VALIDATE_POINTER1(hBand, __func__, nullptr);
12510
0
    if (eDT == GDT_Unknown)
12511
0
    {
12512
0
        CPLError(CE_Failure, CPLE_NotSupported,
12513
0
                 "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12514
0
        return nullptr;
12515
0
    }
12516
0
    return new GDALComputedRasterBand(
12517
0
        GDALComputedRasterBand::Operation::OP_CAST,
12518
0
        *(GDALRasterBand::FromHandle(hBand)), eDT);
12519
0
}
12520
12521
/************************************************************************/
12522
/*                         GetBandVector()                              */
12523
/************************************************************************/
12524
12525
static std::vector<const GDALRasterBand *>
12526
GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12527
0
{
12528
0
    std::vector<const GDALRasterBand *> bands;
12529
0
    for (size_t i = 0; i < nBandCount; ++i)
12530
0
    {
12531
0
        if (i > 0)
12532
0
        {
12533
0
            GDALRasterBand::ThrowIfNotSameDimensions(
12534
0
                *(GDALRasterBand::FromHandle(pahBands[0])),
12535
0
                *(GDALRasterBand::FromHandle(pahBands[i])));
12536
0
        }
12537
0
        bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12538
0
    }
12539
0
    return bands;
12540
0
}
12541
12542
/************************************************************************/
12543
/*                       GDALOperationOnNBands()                        */
12544
/************************************************************************/
12545
12546
static GDALComputedRasterBandH
12547
GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12548
                      GDALRasterBandH *pahBands)
12549
0
{
12550
0
    VALIDATE_POINTER1(pahBands, __func__, nullptr);
12551
0
    if (nBandCount == 0)
12552
0
    {
12553
0
        CPLError(CE_Failure, CPLE_AppDefined,
12554
0
                 "At least one band should be passed");
12555
0
        return nullptr;
12556
0
    }
12557
12558
0
    std::vector<const GDALRasterBand *> bands;
12559
0
    try
12560
0
    {
12561
0
        bands = GetBandVector(nBandCount, pahBands);
12562
0
    }
12563
0
    catch (const std::exception &e)
12564
0
    {
12565
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12566
0
        return nullptr;
12567
0
    }
12568
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12569
0
}
12570
12571
/************************************************************************/
12572
/*                       GDALMaximumOfNBands()                          */
12573
/************************************************************************/
12574
12575
/** Return a band whose each pixel value is the maximum of the corresponding
12576
 * pixel values in the input bands.
12577
 *
12578
 * The resulting band is lazy evaluated. A reference is taken on input
12579
 * datasets.
12580
 *
12581
 * This function is the same as the C ++ method gdal::max()
12582
 *
12583
 * @since 3.12
12584
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12585
 */
12586
GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12587
                                            GDALRasterBandH *pahBands)
12588
0
{
12589
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12590
0
                                 nBandCount, pahBands);
12591
0
}
12592
12593
/************************************************************************/
12594
/*                               gdal::max()                            */
12595
/************************************************************************/
12596
12597
namespace gdal
12598
{
12599
/** Return a band whose each pixel value is the maximum of the corresponding
12600
 * pixel values in the inputs (bands or constants)
12601
 *
12602
 * The resulting band is lazy evaluated. A reference is taken on input
12603
 * datasets.
12604
 *
12605
 * Two or more bands can be passed.
12606
 *
12607
 * This method is the same as the C function GDALMaximumOfNBands()
12608
 *
12609
 * @since 3.12
12610
 * @throw std::runtime_error if bands do not have the same dimensions.
12611
 */
12612
GDALComputedRasterBand max(const GDALRasterBand &first,
12613
                           const GDALRasterBand &second)
12614
0
{
12615
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12616
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
12617
0
                                  first, second);
12618
0
}
12619
}  // namespace gdal
12620
12621
/************************************************************************/
12622
/*                     GDALRasterBandMaxConstant()                      */
12623
/************************************************************************/
12624
12625
/** Return a band whose each pixel value is the maximum of the corresponding
12626
 * pixel values in the input band and the constant.
12627
 *
12628
 * The resulting band is lazy evaluated. A reference is taken on the input
12629
 * dataset.
12630
 *
12631
 * This function is the same as the C ++ method gdal::max()
12632
 *
12633
 * @since 3.12
12634
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12635
 */
12636
GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
12637
                                                  double dfConstant)
12638
0
{
12639
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12640
0
        GDALComputedRasterBand::Operation::OP_MAX,
12641
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12642
0
        dfConstant));
12643
0
}
12644
12645
/************************************************************************/
12646
/*                       GDALMinimumOfNBands()                          */
12647
/************************************************************************/
12648
12649
/** Return a band whose each pixel value is the minimum of the corresponding
12650
 * pixel values in the input bands.
12651
 *
12652
 * The resulting band is lazy evaluated. A reference is taken on input
12653
 * datasets.
12654
 *
12655
 * This function is the same as the C ++ method gdal::min()
12656
 *
12657
 * @since 3.12
12658
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12659
 */
12660
GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
12661
                                            GDALRasterBandH *pahBands)
12662
0
{
12663
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
12664
0
                                 nBandCount, pahBands);
12665
0
}
12666
12667
/************************************************************************/
12668
/*                               gdal::min()                            */
12669
/************************************************************************/
12670
12671
namespace gdal
12672
{
12673
/** Return a band whose each pixel value is the minimum of the corresponding
12674
 * pixel values in the inputs (bands or constants)
12675
 *
12676
 * The resulting band is lazy evaluated. A reference is taken on input
12677
 * datasets.
12678
 *
12679
 * Two or more bands can be passed.
12680
 *
12681
 * This method is the same as the C function GDALMinimumOfNBands()
12682
 *
12683
 * @since 3.12
12684
 * @throw std::runtime_error if bands do not have the same dimensions.
12685
 */
12686
GDALComputedRasterBand min(const GDALRasterBand &first,
12687
                           const GDALRasterBand &second)
12688
0
{
12689
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12690
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
12691
0
                                  first, second);
12692
0
}
12693
}  // namespace gdal
12694
12695
/************************************************************************/
12696
/*                     GDALRasterBandMinConstant()                      */
12697
/************************************************************************/
12698
12699
/** Return a band whose each pixel value is the minimum of the corresponding
12700
 * pixel values in the input band and the constant.
12701
 *
12702
 * The resulting band is lazy evaluated. A reference is taken on the input
12703
 * dataset.
12704
 *
12705
 * This function is the same as the C ++ method gdal::min()
12706
 *
12707
 * @since 3.12
12708
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12709
 */
12710
GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
12711
                                                  double dfConstant)
12712
0
{
12713
0
    return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12714
0
        GDALComputedRasterBand::Operation::OP_MIN,
12715
0
        std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12716
0
        dfConstant));
12717
0
}
12718
12719
/************************************************************************/
12720
/*                         GDALMeanOfNBands()                           */
12721
/************************************************************************/
12722
12723
/** Return a band whose each pixel value is the arithmetic mean of the
12724
 * corresponding pixel values in the input bands.
12725
 *
12726
 * The resulting band is lazy evaluated. A reference is taken on input
12727
 * datasets.
12728
 *
12729
 * This function is the same as the C ++ method gdal::mean()
12730
 *
12731
 * @since 3.12
12732
 * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12733
 */
12734
GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
12735
                                         GDALRasterBandH *pahBands)
12736
0
{
12737
0
    return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
12738
0
                                 nBandCount, pahBands);
12739
0
}
12740
12741
/************************************************************************/
12742
/*                              gdal::mean()                            */
12743
/************************************************************************/
12744
12745
namespace gdal
12746
{
12747
12748
/** Return a band whose each pixel value is the arithmetic mean of the
12749
 * corresponding pixel values in the input bands.
12750
 *
12751
 * The resulting band is lazy evaluated. A reference is taken on input
12752
 * datasets.
12753
 *
12754
 * Two or more bands can be passed.
12755
 *
12756
 * This method is the same as the C function GDALMeanOfNBands()
12757
 *
12758
 * @since 3.12
12759
 * @throw std::runtime_error if bands do not have the same dimensions.
12760
 */
12761
GDALComputedRasterBand mean(const GDALRasterBand &first,
12762
                            const GDALRasterBand &second)
12763
0
{
12764
0
    GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12765
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
12766
0
                                  first, second);
12767
0
}
12768
}  // namespace gdal
12769
12770
/************************************************************************/
12771
/*                              gdal::abs()                             */
12772
/************************************************************************/
12773
12774
namespace gdal
12775
{
12776
12777
/** Return a band whose each pixel value is the absolute value (or module
12778
 * for complex data type) of the corresponding pixel value in the input band.
12779
 *
12780
 * The resulting band is lazy evaluated. A reference is taken on input
12781
 * datasets.
12782
 *
12783
 * @since 3.12
12784
 */
12785
GDALComputedRasterBand abs(const GDALRasterBand &band)
12786
0
{
12787
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12788
0
                                  band);
12789
0
}
12790
}  // namespace gdal
12791
12792
/************************************************************************/
12793
/*                             gdal::fabs()                             */
12794
/************************************************************************/
12795
12796
namespace gdal
12797
{
12798
12799
/** Return a band whose each pixel value is the absolute value (or module
12800
 * for complex data type) of the corresponding pixel value in the input band.
12801
 *
12802
 * The resulting band is lazy evaluated. A reference is taken on input
12803
 * datasets.
12804
 *
12805
 * @since 3.12
12806
 */
12807
GDALComputedRasterBand fabs(const GDALRasterBand &band)
12808
0
{
12809
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12810
0
                                  band);
12811
0
}
12812
}  // namespace gdal
12813
12814
/************************************************************************/
12815
/*                             gdal::sqrt()                             */
12816
/************************************************************************/
12817
12818
namespace gdal
12819
{
12820
12821
/** Return a band whose each pixel value is the square root of the
12822
 * corresponding pixel value in the input band.
12823
 *
12824
 * The resulting band is lazy evaluated. A reference is taken on input
12825
 * datasets.
12826
 *
12827
 * @since 3.12
12828
 */
12829
GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12830
0
{
12831
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12832
0
                                  band);
12833
0
}
12834
}  // namespace gdal
12835
12836
/************************************************************************/
12837
/*                             gdal::log()                              */
12838
/************************************************************************/
12839
12840
namespace gdal
12841
{
12842
12843
/** Return a band whose each pixel value is the natural logarithm of the
12844
 * corresponding pixel value in the input band.
12845
 *
12846
 * The resulting band is lazy evaluated. A reference is taken on input
12847
 * datasets.
12848
 *
12849
 * @since 3.12
12850
 */
12851
GDALComputedRasterBand log(const GDALRasterBand &band)
12852
0
{
12853
0
#ifndef HAVE_MUPARSER
12854
0
    (void)band;
12855
0
    return ThrowIfNotMuparser();
12856
#else
12857
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12858
                                  band);
12859
#endif
12860
0
}
12861
}  // namespace gdal
12862
12863
/************************************************************************/
12864
/*                             gdal::log10()                            */
12865
/************************************************************************/
12866
12867
namespace gdal
12868
{
12869
12870
/** Return a band whose each pixel value is the logarithm base 10 of the
12871
 * corresponding pixel value in the input band.
12872
 *
12873
 * The resulting band is lazy evaluated. A reference is taken on input
12874
 * datasets.
12875
 *
12876
 * @since 3.12
12877
 */
12878
GDALComputedRasterBand log10(const GDALRasterBand &band)
12879
0
{
12880
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12881
0
                                  band);
12882
0
}
12883
}  // namespace gdal
12884
12885
/************************************************************************/
12886
/*                             gdal::pow()                              */
12887
/************************************************************************/
12888
12889
namespace gdal
12890
{
12891
12892
#ifndef DOXYGEN_SKIP
12893
/** Return a band whose each pixel value is the constant raised to the power of
12894
 * the corresponding pixel value in the input band.
12895
 *
12896
 * The resulting band is lazy evaluated. A reference is taken on input
12897
 * datasets.
12898
 *
12899
 * @since 3.12
12900
 */
12901
GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12902
0
{
12903
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12904
0
                                  constant, band);
12905
0
}
12906
#endif
12907
12908
}  // namespace gdal
12909
12910
/************************************************************************/
12911
/*                             gdal::pow()                              */
12912
/************************************************************************/
12913
12914
namespace gdal
12915
{
12916
12917
/** Return a band whose each pixel value is the the corresponding pixel value
12918
 * in the input band raised to the power of the constant.
12919
 *
12920
 * The resulting band is lazy evaluated. A reference is taken on input
12921
 * datasets.
12922
 *
12923
 * @since 3.12
12924
 */
12925
GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12926
0
{
12927
0
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12928
0
                                  band, constant);
12929
0
}
12930
}  // namespace gdal
12931
12932
/************************************************************************/
12933
/*                             gdal::pow()                              */
12934
/************************************************************************/
12935
12936
namespace gdal
12937
{
12938
12939
#ifndef DOXYGEN_SKIP
12940
/** Return a band whose each pixel value is the the corresponding pixel value
12941
 * in the input band1 raised to the power of the corresponding pixel value
12942
 * in the input band2
12943
 *
12944
 * The resulting band is lazy evaluated. A reference is taken on input
12945
 * datasets.
12946
 *
12947
 * @since 3.12
12948
 * @throw std::runtime_error if bands do not have the same dimensions.
12949
 */
12950
GDALComputedRasterBand pow(const GDALRasterBand &band1,
12951
                           const GDALRasterBand &band2)
12952
0
{
12953
0
#ifndef HAVE_MUPARSER
12954
0
    (void)band1;
12955
0
    (void)band2;
12956
0
    return ThrowIfNotMuparser();
12957
#else
12958
    GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12959
    return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12960
                                  band1, band2);
12961
#endif
12962
0
}
12963
#endif
12964
}  // namespace gdal