Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "cpl_float.h"
17 :
18 : #include <algorithm>
19 : #include <cassert>
20 : #include <climits>
21 : #include <cmath>
22 : #include <cstdarg>
23 : #include <cstddef>
24 : #include <cstdio>
25 : #include <cstdlib>
26 : #include <cstring>
27 : #include <limits>
28 : #include <memory>
29 : #include <new>
30 : #include <numeric> // std::lcm
31 : #include <type_traits>
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_float.h"
36 : #include "cpl_multiproc.h"
37 : #include "cpl_progress.h"
38 : #include "cpl_string.h"
39 : #include "cpl_virtualmem.h"
40 : #include "cpl_vsi.h"
41 : #include "cpl_worker_thread_pool.h"
42 : #include "gdal.h"
43 : #include "gdal_abstractbandblockcache.h"
44 : #include "gdalantirecursion.h"
45 : #include "gdal_rat.h"
46 : #include "gdal_rasterband.h"
47 : #include "gdal_priv_templates.hpp"
48 : #include "gdal_interpolateatpoint.h"
49 : #include "gdal_minmax_element.hpp"
50 : #include "gdalmultidim_priv.h"
51 : #include "gdal_thread_pool.h"
52 :
53 : #ifdef USE_NEON_OPTIMIZATIONS
54 : #include "include_sse2neon.h"
55 : #endif
56 :
57 : #if defined(__AVX2__) || defined(__FMA__)
58 : #include <immintrin.h>
59 : #endif
60 :
61 : /************************************************************************/
62 : /* GDALRasterBand() */
63 : /************************************************************************/
64 :
65 : /*! Constructor. Applications should never create GDALRasterBands directly. */
66 :
67 1580880 : GDALRasterBand::GDALRasterBand()
68 : : GDALRasterBand(
69 1580880 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
70 : {
71 1580880 : }
72 :
73 : /** Constructor. Applications should never create GDALRasterBands directly.
74 : * @param bForceCachedIOIn Whether cached IO should be forced.
75 : */
76 1880440 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
77 1880440 : : bForceCachedIO(bForceCachedIOIn)
78 :
79 : {
80 1880440 : }
81 :
82 : /************************************************************************/
83 : /* ~GDALRasterBand() */
84 : /************************************************************************/
85 :
86 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
87 : instead destroy the GDALDataset. */
88 :
89 1880420 : GDALRasterBand::~GDALRasterBand()
90 :
91 : {
92 1880420 : if (poDS && poDS->IsMarkedSuppressOnClose())
93 : {
94 540 : if (poBandBlockCache)
95 472 : poBandBlockCache->DisableDirtyBlockWriting();
96 : }
97 1880420 : GDALRasterBand::FlushCache(true);
98 :
99 1880420 : delete poBandBlockCache;
100 :
101 1880420 : if (static_cast<GIntBig>(nBlockReads) >
102 1880420 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
103 259 : nBand == 1 && poDS != nullptr)
104 : {
105 362 : CPLDebug(
106 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
107 181 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
108 181 : poDS->GetDescription());
109 : }
110 :
111 1880420 : InvalidateMaskBand();
112 1880420 : nBand = -nBand;
113 :
114 1880420 : delete m_poPointsCache;
115 1880420 : }
116 :
117 : /************************************************************************/
118 : /* RasterIO() */
119 : /************************************************************************/
120 :
121 : /**
122 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
123 : * int nXOff, int nYOff, int nXSize, int nYSize,
124 : * void * pData, int nBufXSize, int nBufYSize,
125 : * GDALDataType eBufType,
126 : * GSpacing nPixelSpace,
127 : * GSpacing nLineSpace,
128 : * GDALRasterIOExtraArg* psExtraArg )
129 : * \brief Read/write a region of image data for this band.
130 : *
131 : * This method allows reading a region of a GDALRasterBand into a buffer,
132 : * or writing data from a buffer into a region of a GDALRasterBand. It
133 : * automatically takes care of data type translation if the data type
134 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
135 : * The method also takes care of image decimation / replication if the
136 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
137 : * region being accessed (nXSize x nYSize).
138 : *
139 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
140 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
141 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
142 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
143 : * Or use nLineSpace and a possibly shifted pData value.
144 : *
145 : * The nPixelSpace and nLineSpace parameters allow reading into or
146 : * writing from unusually organized buffers. This is primarily used
147 : * for buffers containing more than one bands raster data in interleaved
148 : * format.
149 : *
150 : * Some formats may efficiently implement decimation into a buffer by
151 : * reading from lower resolution overview images. The logic of the default
152 : * implementation in the base class GDALRasterBand is the following one. It
153 : * computes a target_downscaling_factor from the window of interest and buffer
154 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
155 : * It then walks through overviews and will select the first one whose
156 : * downscaling factor is greater than target_downscaling_factor / 1.2.
157 : *
158 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
159 : * The relationship between target_downscaling_factor and the select overview
160 : * level is the following one:
161 : *
162 : * target_downscaling_factor | selected_overview
163 : * ------------------------- | -----------------
164 : * ]0, 2 / 1.2] | full resolution band
165 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
166 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
167 : * ]8 / 1.2, infinity[ | 8x downsampled band
168 : *
169 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
170 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
171 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
172 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
173 : * this oversampling threshold defaults to 1. Consequently if there are overviews
174 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
175 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
176 : *
177 : * For highest performance full resolution data access, read and write
178 : * on "block boundaries" as returned by GetBlockSize(), or use the
179 : * ReadBlock() and WriteBlock() methods.
180 : *
181 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
182 : * functions.
183 : *
184 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
185 : * write a region of data.
186 : *
187 : * @param nXOff The pixel offset to the top left corner of the region
188 : * of the band to be accessed. This would be zero to start from the left side.
189 : *
190 : * @param nYOff The line offset to the top left corner of the region
191 : * of the band to be accessed. This would be zero to start from the top.
192 : *
193 : * @param nXSize The width of the region of the band to be accessed in pixels.
194 : *
195 : * @param nYSize The height of the region of the band to be accessed in lines.
196 : *
197 : * @param pData The buffer into which the data should be read, or from which
198 : * it should be written. This buffer must contain at least nBufXSize *
199 : * nBufYSize words of type eBufType. It is organized in left to right,
200 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
201 : * and nLineSpace parameters.
202 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
203 : * temporarily modified during the execution of this method (and eventually
204 : * restored back to its original content), so it is not safe to use a buffer
205 : * stored in a read-only section of the calling program.
206 : *
207 : * @param nBufXSize the width of the buffer image into which the desired region
208 : * is to be read, or from which it is to be written.
209 : *
210 : * @param nBufYSize the height of the buffer image into which the desired region
211 : * is to be read, or from which it is to be written.
212 : *
213 : * @param eBufType the type of the pixel values in the pData data buffer. The
214 : * pixel values will automatically be translated to/from the GDALRasterBand
215 : * data type as needed. Most driver implementations will use GDALCopyWords64()
216 : * to perform data type translation.
217 : *
218 : * @param nPixelSpace The byte offset from the start of one pixel value in
219 : * pData to the start of the next pixel value within a scanline. If defaulted
220 : * (0) the size of the datatype eBufType is used.
221 : *
222 : * @param nLineSpace The byte offset from the start of one scanline in
223 : * pData to the start of the next. If defaulted (0) the size of the datatype
224 : * eBufType * nBufXSize is used.
225 : *
226 : * @param psExtraArg Pointer to a GDALRasterIOExtraArg
227 : * structure with additional arguments to specify resampling and progress
228 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
229 : * configuration option can also be defined to override the default resampling
230 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
231 : *
232 : * @return CE_Failure if the access fails, otherwise CE_None.
233 : */
234 :
235 : /**
236 : * \brief Read/write a region of image data for this band.
237 : *
238 : * This method allows reading a region of a GDALRasterBand into a buffer,
239 : * or writing data from a buffer into a region of a GDALRasterBand. It
240 : * automatically takes care of data type translation if the data type
241 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
242 : * The method also takes care of image decimation / replication if the
243 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
244 : * region being accessed (nXSize x nYSize).
245 : *
246 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
247 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
248 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
249 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
250 : * Or use nLineSpace and a possibly shifted pData value.
251 : *
252 : * The nPixelSpace and nLineSpace parameters allow reading into or
253 : * writing from unusually organized buffers. This is primarily used
254 : * for buffers containing more than one bands raster data in interleaved
255 : * format.
256 : *
257 : * Some formats may efficiently implement decimation into a buffer by
258 : * reading from lower resolution overview images. The logic of the default
259 : * implementation in the base class GDALRasterBand is the following one. It
260 : * computes a target_downscaling_factor from the window of interest and buffer
261 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
262 : * It then walks through overviews and will select the first one whose
263 : * downscaling factor is greater than target_downscaling_factor / 1.2.
264 : *
265 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
266 : * The relationship between target_downscaling_factor and the select overview
267 : * level is the following one:
268 : *
269 : * target_downscaling_factor | selected_overview
270 : * ------------------------- | -----------------
271 : * ]0, 2 / 1.2] | full resolution band
272 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
273 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
274 : * ]8 / 1.2, infinity[ | 8x downsampled band
275 : *
276 : * For highest performance full resolution data access, read and write
277 : * on "block boundaries" as returned by GetBlockSize(), or use the
278 : * ReadBlock() and WriteBlock() methods.
279 : *
280 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
281 : * functions.
282 : *
283 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
284 : * more convenient to use for most common use cases.
285 : *
286 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
287 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
288 : * instance of this dataset) concurrently from several threads.
289 : *
290 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
291 : * write a region of data.
292 : *
293 : * @param nXOff The pixel offset to the top left corner of the region
294 : * of the band to be accessed. This would be zero to start from the left side.
295 : *
296 : * @param nYOff The line offset to the top left corner of the region
297 : * of the band to be accessed. This would be zero to start from the top.
298 : *
299 : * @param nXSize The width of the region of the band to be accessed in pixels.
300 : *
301 : * @param nYSize The height of the region of the band to be accessed in lines.
302 : *
303 : * @param[in,out] pData The buffer into which the data should be read, or from
304 : * which it should be written. This buffer must contain at least nBufXSize *
305 : * nBufYSize words of type eBufType. It is organized in left to right,
306 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
307 : * and nLineSpace parameters.
308 : *
309 : * @param nBufXSize the width of the buffer image into which the desired region
310 : * is to be read, or from which it is to be written.
311 : *
312 : * @param nBufYSize the height of the buffer image into which the desired region
313 : * is to be read, or from which it is to be written.
314 : *
315 : * @param eBufType the type of the pixel values in the pData data buffer. The
316 : * pixel values will automatically be translated to/from the GDALRasterBand
317 : * data type as needed.
318 : *
319 : * @param nPixelSpace The byte offset from the start of one pixel value in
320 : * pData to the start of the next pixel value within a scanline. If defaulted
321 : * (0) the size of the datatype eBufType is used.
322 : *
323 : * @param nLineSpace The byte offset from the start of one scanline in
324 : * pData to the start of the next. If defaulted (0) the size of the datatype
325 : * eBufType * nBufXSize is used.
326 : *
327 : * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
328 : * structure with additional arguments to specify resampling and progress
329 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
330 : * configuration option can also be defined to override the default resampling
331 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
332 : *
333 : * @return CE_Failure if the access fails, otherwise CE_None.
334 : *
335 : * @see GDALRasterBand::ReadRaster()
336 : */
337 :
338 4662520 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
339 : int nXSize, int nYSize, void *pData,
340 : int nBufXSize, int nBufYSize,
341 : GDALDataType eBufType, GSpacing nPixelSpace,
342 : GSpacing nLineSpace,
343 : GDALRasterIOExtraArg *psExtraArg)
344 :
345 : {
346 : GDALRasterIOExtraArg sExtraArg;
347 4662520 : if (psExtraArg == nullptr)
348 : {
349 4055620 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
350 4055620 : psExtraArg = &sExtraArg;
351 : }
352 606900 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
353 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
354 : {
355 0 : ReportError(CE_Failure, CPLE_AppDefined,
356 : "Unhandled version of GDALRasterIOExtraArg");
357 0 : return CE_Failure;
358 : }
359 :
360 4662520 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
361 : nBufYSize);
362 :
363 4662520 : if (CPL_UNLIKELY(nullptr == pData))
364 : {
365 0 : ReportError(CE_Failure, CPLE_AppDefined,
366 : "The buffer into which the data should be read is null");
367 0 : return CE_Failure;
368 : }
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Some size values are "noop". Lets just return to avoid */
372 : /* stressing lower level functions. */
373 : /* -------------------------------------------------------------------- */
374 4662520 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
375 : nBufYSize < 1))
376 : {
377 2 : CPLDebug("GDAL",
378 : "RasterIO() skipped for odd window or buffer size.\n"
379 : " Window = (%d,%d)x%dx%d\n"
380 : " Buffer = %dx%d\n",
381 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
382 :
383 2 : return CE_None;
384 : }
385 :
386 4662520 : if (eRWFlag == GF_Write)
387 : {
388 414343 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
389 : {
390 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
391 : "An error occurred while writing a dirty block "
392 : "from GDALRasterBand::RasterIO");
393 0 : CPLErr eErr = eFlushBlockErr;
394 0 : eFlushBlockErr = CE_None;
395 0 : return eErr;
396 : }
397 414343 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
398 : {
399 6 : return CE_Failure;
400 : }
401 : }
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* If pixel and line spacing are defaulted assign reasonable */
405 : /* value assuming a packed buffer. */
406 : /* -------------------------------------------------------------------- */
407 4662510 : if (nPixelSpace == 0)
408 : {
409 4253590 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
410 : }
411 :
412 4662510 : if (nLineSpace == 0)
413 : {
414 4241200 : nLineSpace = nPixelSpace * nBufXSize;
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Do some validation of parameters. */
419 : /* -------------------------------------------------------------------- */
420 4662510 : if (CPL_UNLIKELY(nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
421 : nYSize > nRasterYSize - nYOff))
422 : {
423 15 : ReportError(CE_Failure, CPLE_IllegalArg,
424 : "Access window out of range in RasterIO(). Requested\n"
425 : "(%d,%d) of size %dx%d on raster of %dx%d.",
426 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
427 15 : return CE_Failure;
428 : }
429 :
430 4662500 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
431 : {
432 0 : ReportError(
433 : CE_Failure, CPLE_IllegalArg,
434 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
435 : eRWFlag);
436 0 : return CE_Failure;
437 : }
438 4662500 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
439 : {
440 2 : ReportError(CE_Failure, CPLE_IllegalArg,
441 : "Illegal GDT_Unknown/GDT_TypeCount argument");
442 2 : return CE_Failure;
443 : }
444 :
445 4662500 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
446 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
447 4662500 : nLineSpace, psExtraArg);
448 : }
449 :
450 : /************************************************************************/
451 : /* RasterIOInternal() */
452 : /************************************************************************/
453 :
454 4662600 : CPLErr GDALRasterBand::RasterIOInternal(
455 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
456 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
457 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
458 : {
459 : /* -------------------------------------------------------------------- */
460 : /* Call the format specific function. */
461 : /* -------------------------------------------------------------------- */
462 :
463 4662600 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
464 :
465 : CPLErr eErr;
466 4662600 : if (bForceCachedIO)
467 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
468 : pData, nBufXSize, nBufYSize, eBufType,
469 : nPixelSpace, nLineSpace, psExtraArg);
470 : else
471 : eErr =
472 4662580 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
473 4662580 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
474 :
475 4662600 : if (bCallLeaveReadWrite)
476 614526 : LeaveReadWrite();
477 :
478 4662600 : return eErr;
479 : }
480 :
481 : /************************************************************************/
482 : /* GDALRasterIO() */
483 : /************************************************************************/
484 :
485 : /**
486 : * \brief Read/write a region of image data for this band.
487 : *
488 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
489 : * resolution, progress callback, etc. are needed)
490 : *
491 : * @see GDALRasterBand::RasterIO()
492 : */
493 :
494 3598510 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
495 : int nXOff, int nYOff, int nXSize, int nYSize,
496 : void *pData, int nBufXSize, int nBufYSize,
497 : GDALDataType eBufType, int nPixelSpace,
498 : int nLineSpace)
499 :
500 : {
501 3598510 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
502 :
503 3598510 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
504 :
505 3598510 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
506 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
507 3598510 : nLineSpace, nullptr));
508 : }
509 :
510 : /************************************************************************/
511 : /* GDALRasterIOEx() */
512 : /************************************************************************/
513 :
514 : /**
515 : * \brief Read/write a region of image data for this band.
516 : *
517 : * @see GDALRasterBand::RasterIO()
518 : */
519 :
520 42727 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
521 : int nXOff, int nYOff, int nXSize, int nYSize,
522 : void *pData, int nBufXSize, int nBufYSize,
523 : GDALDataType eBufType, GSpacing nPixelSpace,
524 : GSpacing nLineSpace,
525 : GDALRasterIOExtraArg *psExtraArg)
526 :
527 : {
528 42727 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
529 :
530 42727 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
531 :
532 42727 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
533 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
534 42727 : nLineSpace, psExtraArg));
535 : }
536 :
537 : /************************************************************************/
538 : /* GetGDTFromCppType() */
539 : /************************************************************************/
540 :
541 : namespace
542 : {
543 : template <class T> struct GetGDTFromCppType;
544 :
545 : #define DEFINE_GetGDTFromCppType(T, eDT) \
546 : template <> struct GetGDTFromCppType<T> \
547 : { \
548 : static constexpr GDALDataType GDT = eDT; \
549 : }
550 :
551 : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
552 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
553 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
554 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
555 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
556 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
557 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
558 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
559 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
560 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
561 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
562 : // Not allowed by C++ standard
563 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
564 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
565 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
566 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
567 : } // namespace
568 :
569 : /************************************************************************/
570 : /* ReadRaster() */
571 : /************************************************************************/
572 :
573 : // clang-format off
574 : /** Read a region of image data for this band.
575 : *
576 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
577 : * for common use cases, like reading a whole band.
578 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
579 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
580 : * float, double, std::complex<float|double>.
581 : *
582 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
583 : * and can allocate memory automatically.
584 : *
585 : * To read a whole band (assuming it fits into memory), as an array of double:
586 : *
587 : \code{.cpp}
588 : double* myArray = static_cast<double*>(
589 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
590 : // TODO: check here that myArray != nullptr
591 : const size_t nArrayEltCount =
592 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
593 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
594 : {
595 : // do something
596 : }
597 : VSIFree(myArray)
598 : \endcode
599 : *
600 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
601 : *
602 : \code{.cpp}
603 : double* myArray = static_cast<double*>(
604 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
605 : // TODO: check here that myArray != nullptr
606 : const size_t nArrayEltCount = 128 * 128;
607 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
608 : {
609 : // do something
610 : }
611 : VSIFree(myArray)
612 : \endcode
613 : *
614 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
615 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
616 : * instance of this dataset) concurrently from several threads.
617 : *
618 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
619 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
620 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
621 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
622 : * Or use nLineSpace and a possibly shifted pData value.
623 : *
624 : * @param[out] pData The buffer into which the data should be written.
625 : * This buffer must contain at least nBufXSize *
626 : * nBufYSize words of type T. It is organized in left to right,
627 : * top to bottom pixel order, and fully packed.
628 : * The type of the buffer does not need to be the one of GetDataType(). The
629 : * method will perform data type translation (with potential rounding, clamping)
630 : * if needed.
631 : *
632 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
633 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
634 : * return in error if it is not. If set to zero, then pData is trusted to be
635 : * large enough.
636 : *
637 : * @param dfXOff The pixel offset to the top left corner of the region
638 : * of the band to be accessed. This would be zero to start from the left side.
639 : * Defaults to 0.
640 : *
641 : * @param dfYOff The line offset to the top left corner of the region
642 : * of the band to be accessed. This would be zero to start from the top.
643 : * Defaults to 0.
644 : *
645 : * @param dfXSize The width of the region of the band to be accessed in pixels.
646 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
647 : * dfXSize is set to the band width.
648 : *
649 : * @param dfYSize The height of the region of the band to be accessed in lines.
650 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
651 : * dfYSize is set to the band height.
652 : *
653 : * @param nBufXSize the width of the buffer image into which the desired region
654 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
655 : * then nBufXSize is initialized with dfXSize.
656 : *
657 : * @param nBufYSize the height of the buffer image into which the desired region
658 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
659 : * then nBufYSize is initialized with dfYSize.
660 : *
661 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
662 : *
663 : * @param pfnProgress Progress function. May be nullptr.
664 : *
665 : * @param pProgressData User data of pfnProgress. May be nullptr.
666 : *
667 : * @return CE_Failure if the access fails, otherwise CE_None.
668 : *
669 : * @see GDALRasterBand::RasterIO()
670 : * @since GDAL 3.10
671 : */
672 : // clang-format on
673 :
674 : template <class T>
675 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
676 : double dfXOff, double dfYOff, double dfXSize,
677 : double dfYSize, size_t nBufXSize,
678 : size_t nBufYSize,
679 : GDALRIOResampleAlg eResampleAlg,
680 : GDALProgressFunc pfnProgress,
681 : void *pProgressData) const
682 : {
683 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
684 : {
685 2 : return CE_Failure;
686 : }
687 :
688 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
689 : {
690 16 : dfXSize = nRasterXSize;
691 16 : dfYSize = nRasterYSize;
692 : }
693 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
694 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
695 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
696 2 : dfYOff + dfYSize > INT_MAX)
697 : {
698 0 : return CE_Failure;
699 : }
700 :
701 : GDALRasterIOExtraArg sExtraArg;
702 18 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
703 18 : CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
704 18 : CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
705 18 : CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
706 18 : CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
707 18 : sExtraArg.eResampleAlg = eResampleAlg;
708 18 : sExtraArg.pfnProgress = pfnProgress;
709 18 : sExtraArg.pProgressData = pProgressData;
710 18 : sExtraArg.bFloatingPointWindowValidity = true;
711 18 : sExtraArg.dfXOff = dfXOff;
712 18 : sExtraArg.dfYOff = dfYOff;
713 18 : sExtraArg.dfXSize = dfXSize;
714 18 : sExtraArg.dfYSize = dfYSize;
715 :
716 18 : const int nXOff = static_cast<int>(dfXOff);
717 18 : const int nYOff = static_cast<int>(dfYOff);
718 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
719 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
720 18 : if (nBufXSize == 0 && nBufYSize == 0)
721 : {
722 17 : if (static_cast<int>(dfXSize) == dfXSize &&
723 17 : static_cast<int>(dfYSize) == dfYSize)
724 : {
725 17 : nBufXSize = static_cast<int>(dfXSize);
726 17 : nBufYSize = static_cast<int>(dfYSize);
727 : }
728 : else
729 : {
730 0 : CPLError(CE_Failure, CPLE_AppDefined,
731 : "nBufXSize and nBufYSize must be provided if dfXSize or "
732 : "dfYSize is not an integer value");
733 0 : return CE_Failure;
734 : }
735 : }
736 18 : if (nBufXSize == 0 || nBufYSize == 0)
737 : {
738 0 : CPLDebug("GDAL",
739 : "RasterIO() skipped for odd window or buffer size.\n"
740 : " Window = (%d,%d)x%dx%d\n"
741 : " Buffer = %dx%d\n",
742 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
743 : static_cast<int>(nBufYSize));
744 :
745 0 : return CE_None;
746 : }
747 :
748 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
749 : {
750 1 : CPLError(CE_Failure, CPLE_AppDefined,
751 : "Provided array is not large enough");
752 1 : return CE_Failure;
753 : }
754 :
755 17 : constexpr GSpacing nPixelSpace = sizeof(T);
756 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
757 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
758 :
759 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
760 :
761 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
762 : static_cast<int>(nBufXSize),
763 : static_cast<int>(nBufYSize), eBufType,
764 17 : nPixelSpace, nLineSpace, &sExtraArg);
765 : }
766 :
767 : //! @cond Doxygen_Suppress
768 :
769 : #define INSTANTIATE_READ_RASTER(T) \
770 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
771 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
772 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
773 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
774 : void *pProgressData) const;
775 :
776 : INSTANTIATE_READ_RASTER(uint8_t)
777 : INSTANTIATE_READ_RASTER(int8_t)
778 : INSTANTIATE_READ_RASTER(uint16_t)
779 : INSTANTIATE_READ_RASTER(int16_t)
780 : INSTANTIATE_READ_RASTER(uint32_t)
781 : INSTANTIATE_READ_RASTER(int32_t)
782 : INSTANTIATE_READ_RASTER(uint64_t)
783 : INSTANTIATE_READ_RASTER(int64_t)
784 : INSTANTIATE_READ_RASTER(GFloat16)
785 : INSTANTIATE_READ_RASTER(float)
786 : INSTANTIATE_READ_RASTER(double)
787 : // Not allowed by C++ standard
788 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
789 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
790 : INSTANTIATE_READ_RASTER(std::complex<float>)
791 : INSTANTIATE_READ_RASTER(std::complex<double>)
792 :
793 : //! @endcond
794 :
795 : /************************************************************************/
796 : /* ReadRaster() */
797 : /************************************************************************/
798 :
799 : /** Read a region of image data for this band.
800 : *
801 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
802 : * for common use cases, like reading a whole band.
803 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
804 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
805 : * float, double, std::complex<float|double>.
806 : *
807 : * To read a whole band (assuming it fits into memory), as a vector of double:
808 : *
809 : \code
810 : std::vector<double> myArray;
811 : if (poBand->ReadRaster(myArray) == CE_None)
812 : {
813 : // do something
814 : }
815 : \endcode
816 : *
817 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
818 : *
819 : \code{.cpp}
820 : std::vector<double> myArray;
821 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
822 : {
823 : // do something
824 : }
825 : \endcode
826 : *
827 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
828 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
829 : * instance of this dataset) concurrently from several threads.
830 : *
831 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
832 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
833 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
834 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
835 : * Or use nLineSpace and a possibly shifted pData value.
836 : *
837 : * @param[out] vData The vector into which the data should be written.
838 : * The vector will be resized, if needed, to contain at least nBufXSize *
839 : * nBufYSize values. The values in the vector are organized in left to right,
840 : * top to bottom pixel order, and fully packed.
841 : * The type of the vector does not need to be the one of GetDataType(). The
842 : * method will perform data type translation (with potential rounding, clamping)
843 : * if needed.
844 : *
845 : * @param dfXOff The pixel offset to the top left corner of the region
846 : * of the band to be accessed. This would be zero to start from the left side.
847 : * Defaults to 0.
848 : *
849 : * @param dfYOff The line offset to the top left corner of the region
850 : * of the band to be accessed. This would be zero to start from the top.
851 : * Defaults to 0.
852 : *
853 : * @param dfXSize The width of the region of the band to be accessed in pixels.
854 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
855 : * dfXSize is set to the band width.
856 : *
857 : * @param dfYSize The height of the region of the band to be accessed in lines.
858 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
859 : * dfYSize is set to the band height.
860 : *
861 : * @param nBufXSize the width of the buffer image into which the desired region
862 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
863 : * then nBufXSize is initialized with dfXSize.
864 : *
865 : * @param nBufYSize the height of the buffer image into which the desired region
866 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
867 : * then nBufYSize is initialized with dfYSize.
868 : *
869 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
870 : *
871 : * @param pfnProgress Progress function. May be nullptr.
872 : *
873 : * @param pProgressData User data of pfnProgress. May be nullptr.
874 : *
875 : * @return CE_Failure if the access fails, otherwise CE_None.
876 : *
877 : * @see GDALRasterBand::RasterIO()
878 : * @since GDAL 3.10
879 : */
880 : template <class T>
881 90 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
882 : double dfYOff, double dfXSize, double dfYSize,
883 : size_t nBufXSize, size_t nBufYSize,
884 : GDALRIOResampleAlg eResampleAlg,
885 : GDALProgressFunc pfnProgress,
886 : void *pProgressData) const
887 : {
888 90 : if (((nBufXSize | nBufYSize) >> 31) != 0)
889 : {
890 2 : return CE_Failure;
891 : }
892 :
893 88 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
894 : {
895 81 : dfXSize = nRasterXSize;
896 81 : dfYSize = nRasterYSize;
897 : }
898 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
899 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
900 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
901 7 : dfYOff + dfYSize > INT_MAX)
902 : {
903 0 : return CE_Failure;
904 : }
905 :
906 : GDALRasterIOExtraArg sExtraArg;
907 88 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
908 88 : CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
909 88 : CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
910 88 : CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
911 88 : CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
912 88 : sExtraArg.eResampleAlg = eResampleAlg;
913 88 : sExtraArg.pfnProgress = pfnProgress;
914 88 : sExtraArg.pProgressData = pProgressData;
915 88 : sExtraArg.bFloatingPointWindowValidity = true;
916 88 : sExtraArg.dfXOff = dfXOff;
917 88 : sExtraArg.dfYOff = dfYOff;
918 88 : sExtraArg.dfXSize = dfXSize;
919 88 : sExtraArg.dfYSize = dfYSize;
920 :
921 88 : const int nXOff = static_cast<int>(dfXOff);
922 88 : const int nYOff = static_cast<int>(dfYOff);
923 88 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
924 88 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
925 88 : if (nBufXSize == 0 && nBufYSize == 0)
926 : {
927 84 : if (static_cast<int>(dfXSize) == dfXSize &&
928 83 : static_cast<int>(dfYSize) == dfYSize)
929 : {
930 83 : nBufXSize = static_cast<int>(dfXSize);
931 83 : nBufYSize = static_cast<int>(dfYSize);
932 : }
933 : else
934 : {
935 1 : CPLError(CE_Failure, CPLE_AppDefined,
936 : "nBufXSize and nBufYSize must be provided if "
937 : "dfXSize or dfYSize is not an integer value");
938 1 : return CE_Failure;
939 : }
940 : }
941 87 : if (nBufXSize == 0 || nBufYSize == 0)
942 : {
943 0 : CPLDebug("GDAL",
944 : "RasterIO() skipped for odd window or buffer size.\n"
945 : " Window = (%d,%d)x%dx%d\n"
946 : " Buffer = %dx%d\n",
947 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
948 : static_cast<int>(nBufYSize));
949 :
950 0 : return CE_None;
951 : }
952 :
953 : if constexpr (SIZEOF_VOIDP < 8)
954 : {
955 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
956 : {
957 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
958 : return CE_Failure;
959 : }
960 : }
961 :
962 87 : if (vData.size() < nBufXSize * nBufYSize)
963 : {
964 : try
965 : {
966 85 : vData.resize(nBufXSize * nBufYSize);
967 : }
968 1 : catch (const std::exception &)
969 : {
970 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
971 1 : return CE_Failure;
972 : }
973 : }
974 :
975 86 : constexpr GSpacing nPixelSpace = sizeof(T);
976 86 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
977 86 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
978 :
979 86 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
980 :
981 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
982 : vData.data(), static_cast<int>(nBufXSize),
983 : static_cast<int>(nBufYSize), eBufType,
984 86 : nPixelSpace, nLineSpace, &sExtraArg);
985 : }
986 :
987 : //! @cond Doxygen_Suppress
988 :
989 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
990 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
991 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
992 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
993 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
994 : void *pProgressData) const;
995 :
996 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
997 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
998 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
999 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
1000 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
1001 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
1002 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
1003 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
1004 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
1005 : INSTANTIATE_READ_RASTER_VECTOR(float)
1006 : INSTANTIATE_READ_RASTER_VECTOR(double)
1007 : // Not allowed by C++ standard
1008 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
1009 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1010 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1011 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1012 :
1013 : //! @endcond
1014 :
1015 : /************************************************************************/
1016 : /* ReadBlock() */
1017 : /************************************************************************/
1018 :
1019 : /**
1020 : * \brief Read a block of image data efficiently.
1021 : *
1022 : * This method accesses a "natural" block from the raster band without
1023 : * resampling, or data type conversion. For a more generalized, but
1024 : * potentially less efficient access use RasterIO().
1025 : *
1026 : * This method is the same as the C GDALReadBlock() function.
1027 : *
1028 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1029 : * block oriented data without an extra copy into an application buffer.
1030 : *
1031 : * The following code would efficiently compute a histogram of eight bit
1032 : * raster data. Note that the final block may be partial ... data beyond
1033 : * the edge of the underlying raster band in these edge blocks is of an
1034 : * undetermined value.
1035 : *
1036 : \code{.cpp}
1037 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1038 :
1039 : {
1040 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1041 :
1042 : CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1043 :
1044 : int nXBlockSize, nYBlockSize;
1045 :
1046 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1047 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1048 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1049 :
1050 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1051 :
1052 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1053 : {
1054 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1055 : {
1056 : int nXValid, nYValid;
1057 :
1058 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1059 :
1060 : // Compute the portion of the block that is valid
1061 : // for partial edge blocks.
1062 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1063 :
1064 : // Collect the histogram counts.
1065 : for( int iY = 0; iY < nYValid; iY++ )
1066 : {
1067 : for( int iX = 0; iX < nXValid; iX++ )
1068 : {
1069 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1070 : }
1071 : }
1072 : }
1073 : }
1074 : }
1075 : \endcode
1076 : *
1077 : * @param nXBlockOff the horizontal block offset, with zero indicating
1078 : * the left most block, 1 the next block and so forth.
1079 : *
1080 : * @param nYBlockOff the vertical block offset, with zero indicating
1081 : * the top most block, 1 the next block and so forth.
1082 : *
1083 : * @param pImage the buffer into which the data will be read. The buffer
1084 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1085 : * of type GetRasterDataType().
1086 : *
1087 : * @return CE_None on success or CE_Failure on an error.
1088 : */
1089 :
1090 1084 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1091 :
1092 : {
1093 : /* -------------------------------------------------------------------- */
1094 : /* Validate arguments. */
1095 : /* -------------------------------------------------------------------- */
1096 1084 : CPLAssert(pImage != nullptr);
1097 :
1098 1084 : if (!InitBlockInfo())
1099 0 : return CE_Failure;
1100 :
1101 1084 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1102 : {
1103 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1104 : "Illegal nXBlockOff value (%d) in "
1105 : "GDALRasterBand::ReadBlock()\n",
1106 : nXBlockOff);
1107 :
1108 0 : return (CE_Failure);
1109 : }
1110 :
1111 1084 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1112 : {
1113 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1114 : "Illegal nYBlockOff value (%d) in "
1115 : "GDALRasterBand::ReadBlock()\n",
1116 : nYBlockOff);
1117 :
1118 0 : return (CE_Failure);
1119 : }
1120 :
1121 : /* -------------------------------------------------------------------- */
1122 : /* Invoke underlying implementation method. */
1123 : /* -------------------------------------------------------------------- */
1124 :
1125 1084 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1126 1084 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1127 1084 : if (bCallLeaveReadWrite)
1128 4 : LeaveReadWrite();
1129 1084 : return eErr;
1130 : }
1131 :
1132 : /************************************************************************/
1133 : /* GDALReadBlock() */
1134 : /************************************************************************/
1135 :
1136 : /**
1137 : * \brief Read a block of image data efficiently.
1138 : *
1139 : * @see GDALRasterBand::ReadBlock()
1140 : */
1141 :
1142 79 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1143 : void *pData)
1144 :
1145 : {
1146 79 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1147 :
1148 79 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1149 79 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1150 : }
1151 :
1152 : /************************************************************************/
1153 : /* IReadBlock() */
1154 : /************************************************************************/
1155 :
1156 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1157 : * ) \brief Read a block of data.
1158 : *
1159 : * Default internal implementation ... to be overridden by
1160 : * subclasses that support reading.
1161 : * @param nBlockXOff Block X Offset
1162 : * @param nBlockYOff Block Y Offset
1163 : * @param pData Pixel buffer into which to place read data.
1164 : * @return CE_None on success or CE_Failure on an error.
1165 : */
1166 :
1167 : /************************************************************************/
1168 : /* IWriteBlock() */
1169 : /************************************************************************/
1170 :
1171 : /**
1172 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1173 : * Write a block of data.
1174 : *
1175 : * Default internal implementation ... to be overridden by
1176 : * subclasses that support writing.
1177 : * @param nBlockXOff Block X Offset
1178 : * @param nBlockYOff Block Y Offset
1179 : * @param pData Pixel buffer to write
1180 : * @return CE_None on success or CE_Failure on an error.
1181 : */
1182 :
1183 : /**/
1184 : /**/
1185 :
1186 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1187 : void * /*pData*/)
1188 :
1189 : {
1190 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1191 0 : ReportError(CE_Failure, CPLE_NotSupported,
1192 : "WriteBlock() not supported for this dataset.");
1193 :
1194 0 : return (CE_Failure);
1195 : }
1196 :
1197 : /************************************************************************/
1198 : /* WriteBlock() */
1199 : /************************************************************************/
1200 :
1201 : /**
1202 : * \brief Write a block of image data efficiently.
1203 : *
1204 : * This method accesses a "natural" block from the raster band without
1205 : * resampling, or data type conversion. For a more generalized, but
1206 : * potentially less efficient access use RasterIO().
1207 : *
1208 : * This method is the same as the C GDALWriteBlock() function.
1209 : *
1210 : * See ReadBlock() for an example of block oriented data access.
1211 : *
1212 : * @param nXBlockOff the horizontal block offset, with zero indicating
1213 : * the left most block, 1 the next block and so forth.
1214 : *
1215 : * @param nYBlockOff the vertical block offset, with zero indicating
1216 : * the left most block, 1 the next block and so forth.
1217 : *
1218 : * @param pImage the buffer from which the data will be written. The buffer
1219 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1220 : * of type GetRasterDataType(). Note that the content of the buffer might be
1221 : * temporarily modified during the execution of this method (and eventually
1222 : * restored back to its original content), so it is not safe to use a buffer
1223 : * stored in a read-only section of the calling program.
1224 : *
1225 : * @return CE_None on success or CE_Failure on an error.
1226 : */
1227 :
1228 4881 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1229 :
1230 : {
1231 : /* -------------------------------------------------------------------- */
1232 : /* Validate arguments. */
1233 : /* -------------------------------------------------------------------- */
1234 4881 : CPLAssert(pImage != nullptr);
1235 :
1236 4881 : if (!InitBlockInfo())
1237 0 : return CE_Failure;
1238 :
1239 4881 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1240 : {
1241 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1242 : "Illegal nXBlockOff value (%d) in "
1243 : "GDALRasterBand::WriteBlock()\n",
1244 : nXBlockOff);
1245 :
1246 0 : return (CE_Failure);
1247 : }
1248 :
1249 4881 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1250 : {
1251 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1252 : "Illegal nYBlockOff value (%d) in "
1253 : "GDALRasterBand::WriteBlock()\n",
1254 : nYBlockOff);
1255 :
1256 0 : return (CE_Failure);
1257 : }
1258 :
1259 4881 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1260 : {
1261 0 : return CE_Failure;
1262 : }
1263 :
1264 4881 : if (eFlushBlockErr != CE_None)
1265 : {
1266 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1267 : "An error occurred while writing a dirty block "
1268 : "from GDALRasterBand::WriteBlock");
1269 0 : CPLErr eErr = eFlushBlockErr;
1270 0 : eFlushBlockErr = CE_None;
1271 0 : return eErr;
1272 : }
1273 :
1274 : /* -------------------------------------------------------------------- */
1275 : /* Invoke underlying implementation method. */
1276 : /* -------------------------------------------------------------------- */
1277 :
1278 4881 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1279 4881 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1280 4881 : if (bCallLeaveReadWrite)
1281 4881 : LeaveReadWrite();
1282 :
1283 4881 : return eErr;
1284 : }
1285 :
1286 : /************************************************************************/
1287 : /* GDALWriteBlock() */
1288 : /************************************************************************/
1289 :
1290 : /**
1291 : * \brief Write a block of image data efficiently.
1292 : *
1293 : * @see GDALRasterBand::WriteBlock()
1294 : */
1295 :
1296 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1297 : void *pData)
1298 :
1299 : {
1300 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1301 :
1302 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1303 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1304 : }
1305 :
1306 : /************************************************************************/
1307 : /* EmitErrorMessageIfWriteNotSupported() */
1308 : /************************************************************************/
1309 :
1310 : /**
1311 : * Emit an error message if a write operation to this band is not supported.
1312 : *
1313 : * The base implementation will emit an error message if the access mode is
1314 : * read-only. Derived classes may implement it to provide a custom message.
1315 : *
1316 : * @param pszCaller Calling function.
1317 : * @return true if an error message has been emitted.
1318 : */
1319 688532 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1320 : const char *pszCaller) const
1321 : {
1322 688532 : if (eAccess == GA_ReadOnly)
1323 : {
1324 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1325 : "%s: attempt to write to dataset opened in read-only mode.",
1326 : pszCaller);
1327 :
1328 4 : return true;
1329 : }
1330 688528 : return false;
1331 : }
1332 :
1333 : /************************************************************************/
1334 : /* GetActualBlockSize() */
1335 : /************************************************************************/
1336 : /**
1337 : * \brief Fetch the actual block size for a given block offset.
1338 : *
1339 : * Handles partial blocks at the edges of the raster and returns the true
1340 : * number of pixels
1341 : *
1342 : * @param nXBlockOff the horizontal block offset for which to calculate the
1343 : * number of valid pixels, with zero indicating the left most block, 1 the next
1344 : * block and so forth.
1345 : *
1346 : * @param nYBlockOff the vertical block offset, with zero indicating
1347 : * the top most block, 1 the next block and so forth.
1348 : *
1349 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1350 : * the x direction will be stored
1351 : *
1352 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1353 : * the y direction will be stored
1354 : *
1355 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1356 : *
1357 : */
1358 34641 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1359 : int *pnXValid, int *pnYValid) const
1360 : {
1361 69281 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1362 69278 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1363 69274 : nYBlockOff < 0 || nBlockYSize == 0 ||
1364 34637 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1365 : {
1366 6 : return CE_Failure;
1367 : }
1368 :
1369 34635 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1370 34635 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1371 :
1372 34635 : *pnXValid = nBlockXSize;
1373 34635 : *pnYValid = nBlockYSize;
1374 :
1375 34635 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1376 : {
1377 33298 : *pnXValid = nRasterXSize - nXPixelOff;
1378 : }
1379 :
1380 34635 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1381 : {
1382 3324 : *pnYValid = nRasterYSize - nYPixelOff;
1383 : }
1384 :
1385 34635 : return CE_None;
1386 : }
1387 :
1388 : /************************************************************************/
1389 : /* GDALGetActualBlockSize() */
1390 : /************************************************************************/
1391 :
1392 : /**
1393 : * \brief Retrieve the actual block size for a given block offset.
1394 : *
1395 : * @see GDALRasterBand::GetActualBlockSize()
1396 : */
1397 :
1398 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1399 : int nYBlockOff, int *pnXValid,
1400 : int *pnYValid)
1401 :
1402 : {
1403 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1404 :
1405 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1406 : return (
1407 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1408 : }
1409 :
1410 : /************************************************************************/
1411 : /* GetSuggestedBlockAccessPattern() */
1412 : /************************************************************************/
1413 :
1414 : /**
1415 : * \brief Return the suggested/most efficient access pattern to blocks
1416 : * (for read operations).
1417 : *
1418 : * While all GDAL drivers have to expose a block size, not all can guarantee
1419 : * efficient random access (GSBAP_RANDOM) to any block.
1420 : * Some drivers for example decompress sequentially a compressed stream from
1421 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1422 : * case best performance will be achieved while reading blocks in that order.
1423 : * (accessing blocks in random access in such rasters typically causes the
1424 : * decoding to be re-initialized from the start if accessing blocks in
1425 : * a non-sequential order)
1426 : *
1427 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1428 : * returned by drivers that expose a somewhat artificial block size, because
1429 : * they can extract any part of a raster, but in a rather inefficient way.
1430 : *
1431 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1432 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1433 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1434 : * most efficient strategy is to read as many pixels as possible in the less
1435 : * RasterIO() operations.
1436 : *
1437 : * The return of this method is for example used to determine the swath size
1438 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1439 : *
1440 : * @since GDAL 3.6
1441 : */
1442 :
1443 : GDALSuggestedBlockAccessPattern
1444 2512 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1445 : {
1446 2512 : return GSBAP_UNKNOWN;
1447 : }
1448 :
1449 : /************************************************************************/
1450 : /* GetRasterDataType() */
1451 : /************************************************************************/
1452 :
1453 : /**
1454 : * \brief Fetch the pixel data type for this band.
1455 : *
1456 : * This method is the same as the C function GDALGetRasterDataType().
1457 : *
1458 : * @return the data type of pixels for this band.
1459 : */
1460 :
1461 9110900 : GDALDataType GDALRasterBand::GetRasterDataType() const
1462 :
1463 : {
1464 9110900 : return eDataType;
1465 : }
1466 :
1467 : /************************************************************************/
1468 : /* GDALGetRasterDataType() */
1469 : /************************************************************************/
1470 :
1471 : /**
1472 : * \brief Fetch the pixel data type for this band.
1473 : *
1474 : * @see GDALRasterBand::GetRasterDataType()
1475 : */
1476 :
1477 911828 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1478 :
1479 : {
1480 911828 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1481 :
1482 911828 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1483 911828 : return poBand->GetRasterDataType();
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* GetBlockSize() */
1488 : /************************************************************************/
1489 :
1490 : /**
1491 : * \brief Fetch the "natural" block size of this band.
1492 : *
1493 : * GDAL contains a concept of the natural block size of rasters so that
1494 : * applications can organized data access efficiently for some file formats.
1495 : * The natural block size is the block size that is most efficient for
1496 : * accessing the format. For many formats this is simple a whole scanline
1497 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1498 : *
1499 : * However, for tiled images this will typically be the tile size.
1500 : *
1501 : * Note that the X and Y block sizes don't have to divide the image size
1502 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1503 : * See ReadBlock() for an example of code dealing with these issues.
1504 : *
1505 : * This method is the same as the C function GDALGetBlockSize().
1506 : *
1507 : * @param pnXSize integer to put the X block size into or NULL.
1508 : *
1509 : * @param pnYSize integer to put the Y block size into or NULL.
1510 : */
1511 :
1512 5611060 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1513 :
1514 : {
1515 5611060 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1516 : {
1517 0 : ReportError(CE_Failure, CPLE_AppDefined,
1518 0 : "Invalid block dimension : %d * %d", nBlockXSize,
1519 0 : nBlockYSize);
1520 0 : if (pnXSize != nullptr)
1521 0 : *pnXSize = 0;
1522 0 : if (pnYSize != nullptr)
1523 0 : *pnYSize = 0;
1524 : }
1525 : else
1526 : {
1527 5611060 : if (pnXSize != nullptr)
1528 5611060 : *pnXSize = nBlockXSize;
1529 5611060 : if (pnYSize != nullptr)
1530 5611060 : *pnYSize = nBlockYSize;
1531 : }
1532 5611060 : }
1533 :
1534 : /************************************************************************/
1535 : /* GDALGetBlockSize() */
1536 : /************************************************************************/
1537 :
1538 : /**
1539 : * \brief Fetch the "natural" block size of this band.
1540 : *
1541 : * @see GDALRasterBand::GetBlockSize()
1542 : */
1543 :
1544 41449 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1545 : int *pnYSize)
1546 :
1547 : {
1548 41449 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1549 :
1550 41449 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1551 41449 : poBand->GetBlockSize(pnXSize, pnYSize);
1552 : }
1553 :
1554 : /************************************************************************/
1555 : /* InitBlockInfo() */
1556 : /************************************************************************/
1557 :
1558 : //! @cond Doxygen_Suppress
1559 3695640 : int GDALRasterBand::InitBlockInfo()
1560 :
1561 : {
1562 3695640 : if (poBandBlockCache != nullptr)
1563 3453810 : return poBandBlockCache->IsInitOK();
1564 :
1565 : /* Do some validation of raster and block dimensions in case the driver */
1566 : /* would have neglected to do it itself */
1567 241833 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1568 : {
1569 0 : ReportError(CE_Failure, CPLE_AppDefined,
1570 : "Invalid block dimension : %d * %d", nBlockXSize,
1571 : nBlockYSize);
1572 0 : return FALSE;
1573 : }
1574 :
1575 241833 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1576 : {
1577 0 : ReportError(CE_Failure, CPLE_AppDefined,
1578 : "Invalid raster dimension : %d * %d", nRasterXSize,
1579 : nRasterYSize);
1580 0 : return FALSE;
1581 : }
1582 :
1583 241833 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1584 241833 : if (nDataTypeSize == 0)
1585 : {
1586 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1587 0 : return FALSE;
1588 : }
1589 :
1590 : #if SIZEOF_VOIDP == 4
1591 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1592 : {
1593 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1594 : * multiplication in other cases */
1595 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1596 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1597 : {
1598 : ReportError(CE_Failure, CPLE_NotSupported,
1599 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1600 : nBlockYSize);
1601 : return FALSE;
1602 : }
1603 : }
1604 : #endif
1605 :
1606 241833 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1607 241833 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1608 :
1609 : const char *pszBlockStrategy =
1610 241833 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1611 241833 : bool bUseArray = true;
1612 241833 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1613 : {
1614 241793 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1615 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1616 : {
1617 241774 : GUIntBig nBlockCount =
1618 241774 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1619 241774 : if (poDS != nullptr)
1620 241563 : nBlockCount *= poDS->GetRasterCount();
1621 241774 : bUseArray = (nBlockCount < 1024 * 1024);
1622 : }
1623 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1624 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1625 : {
1626 0 : bUseArray = false;
1627 241793 : }
1628 : }
1629 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1630 40 : bUseArray = false;
1631 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1632 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1633 : pszBlockStrategy);
1634 :
1635 241833 : if (bUseArray)
1636 241762 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1637 : else
1638 : {
1639 71 : if (nBand == 1)
1640 26 : CPLDebug("GDAL", "Use hashset band block cache");
1641 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1642 : }
1643 241833 : if (poBandBlockCache == nullptr)
1644 0 : return FALSE;
1645 241833 : return poBandBlockCache->Init();
1646 : }
1647 :
1648 : //! @endcond
1649 :
1650 : /************************************************************************/
1651 : /* FlushCache() */
1652 : /************************************************************************/
1653 :
1654 : /**
1655 : * \brief Flush raster data cache.
1656 : *
1657 : * This call will recover memory used to cache data blocks for this raster
1658 : * band, and ensure that new requests are referred to the underlying driver.
1659 : *
1660 : * This method is the same as the C function GDALFlushRasterCache().
1661 : *
1662 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1663 : * @return CE_None on success.
1664 : */
1665 :
1666 5911550 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1667 :
1668 : {
1669 6048260 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1670 136705 : poBandBlockCache)
1671 4366 : poBandBlockCache->DisableDirtyBlockWriting();
1672 :
1673 5911550 : CPLErr eGlobalErr = eFlushBlockErr;
1674 :
1675 5911550 : if (eFlushBlockErr != CE_None)
1676 : {
1677 0 : ReportError(
1678 : eFlushBlockErr, CPLE_AppDefined,
1679 : "An error occurred while writing a dirty block from FlushCache");
1680 0 : eFlushBlockErr = CE_None;
1681 : }
1682 :
1683 5911550 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1684 5137440 : return eGlobalErr;
1685 :
1686 774110 : return poBandBlockCache->FlushCache();
1687 : }
1688 :
1689 : /************************************************************************/
1690 : /* GDALFlushRasterCache() */
1691 : /************************************************************************/
1692 :
1693 : /**
1694 : * \brief Flush raster data cache.
1695 : *
1696 : * @see GDALRasterBand::FlushCache()
1697 : */
1698 :
1699 626 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1700 :
1701 : {
1702 626 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1703 :
1704 626 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1705 : }
1706 :
1707 : /************************************************************************/
1708 : /* DropCache() */
1709 : /************************************************************************/
1710 :
1711 : /**
1712 : * \brief Drop raster data cache : data in cache will be lost.
1713 : *
1714 : * This call will recover memory used to cache data blocks for this raster
1715 : * band, and ensure that new requests are referred to the underlying driver.
1716 : *
1717 : * This method is the same as the C function GDALDropRasterCache().
1718 : *
1719 : * @return CE_None on success.
1720 : * @since 3.9
1721 : */
1722 :
1723 1 : CPLErr GDALRasterBand::DropCache()
1724 :
1725 : {
1726 1 : CPLErr result = CE_None;
1727 :
1728 1 : if (poBandBlockCache)
1729 1 : poBandBlockCache->DisableDirtyBlockWriting();
1730 :
1731 1 : CPLErr eGlobalErr = eFlushBlockErr;
1732 :
1733 1 : if (eFlushBlockErr != CE_None)
1734 : {
1735 0 : ReportError(
1736 : eFlushBlockErr, CPLE_AppDefined,
1737 : "An error occurred while writing a dirty block from DropCache");
1738 0 : eFlushBlockErr = CE_None;
1739 : }
1740 :
1741 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1742 0 : result = eGlobalErr;
1743 : else
1744 1 : result = poBandBlockCache->FlushCache();
1745 :
1746 1 : if (poBandBlockCache)
1747 1 : poBandBlockCache->EnableDirtyBlockWriting();
1748 :
1749 1 : return result;
1750 : }
1751 :
1752 : /************************************************************************/
1753 : /* GDALDropRasterCache() */
1754 : /************************************************************************/
1755 :
1756 : /**
1757 : * \brief Drop raster data cache.
1758 : *
1759 : * @see GDALRasterBand::DropCache()
1760 : * @since 3.9
1761 : */
1762 :
1763 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1764 :
1765 : {
1766 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1767 :
1768 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1769 : }
1770 :
1771 : /************************************************************************/
1772 : /* UnreferenceBlock() */
1773 : /* */
1774 : /* Unreference the block from our array of blocks */
1775 : /* This method should only be called by */
1776 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1777 : /* the block cache mutex) */
1778 : /************************************************************************/
1779 :
1780 29740 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1781 : {
1782 : #ifdef notdef
1783 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1784 : {
1785 : if (poBandBlockCache == nullptr)
1786 : printf("poBandBlockCache == NULL\n"); /*ok*/
1787 : else
1788 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1789 : printf("caller = %s\n", pszCaller); /*ok*/
1790 : printf("GDALRasterBand: %p\n", this); /*ok*/
1791 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1792 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1793 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1794 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1795 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1796 : poBlock->DumpBlock();
1797 : if (GetDataset() != nullptr)
1798 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1799 : GDALRasterBlock::Verify();
1800 : abort();
1801 : }
1802 : #endif
1803 29740 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1804 29740 : return poBandBlockCache->UnreferenceBlock(poBlock);
1805 : }
1806 :
1807 : /************************************************************************/
1808 : /* AddBlockToFreeList() */
1809 : /* */
1810 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1811 : /* finished with a block about to be free'd, they pass it to that */
1812 : /* method. */
1813 : /************************************************************************/
1814 :
1815 : //! @cond Doxygen_Suppress
1816 29740 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1817 : {
1818 29740 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1819 29740 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1820 : }
1821 :
1822 : //! @endcond
1823 :
1824 : /************************************************************************/
1825 : /* HasDirtyBlocks() */
1826 : /************************************************************************/
1827 :
1828 : //! @cond Doxygen_Suppress
1829 17 : bool GDALRasterBand::HasDirtyBlocks() const
1830 : {
1831 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1832 : }
1833 :
1834 : //! @endcond
1835 :
1836 : /************************************************************************/
1837 : /* FlushBlock() */
1838 : /************************************************************************/
1839 :
1840 : /** Flush a block out of the block cache.
1841 : * @param nXBlockOff block x offset
1842 : * @param nYBlockOff blocky offset
1843 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1844 : * @return CE_None in case of success, an error code otherwise.
1845 : */
1846 2316 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1847 : int bWriteDirtyBlock)
1848 :
1849 : {
1850 2316 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1851 0 : return (CE_Failure);
1852 :
1853 : /* -------------------------------------------------------------------- */
1854 : /* Validate the request */
1855 : /* -------------------------------------------------------------------- */
1856 2316 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1857 : {
1858 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1859 : "Illegal nBlockXOff value (%d) in "
1860 : "GDALRasterBand::FlushBlock()\n",
1861 : nXBlockOff);
1862 :
1863 0 : return (CE_Failure);
1864 : }
1865 :
1866 2316 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1867 : {
1868 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1869 : "Illegal nBlockYOff value (%d) in "
1870 : "GDALRasterBand::FlushBlock()\n",
1871 : nYBlockOff);
1872 :
1873 0 : return (CE_Failure);
1874 : }
1875 :
1876 2316 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1877 2316 : bWriteDirtyBlock);
1878 : }
1879 :
1880 : /************************************************************************/
1881 : /* TryGetLockedBlockRef() */
1882 : /************************************************************************/
1883 :
1884 : /**
1885 : * \brief Try fetching block ref.
1886 : *
1887 : * This method will returned the requested block (locked) if it is already
1888 : * in the block cache for the layer. If not, nullptr is returned.
1889 : *
1890 : * If a non-NULL value is returned, then a lock for the block will have been
1891 : * acquired on behalf of the caller. It is absolutely imperative that the
1892 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1893 : * severe problems may result.
1894 : *
1895 : * @param nXBlockOff the horizontal block offset, with zero indicating
1896 : * the left most block, 1 the next block and so forth.
1897 : *
1898 : * @param nYBlockOff the vertical block offset, with zero indicating
1899 : * the top most block, 1 the next block and so forth.
1900 : *
1901 : * @return NULL if block not available, or locked block pointer.
1902 : */
1903 :
1904 10803800 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1905 : int nYBlockOff)
1906 :
1907 : {
1908 10803800 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1909 174604 : return nullptr;
1910 :
1911 : /* -------------------------------------------------------------------- */
1912 : /* Validate the request */
1913 : /* -------------------------------------------------------------------- */
1914 10629200 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1915 : {
1916 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1917 : "Illegal nBlockXOff value (%d) in "
1918 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1919 : nXBlockOff);
1920 :
1921 0 : return (nullptr);
1922 : }
1923 :
1924 10629200 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1925 : {
1926 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1927 : "Illegal nBlockYOff value (%d) in "
1928 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1929 : nYBlockOff);
1930 :
1931 0 : return (nullptr);
1932 : }
1933 :
1934 10629200 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1935 : }
1936 :
1937 : /************************************************************************/
1938 : /* GetLockedBlockRef() */
1939 : /************************************************************************/
1940 :
1941 : /**
1942 : * \brief Fetch a pointer to an internally cached raster block.
1943 : *
1944 : * This method will returned the requested block (locked) if it is already
1945 : * in the block cache for the layer. If not, the block will be read from
1946 : * the driver, and placed in the layer block cached, then returned. If an
1947 : * error occurs reading the block from the driver, a NULL value will be
1948 : * returned.
1949 : *
1950 : * If a non-NULL value is returned, then a lock for the block will have been
1951 : * acquired on behalf of the caller. It is absolutely imperative that the
1952 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1953 : * severe problems may result.
1954 : *
1955 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1956 : * enable caching.
1957 : *
1958 : * @param nXBlockOff the horizontal block offset, with zero indicating
1959 : * the left most block, 1 the next block and so forth.
1960 : *
1961 : * @param nYBlockOff the vertical block offset, with zero indicating
1962 : * the top most block, 1 the next block and so forth.
1963 : *
1964 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1965 : * but not actually read from the source. This is useful when it will just
1966 : * be completely set and written back.
1967 : *
1968 : * @return pointer to the block object, or NULL on failure.
1969 : */
1970 :
1971 10493000 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1972 : int nYBlockOff,
1973 : int bJustInitialize)
1974 :
1975 : {
1976 : /* -------------------------------------------------------------------- */
1977 : /* Try and fetch from cache. */
1978 : /* -------------------------------------------------------------------- */
1979 10493000 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1980 :
1981 : /* -------------------------------------------------------------------- */
1982 : /* If we didn't find it in our memory cache, instantiate a */
1983 : /* block (potentially load from disk) and "adopt" it into the */
1984 : /* cache. */
1985 : /* -------------------------------------------------------------------- */
1986 10493000 : if (poBlock == nullptr)
1987 : {
1988 3416950 : if (!InitBlockInfo())
1989 0 : return (nullptr);
1990 :
1991 : /* --------------------------------------------------------------------
1992 : */
1993 : /* Validate the request */
1994 : /* --------------------------------------------------------------------
1995 : */
1996 3416950 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1997 : {
1998 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1999 : "Illegal nBlockXOff value (%d) in "
2000 : "GDALRasterBand::GetLockedBlockRef()\n",
2001 : nXBlockOff);
2002 :
2003 0 : return (nullptr);
2004 : }
2005 :
2006 3416950 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
2007 : {
2008 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2009 : "Illegal nBlockYOff value (%d) in "
2010 : "GDALRasterBand::GetLockedBlockRef()\n",
2011 : nYBlockOff);
2012 :
2013 0 : return (nullptr);
2014 : }
2015 :
2016 3416950 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2017 3416950 : if (poBlock == nullptr)
2018 0 : return nullptr;
2019 :
2020 3416950 : poBlock->AddLock();
2021 :
2022 : /* We need to temporarily drop the read-write lock in the following */
2023 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2024 : */
2025 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2026 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2027 : */
2028 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2029 : */
2030 : /* called and attempt at taking the lock on T2 (already taken).
2031 : * Similarly */
2032 : /* for T2 with D1, hence a deadlock situation (#6163) */
2033 : /* But this may open the door to other problems... */
2034 3416950 : if (poDS)
2035 3415540 : poDS->TemporarilyDropReadWriteLock();
2036 : /* allocate data space */
2037 3416950 : CPLErr eErr = poBlock->Internalize();
2038 3416950 : if (poDS)
2039 3415540 : poDS->ReacquireReadWriteLock();
2040 3416950 : if (eErr != CE_None)
2041 : {
2042 0 : poBlock->DropLock();
2043 0 : delete poBlock;
2044 0 : return nullptr;
2045 : }
2046 :
2047 3416950 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2048 : {
2049 0 : poBlock->DropLock();
2050 0 : delete poBlock;
2051 0 : return nullptr;
2052 : }
2053 :
2054 3416950 : if (!bJustInitialize)
2055 : {
2056 2907190 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2057 2907190 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2058 2907190 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2059 2907190 : if (bCallLeaveReadWrite)
2060 136224 : LeaveReadWrite();
2061 2907190 : if (eErr != CE_None)
2062 : {
2063 1166 : poBlock->DropLock();
2064 1166 : FlushBlock(nXBlockOff, nYBlockOff);
2065 1166 : ReportError(CE_Failure, CPLE_AppDefined,
2066 : "IReadBlock failed at X offset %d, Y offset %d%s",
2067 : nXBlockOff, nYBlockOff,
2068 1166 : (nErrorCounter != CPLGetErrorCounter())
2069 1164 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2070 : : "");
2071 1166 : return nullptr;
2072 : }
2073 :
2074 2906020 : nBlockReads++;
2075 2906020 : if (static_cast<GIntBig>(nBlockReads) ==
2076 2906020 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2077 259 : 1 &&
2078 259 : nBand == 1 && poDS != nullptr)
2079 : {
2080 181 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2081 181 : poDS->GetDescription());
2082 : }
2083 : }
2084 : }
2085 :
2086 10491900 : return poBlock;
2087 : }
2088 :
2089 : /************************************************************************/
2090 : /* Fill() */
2091 : /************************************************************************/
2092 :
2093 : /**
2094 : * \brief Fill this band with a constant value.
2095 : *
2096 : * GDAL makes no guarantees
2097 : * about what values pixels in newly created files are set to, so this
2098 : * method can be used to clear a band to a specified "default" value.
2099 : * The fill value is passed in as a double but this will be converted
2100 : * to the underlying type before writing to the file. An optional
2101 : * second argument allows the imaginary component of a complex
2102 : * constant value to be specified.
2103 : *
2104 : * This method is the same as the C function GDALFillRaster().
2105 : *
2106 : * @param dfRealValue Real component of fill value
2107 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2108 : *
2109 : * @return CE_Failure if the write fails, otherwise CE_None
2110 : */
2111 270122 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2112 : {
2113 :
2114 : // General approach is to construct a source block of the file's
2115 : // native type containing the appropriate value and then copy this
2116 : // to each block in the image via the RasterBlock cache. Using
2117 : // the cache means we avoid file I/O if it is not necessary, at the
2118 : // expense of some extra memcpy's (since we write to the
2119 : // RasterBlock cache, which is then at some point written to the
2120 : // underlying file, rather than simply directly to the underlying
2121 : // file.)
2122 :
2123 : // Check we can write to the file.
2124 270122 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2125 : {
2126 6 : return CE_Failure;
2127 : }
2128 :
2129 : // Make sure block parameters are set.
2130 270116 : if (!InitBlockInfo())
2131 0 : return CE_Failure;
2132 :
2133 : // Allocate the source block.
2134 270116 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2135 270116 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2136 270116 : auto blockByteSize = blockSize * elementSize;
2137 : unsigned char *srcBlock =
2138 270116 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2139 270116 : if (srcBlock == nullptr)
2140 : {
2141 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2142 : "GDALRasterBand::Fill(): Out of memory "
2143 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2144 : static_cast<GUIntBig>(blockByteSize));
2145 0 : return CE_Failure;
2146 : }
2147 :
2148 : // Initialize the source block.
2149 270116 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2150 270116 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2151 : elementSize, blockSize);
2152 :
2153 270116 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2154 :
2155 : // Write block to block cache
2156 893109 : for (int j = 0; j < nBlocksPerColumn; ++j)
2157 : {
2158 1540360 : for (int i = 0; i < nBlocksPerRow; ++i)
2159 : {
2160 917367 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2161 917367 : if (destBlock == nullptr)
2162 : {
2163 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2164 : "GDALRasterBand::Fill(): Error "
2165 : "while retrieving cache block.");
2166 0 : VSIFree(srcBlock);
2167 0 : return CE_Failure;
2168 : }
2169 917367 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2170 917367 : destBlock->MarkDirty();
2171 917367 : destBlock->DropLock();
2172 : }
2173 : }
2174 :
2175 270116 : if (bCallLeaveReadWrite)
2176 267842 : LeaveReadWrite();
2177 :
2178 : // Free up the source block
2179 270116 : VSIFree(srcBlock);
2180 :
2181 270116 : return CE_None;
2182 : }
2183 :
2184 : /************************************************************************/
2185 : /* GDALFillRaster() */
2186 : /************************************************************************/
2187 :
2188 : /**
2189 : * \brief Fill this band with a constant value.
2190 : *
2191 : * @see GDALRasterBand::Fill()
2192 : */
2193 269759 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2194 : double dfImaginaryValue)
2195 : {
2196 269759 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2197 :
2198 269759 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2199 269759 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2200 : }
2201 :
2202 : /************************************************************************/
2203 : /* GetAccess() */
2204 : /************************************************************************/
2205 :
2206 : /**
2207 : * \brief Find out if we have update permission for this band.
2208 : *
2209 : * This method is the same as the C function GDALGetRasterAccess().
2210 : *
2211 : * @return Either GA_Update or GA_ReadOnly.
2212 : */
2213 :
2214 3328 : GDALAccess GDALRasterBand::GetAccess()
2215 :
2216 : {
2217 3328 : return eAccess;
2218 : }
2219 :
2220 : /************************************************************************/
2221 : /* GDALGetRasterAccess() */
2222 : /************************************************************************/
2223 :
2224 : /**
2225 : * \brief Find out if we have update permission for this band.
2226 : *
2227 : * @see GDALRasterBand::GetAccess()
2228 : */
2229 :
2230 2665 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2231 :
2232 : {
2233 2665 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2234 :
2235 2665 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2236 2665 : return poBand->GetAccess();
2237 : }
2238 :
2239 : /************************************************************************/
2240 : /* GetCategoryNames() */
2241 : /************************************************************************/
2242 :
2243 : /**
2244 : * \brief Fetch the list of category names for this raster.
2245 : *
2246 : * The return list is a "StringList" in the sense of the CPL functions.
2247 : * That is a NULL terminated array of strings. Raster values without
2248 : * associated names will have an empty string in the returned list. The
2249 : * first entry in the list is for raster values of zero, and so on.
2250 : *
2251 : * The returned stringlist should not be altered or freed by the application.
2252 : * It may change on the next GDAL call, so please copy it if it is needed
2253 : * for any period of time.
2254 : *
2255 : * This method is the same as the C function GDALGetRasterCategoryNames().
2256 : *
2257 : * @return list of names, or NULL if none.
2258 : */
2259 :
2260 521 : char **GDALRasterBand::GetCategoryNames()
2261 :
2262 : {
2263 521 : return nullptr;
2264 : }
2265 :
2266 : /************************************************************************/
2267 : /* GDALGetRasterCategoryNames() */
2268 : /************************************************************************/
2269 :
2270 : /**
2271 : * \brief Fetch the list of category names for this raster.
2272 : *
2273 : * @see GDALRasterBand::GetCategoryNames()
2274 : */
2275 :
2276 211 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2277 :
2278 : {
2279 211 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2280 :
2281 211 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2282 211 : return poBand->GetCategoryNames();
2283 : }
2284 :
2285 : /************************************************************************/
2286 : /* SetCategoryNames() */
2287 : /************************************************************************/
2288 :
2289 : /**
2290 : * \fn GDALRasterBand::SetCategoryNames(char**)
2291 : * \brief Set the category names for this band.
2292 : *
2293 : * See the GetCategoryNames() method for more on the interpretation of
2294 : * category names.
2295 : *
2296 : * This method is the same as the C function GDALSetRasterCategoryNames().
2297 : *
2298 : * @param papszNames the NULL terminated StringList of category names. May
2299 : * be NULL to just clear the existing list.
2300 : *
2301 : * @return CE_None on success of CE_Failure on failure. If unsupported
2302 : * by the driver CE_Failure is returned, but no error message is reported.
2303 : */
2304 :
2305 : /**/
2306 : /**/
2307 :
2308 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2309 : {
2310 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2311 0 : ReportError(CE_Failure, CPLE_NotSupported,
2312 : "SetCategoryNames() not supported for this dataset.");
2313 :
2314 0 : return CE_Failure;
2315 : }
2316 :
2317 : /************************************************************************/
2318 : /* GDALSetCategoryNames() */
2319 : /************************************************************************/
2320 :
2321 : /**
2322 : * \brief Set the category names for this band.
2323 : *
2324 : * @see GDALRasterBand::SetCategoryNames()
2325 : */
2326 :
2327 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2328 : CSLConstList papszNames)
2329 :
2330 : {
2331 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2332 :
2333 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2334 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2335 : }
2336 :
2337 : /************************************************************************/
2338 : /* GetNoDataValue() */
2339 : /************************************************************************/
2340 :
2341 : /**
2342 : * \brief Fetch the no data value for this band.
2343 : *
2344 : * If there is no out of data value, an out of range value will generally
2345 : * be returned. The no data value for a band is generally a special marker
2346 : * value used to mark pixels that are not valid data. Such pixels should
2347 : * generally not be displayed, nor contribute to analysis operations.
2348 : *
2349 : * The no data value returned is 'raw', meaning that it has no offset and
2350 : * scale applied.
2351 : *
2352 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2353 : * lossy if the nodata value cannot exactly been represented by a double.
2354 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2355 : *
2356 : * This method is the same as the C function GDALGetRasterNoDataValue().
2357 : *
2358 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2359 : * is actually associated with this layer. May be NULL (default).
2360 : *
2361 : * @return the nodata value for this band.
2362 : */
2363 :
2364 32762 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2365 :
2366 : {
2367 32762 : if (pbSuccess != nullptr)
2368 32762 : *pbSuccess = FALSE;
2369 :
2370 32762 : return -1e10;
2371 : }
2372 :
2373 : /************************************************************************/
2374 : /* GDALGetRasterNoDataValue() */
2375 : /************************************************************************/
2376 :
2377 : /**
2378 : * \brief Fetch the no data value for this band.
2379 : *
2380 : * @see GDALRasterBand::GetNoDataValue()
2381 : */
2382 :
2383 415255 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2384 : int *pbSuccess)
2385 :
2386 : {
2387 415255 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2388 :
2389 415255 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2390 415255 : return poBand->GetNoDataValue(pbSuccess);
2391 : }
2392 :
2393 : /************************************************************************/
2394 : /* GetNoDataValueAsInt64() */
2395 : /************************************************************************/
2396 :
2397 : /**
2398 : * \brief Fetch the no data value for this band.
2399 : *
2400 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2401 : *
2402 : * If there is no out of data value, an out of range value will generally
2403 : * be returned. The no data value for a band is generally a special marker
2404 : * value used to mark pixels that are not valid data. Such pixels should
2405 : * generally not be displayed, nor contribute to analysis operations.
2406 : *
2407 : * The no data value returned is 'raw', meaning that it has no offset and
2408 : * scale applied.
2409 : *
2410 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2411 : *
2412 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2413 : * is actually associated with this layer. May be NULL (default).
2414 : *
2415 : * @return the nodata value for this band.
2416 : *
2417 : * @since GDAL 3.5
2418 : */
2419 :
2420 27 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2421 :
2422 : {
2423 27 : if (pbSuccess != nullptr)
2424 27 : *pbSuccess = FALSE;
2425 :
2426 27 : return std::numeric_limits<int64_t>::min();
2427 : }
2428 :
2429 : /************************************************************************/
2430 : /* GDALGetRasterNoDataValueAsInt64() */
2431 : /************************************************************************/
2432 :
2433 : /**
2434 : * \brief Fetch the no data value for this band.
2435 : *
2436 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2437 : *
2438 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2439 : *
2440 : * @since GDAL 3.5
2441 : */
2442 :
2443 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2444 : int *pbSuccess)
2445 :
2446 : {
2447 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2448 : std::numeric_limits<int64_t>::min());
2449 :
2450 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2451 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2452 : }
2453 :
2454 : /************************************************************************/
2455 : /* GetNoDataValueAsUInt64() */
2456 : /************************************************************************/
2457 :
2458 : /**
2459 : * \brief Fetch the no data value for this band.
2460 : *
2461 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2462 : *
2463 : * If there is no out of data value, an out of range value will generally
2464 : * be returned. The no data value for a band is generally a special marker
2465 : * value used to mark pixels that are not valid data. Such pixels should
2466 : * generally not be displayed, nor contribute to analysis operations.
2467 : *
2468 : * The no data value returned is 'raw', meaning that it has no offset and
2469 : * scale applied.
2470 : *
2471 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2472 : *
2473 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2474 : * is actually associated with this layer. May be NULL (default).
2475 : *
2476 : * @return the nodata value for this band.
2477 : *
2478 : * @since GDAL 3.5
2479 : */
2480 :
2481 26 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2482 :
2483 : {
2484 26 : if (pbSuccess != nullptr)
2485 26 : *pbSuccess = FALSE;
2486 :
2487 26 : return std::numeric_limits<uint64_t>::max();
2488 : }
2489 :
2490 : /************************************************************************/
2491 : /* GDALGetRasterNoDataValueAsUInt64() */
2492 : /************************************************************************/
2493 :
2494 : /**
2495 : * \brief Fetch the no data value for this band.
2496 : *
2497 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2498 : *
2499 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2500 : *
2501 : * @since GDAL 3.5
2502 : */
2503 :
2504 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2505 : int *pbSuccess)
2506 :
2507 : {
2508 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2509 : std::numeric_limits<uint64_t>::max());
2510 :
2511 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2512 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2513 : }
2514 :
2515 : /************************************************************************/
2516 : /* SetNoDataValueAsString() */
2517 : /************************************************************************/
2518 :
2519 : /**
2520 : * \brief Set the no data value for this band.
2521 : *
2522 : * Depending on drivers, changing the no data value may or may not have an
2523 : * effect on the pixel values of a raster that has just been created. It is
2524 : * thus advised to explicitly called Fill() if the intent is to initialize
2525 : * the raster to the nodata value.
2526 : * In any case, changing an existing no data value, when one already exists and
2527 : * the dataset exists or has been initialized, has no effect on the pixel whose
2528 : * value matched the previous nodata value.
2529 : *
2530 : * To clear the nodata value, use DeleteNoDataValue().
2531 : *
2532 : * @param pszNoData the value to set.
2533 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2534 : * If the value cannot be exactly represented on the output data
2535 : * type, *pbCannotBeExactlyRepresented will be set to true.
2536 : *
2537 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2538 : * by the driver, CE_Failure is returned but no error message will have
2539 : * been emitted.
2540 : *
2541 : * @since 3.11
2542 : */
2543 :
2544 : CPLErr
2545 186 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2546 : bool *pbCannotBeExactlyRepresented)
2547 : {
2548 186 : if (pbCannotBeExactlyRepresented)
2549 186 : *pbCannotBeExactlyRepresented = false;
2550 186 : if (eDataType == GDT_Int64)
2551 : {
2552 8 : if (strchr(pszNoData, '.') ||
2553 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2554 : {
2555 2 : char *endptr = nullptr;
2556 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2557 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2558 2 : GDALIsValueExactAs<int64_t>(dfVal))
2559 : {
2560 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2561 : }
2562 : }
2563 : else
2564 : {
2565 : try
2566 : {
2567 7 : const auto val = std::stoll(pszNoData);
2568 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2569 : }
2570 2 : catch (const std::exception &)
2571 : {
2572 : }
2573 : }
2574 : }
2575 181 : else if (eDataType == GDT_UInt64)
2576 : {
2577 2 : if (strchr(pszNoData, '.') ||
2578 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2579 : {
2580 0 : char *endptr = nullptr;
2581 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2582 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2583 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2584 : {
2585 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2586 : }
2587 : }
2588 : else
2589 : {
2590 : try
2591 : {
2592 1 : const auto val = std::stoull(pszNoData);
2593 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2594 : }
2595 0 : catch (const std::exception &)
2596 : {
2597 : }
2598 : }
2599 : }
2600 180 : else if (eDataType == GDT_Float32)
2601 : {
2602 10 : char *endptr = nullptr;
2603 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2604 10 : if (endptr == pszNoData + strlen(pszNoData))
2605 : {
2606 10 : return SetNoDataValue(double(fVal));
2607 : }
2608 : }
2609 : else
2610 : {
2611 170 : char *endptr = nullptr;
2612 170 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2613 340 : if (endptr == pszNoData + strlen(pszNoData) &&
2614 170 : GDALIsValueExactAs(dfVal, eDataType))
2615 : {
2616 169 : return SetNoDataValue(dfVal);
2617 : }
2618 : }
2619 5 : if (pbCannotBeExactlyRepresented)
2620 5 : *pbCannotBeExactlyRepresented = true;
2621 5 : return CE_Failure;
2622 : }
2623 :
2624 : /************************************************************************/
2625 : /* SetNoDataValue() */
2626 : /************************************************************************/
2627 :
2628 : /**
2629 : * \fn GDALRasterBand::SetNoDataValue(double)
2630 : * \brief Set the no data value for this band.
2631 : *
2632 : * Depending on drivers, changing the no data value may or may not have an
2633 : * effect on the pixel values of a raster that has just been created. It is
2634 : * thus advised to explicitly called Fill() if the intent is to initialize
2635 : * the raster to the nodata value.
2636 : * In any case, changing an existing no data value, when one already exists and
2637 : * the dataset exists or has been initialized, has no effect on the pixel whose
2638 : * value matched the previous nodata value.
2639 : *
2640 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2641 : * be represented by a double, use SetNoDataValueAsInt64() or
2642 : * SetNoDataValueAsUInt64() instead.
2643 : *
2644 : * To clear the nodata value, use DeleteNoDataValue().
2645 : *
2646 : * This method is the same as the C function GDALSetRasterNoDataValue().
2647 : *
2648 : * @param dfNoData the value to set.
2649 : *
2650 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2651 : * by the driver, CE_Failure is returned but no error message will have
2652 : * been emitted.
2653 : */
2654 :
2655 : /**/
2656 : /**/
2657 :
2658 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2659 :
2660 : {
2661 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2662 0 : ReportError(CE_Failure, CPLE_NotSupported,
2663 : "SetNoDataValue() not supported for this dataset.");
2664 :
2665 0 : return CE_Failure;
2666 : }
2667 :
2668 : /************************************************************************/
2669 : /* GDALSetRasterNoDataValue() */
2670 : /************************************************************************/
2671 :
2672 : /**
2673 : * \brief Set the no data value for this band.
2674 : *
2675 : * Depending on drivers, changing the no data value may or may not have an
2676 : * effect on the pixel values of a raster that has just been created. It is
2677 : * thus advised to explicitly called Fill() if the intent is to initialize
2678 : * the raster to the nodata value.
2679 : * In any case, changing an existing no data value, when one already exists and
2680 : * the dataset exists or has been initialized, has no effect on the pixel whose
2681 : * value matched the previous nodata value.
2682 : *
2683 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2684 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2685 : * GDALSetRasterNoDataValueAsUInt64() instead.
2686 : *
2687 : * @see GDALRasterBand::SetNoDataValue()
2688 : */
2689 :
2690 1328 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2691 : double dfValue)
2692 :
2693 : {
2694 1328 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2695 :
2696 1328 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2697 1328 : return poBand->SetNoDataValue(dfValue);
2698 : }
2699 :
2700 : /************************************************************************/
2701 : /* SetNoDataValueAsInt64() */
2702 : /************************************************************************/
2703 :
2704 : /**
2705 : * \brief Set the no data value for this band.
2706 : *
2707 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2708 : *
2709 : * Depending on drivers, changing the no data value may or may not have an
2710 : * effect on the pixel values of a raster that has just been created. It is
2711 : * thus advised to explicitly called Fill() if the intent is to initialize
2712 : * the raster to the nodata value.
2713 : * In ay case, changing an existing no data value, when one already exists and
2714 : * the dataset exists or has been initialized, has no effect on the pixel whose
2715 : * value matched the previous nodata value.
2716 : *
2717 : * To clear the nodata value, use DeleteNoDataValue().
2718 : *
2719 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2720 : *
2721 : * @param nNoDataValue the value to set.
2722 : *
2723 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2724 : * by the driver, CE_Failure is returned but no error message will have
2725 : * been emitted.
2726 : *
2727 : * @since GDAL 3.5
2728 : */
2729 :
2730 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2731 :
2732 : {
2733 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2734 0 : ReportError(CE_Failure, CPLE_NotSupported,
2735 : "SetNoDataValueAsInt64() not supported for this dataset.");
2736 :
2737 0 : return CE_Failure;
2738 : }
2739 :
2740 : /************************************************************************/
2741 : /* GDALSetRasterNoDataValueAsInt64() */
2742 : /************************************************************************/
2743 :
2744 : /**
2745 : * \brief Set the no data value for this band.
2746 : *
2747 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2748 : *
2749 : * Depending on drivers, changing the no data value may or may not have an
2750 : * effect on the pixel values of a raster that has just been created. It is
2751 : * thus advised to explicitly called Fill() if the intent is to initialize
2752 : * the raster to the nodata value.
2753 : * In ay case, changing an existing no data value, when one already exists and
2754 : * the dataset exists or has been initialized, has no effect on the pixel whose
2755 : * value matched the previous nodata value.
2756 : *
2757 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2758 : *
2759 : * @since GDAL 3.5
2760 : */
2761 :
2762 24 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2763 : int64_t nValue)
2764 :
2765 : {
2766 24 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2767 :
2768 24 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2769 24 : return poBand->SetNoDataValueAsInt64(nValue);
2770 : }
2771 :
2772 : /************************************************************************/
2773 : /* SetNoDataValueAsUInt64() */
2774 : /************************************************************************/
2775 :
2776 : /**
2777 : * \brief Set the no data value for this band.
2778 : *
2779 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2780 : *
2781 : * Depending on drivers, changing the no data value may or may not have an
2782 : * effect on the pixel values of a raster that has just been created. It is
2783 : * thus advised to explicitly called Fill() if the intent is to initialize
2784 : * the raster to the nodata value.
2785 : * In ay case, changing an existing no data value, when one already exists and
2786 : * the dataset exists or has been initialized, has no effect on the pixel whose
2787 : * value matched the previous nodata value.
2788 : *
2789 : * To clear the nodata value, use DeleteNoDataValue().
2790 : *
2791 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2792 : *
2793 : * @param nNoDataValue the value to set.
2794 : *
2795 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2796 : * by the driver, CE_Failure is returned but no error message will have
2797 : * been emitted.
2798 : *
2799 : * @since GDAL 3.5
2800 : */
2801 :
2802 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2803 :
2804 : {
2805 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2806 0 : ReportError(CE_Failure, CPLE_NotSupported,
2807 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2808 :
2809 0 : return CE_Failure;
2810 : }
2811 :
2812 : /************************************************************************/
2813 : /* GDALSetRasterNoDataValueAsUInt64() */
2814 : /************************************************************************/
2815 :
2816 : /**
2817 : * \brief Set the no data value for this band.
2818 : *
2819 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2820 : *
2821 : * Depending on drivers, changing the no data value may or may not have an
2822 : * effect on the pixel values of a raster that has just been created. It is
2823 : * thus advised to explicitly called Fill() if the intent is to initialize
2824 : * the raster to the nodata value.
2825 : * In ay case, changing an existing no data value, when one already exists and
2826 : * the dataset exists or has been initialized, has no effect on the pixel whose
2827 : * value matched the previous nodata value.
2828 : *
2829 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2830 : *
2831 : * @since GDAL 3.5
2832 : */
2833 :
2834 23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2835 : uint64_t nValue)
2836 :
2837 : {
2838 23 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2839 :
2840 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2841 23 : return poBand->SetNoDataValueAsUInt64(nValue);
2842 : }
2843 :
2844 : /************************************************************************/
2845 : /* DeleteNoDataValue() */
2846 : /************************************************************************/
2847 :
2848 : /**
2849 : * \brief Remove the no data value for this band.
2850 : *
2851 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2852 : *
2853 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2854 : * by the driver, CE_Failure is returned but no error message will have
2855 : * been emitted.
2856 : *
2857 : */
2858 :
2859 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2860 :
2861 : {
2862 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2863 0 : ReportError(CE_Failure, CPLE_NotSupported,
2864 : "DeleteNoDataValue() not supported for this dataset.");
2865 :
2866 0 : return CE_Failure;
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* GDALDeleteRasterNoDataValue() */
2871 : /************************************************************************/
2872 :
2873 : /**
2874 : * \brief Remove the no data value for this band.
2875 : *
2876 : * @see GDALRasterBand::DeleteNoDataValue()
2877 : *
2878 : */
2879 :
2880 56 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2881 :
2882 : {
2883 56 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2884 :
2885 56 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2886 56 : return poBand->DeleteNoDataValue();
2887 : }
2888 :
2889 : /************************************************************************/
2890 : /* GetMaximum() */
2891 : /************************************************************************/
2892 :
2893 : /**
2894 : * \brief Fetch the maximum value for this band.
2895 : *
2896 : * For file formats that don't know this intrinsically, the maximum supported
2897 : * value for the data type will generally be returned.
2898 : *
2899 : * This method is the same as the C function GDALGetRasterMaximum().
2900 : *
2901 : * @param pbSuccess pointer to a boolean to use to indicate if the
2902 : * returned value is a tight maximum or not. May be NULL (default).
2903 : *
2904 : * @return the maximum raster value (excluding no data pixels)
2905 : */
2906 :
2907 549 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2908 :
2909 : {
2910 549 : const char *pszValue = nullptr;
2911 :
2912 549 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2913 : {
2914 47 : if (pbSuccess != nullptr)
2915 42 : *pbSuccess = TRUE;
2916 :
2917 47 : return CPLAtofM(pszValue);
2918 : }
2919 :
2920 502 : if (pbSuccess != nullptr)
2921 498 : *pbSuccess = FALSE;
2922 :
2923 502 : switch (eDataType)
2924 : {
2925 345 : case GDT_UInt8:
2926 : {
2927 345 : EnablePixelTypeSignedByteWarning(false);
2928 : const char *pszPixelType =
2929 345 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
2930 345 : EnablePixelTypeSignedByteWarning(true);
2931 345 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2932 0 : return 127;
2933 :
2934 345 : return 255;
2935 : }
2936 :
2937 1 : case GDT_Int8:
2938 1 : return 127;
2939 :
2940 21 : case GDT_UInt16:
2941 21 : return 65535;
2942 :
2943 24 : case GDT_Int16:
2944 : case GDT_CInt16:
2945 24 : return 32767;
2946 :
2947 39 : case GDT_Int32:
2948 : case GDT_CInt32:
2949 39 : return 2147483647.0;
2950 :
2951 15 : case GDT_UInt32:
2952 15 : return 4294967295.0;
2953 :
2954 1 : case GDT_Int64:
2955 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2956 :
2957 1 : case GDT_UInt64:
2958 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2959 :
2960 0 : case GDT_Float16:
2961 : case GDT_CFloat16:
2962 0 : return 65504.0;
2963 :
2964 33 : case GDT_Float32:
2965 : case GDT_CFloat32:
2966 33 : return 4294967295.0; // Not actually accurate.
2967 :
2968 22 : case GDT_Float64:
2969 : case GDT_CFloat64:
2970 22 : return 4294967295.0; // Not actually accurate.
2971 :
2972 0 : case GDT_Unknown:
2973 : case GDT_TypeCount:
2974 0 : break;
2975 : }
2976 0 : return 4294967295.0; // Not actually accurate.
2977 : }
2978 :
2979 : /************************************************************************/
2980 : /* GDALGetRasterMaximum() */
2981 : /************************************************************************/
2982 :
2983 : /**
2984 : * \brief Fetch the maximum value for this band.
2985 : *
2986 : * @see GDALRasterBand::GetMaximum()
2987 : */
2988 :
2989 350 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2990 :
2991 : {
2992 350 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2993 :
2994 350 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2995 350 : return poBand->GetMaximum(pbSuccess);
2996 : }
2997 :
2998 : /************************************************************************/
2999 : /* GetMinimum() */
3000 : /************************************************************************/
3001 :
3002 : /**
3003 : * \brief Fetch the minimum value for this band.
3004 : *
3005 : * For file formats that don't know this intrinsically, the minimum supported
3006 : * value for the data type will generally be returned.
3007 : *
3008 : * This method is the same as the C function GDALGetRasterMinimum().
3009 : *
3010 : * @param pbSuccess pointer to a boolean to use to indicate if the
3011 : * returned value is a tight minimum or not. May be NULL (default).
3012 : *
3013 : * @return the minimum raster value (excluding no data pixels)
3014 : */
3015 :
3016 557 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3017 :
3018 : {
3019 557 : const char *pszValue = nullptr;
3020 :
3021 557 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3022 : {
3023 52 : if (pbSuccess != nullptr)
3024 47 : *pbSuccess = TRUE;
3025 :
3026 52 : return CPLAtofM(pszValue);
3027 : }
3028 :
3029 505 : if (pbSuccess != nullptr)
3030 501 : *pbSuccess = FALSE;
3031 :
3032 505 : switch (eDataType)
3033 : {
3034 348 : case GDT_UInt8:
3035 : {
3036 348 : EnablePixelTypeSignedByteWarning(false);
3037 : const char *pszPixelType =
3038 348 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
3039 348 : EnablePixelTypeSignedByteWarning(true);
3040 348 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3041 0 : return -128;
3042 :
3043 348 : return 0;
3044 : }
3045 :
3046 1 : case GDT_Int8:
3047 1 : return -128;
3048 :
3049 21 : case GDT_UInt16:
3050 21 : return 0;
3051 :
3052 24 : case GDT_Int16:
3053 : case GDT_CInt16:
3054 24 : return -32768;
3055 :
3056 39 : case GDT_Int32:
3057 : case GDT_CInt32:
3058 39 : return -2147483648.0;
3059 :
3060 15 : case GDT_UInt32:
3061 15 : return 0;
3062 :
3063 1 : case GDT_Int64:
3064 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3065 :
3066 1 : case GDT_UInt64:
3067 1 : return 0;
3068 :
3069 0 : case GDT_Float16:
3070 : case GDT_CFloat16:
3071 0 : return -65504.0;
3072 :
3073 33 : case GDT_Float32:
3074 : case GDT_CFloat32:
3075 33 : return -4294967295.0; // Not actually accurate.
3076 :
3077 22 : case GDT_Float64:
3078 : case GDT_CFloat64:
3079 22 : return -4294967295.0; // Not actually accurate.
3080 :
3081 0 : case GDT_Unknown:
3082 : case GDT_TypeCount:
3083 0 : break;
3084 : }
3085 0 : return -4294967295.0; // Not actually accurate.
3086 : }
3087 :
3088 : /************************************************************************/
3089 : /* GDALGetRasterMinimum() */
3090 : /************************************************************************/
3091 :
3092 : /**
3093 : * \brief Fetch the minimum value for this band.
3094 : *
3095 : * @see GDALRasterBand::GetMinimum()
3096 : */
3097 :
3098 360 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3099 :
3100 : {
3101 360 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3102 :
3103 360 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3104 360 : return poBand->GetMinimum(pbSuccess);
3105 : }
3106 :
3107 : /************************************************************************/
3108 : /* GetColorInterpretation() */
3109 : /************************************************************************/
3110 :
3111 : /**
3112 : * \brief How should this band be interpreted as color?
3113 : *
3114 : * GCI_Undefined is returned when the format doesn't know anything
3115 : * about the color interpretation.
3116 : *
3117 : * This method is the same as the C function
3118 : * GDALGetRasterColorInterpretation().
3119 : *
3120 : * @return color interpretation value for band.
3121 : */
3122 :
3123 168 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3124 :
3125 : {
3126 168 : return GCI_Undefined;
3127 : }
3128 :
3129 : /************************************************************************/
3130 : /* GDALGetRasterColorInterpretation() */
3131 : /************************************************************************/
3132 :
3133 : /**
3134 : * \brief How should this band be interpreted as color?
3135 : *
3136 : * @see GDALRasterBand::GetColorInterpretation()
3137 : */
3138 :
3139 : GDALColorInterp CPL_STDCALL
3140 6563 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3141 :
3142 : {
3143 6563 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3144 :
3145 6563 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3146 6563 : return poBand->GetColorInterpretation();
3147 : }
3148 :
3149 : /************************************************************************/
3150 : /* SetColorInterpretation() */
3151 : /************************************************************************/
3152 :
3153 : /**
3154 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3155 : * \brief Set color interpretation of a band.
3156 : *
3157 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3158 : *
3159 : * @param eColorInterp the new color interpretation to apply to this band.
3160 : *
3161 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3162 : */
3163 :
3164 : /**/
3165 : /**/
3166 :
3167 1 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3168 :
3169 : {
3170 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3171 1 : ReportError(CE_Failure, CPLE_NotSupported,
3172 : "SetColorInterpretation() not supported for this dataset.");
3173 1 : return CE_Failure;
3174 : }
3175 :
3176 : /************************************************************************/
3177 : /* GDALSetRasterColorInterpretation() */
3178 : /************************************************************************/
3179 :
3180 : /**
3181 : * \brief Set color interpretation of a band.
3182 : *
3183 : * @see GDALRasterBand::SetColorInterpretation()
3184 : */
3185 :
3186 1924 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3187 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3188 :
3189 : {
3190 1924 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3191 :
3192 1924 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3193 1924 : return poBand->SetColorInterpretation(eColorInterp);
3194 : }
3195 :
3196 : /************************************************************************/
3197 : /* GetColorTable() */
3198 : /************************************************************************/
3199 :
3200 : /**
3201 : * \brief Fetch the color table associated with band.
3202 : *
3203 : * If there is no associated color table, the return result is NULL. The
3204 : * returned color table remains owned by the GDALRasterBand, and can't
3205 : * be depended on for long, nor should it ever be modified by the caller.
3206 : *
3207 : * This method is the same as the C function GDALGetRasterColorTable().
3208 : *
3209 : * @return internal color table, or NULL.
3210 : */
3211 :
3212 219 : GDALColorTable *GDALRasterBand::GetColorTable()
3213 :
3214 : {
3215 219 : return nullptr;
3216 : }
3217 :
3218 : /************************************************************************/
3219 : /* GDALGetRasterColorTable() */
3220 : /************************************************************************/
3221 :
3222 : /**
3223 : * \brief Fetch the color table associated with band.
3224 : *
3225 : * @see GDALRasterBand::GetColorTable()
3226 : */
3227 :
3228 2243 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3229 :
3230 : {
3231 2243 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3232 :
3233 2243 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3234 2243 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3235 : }
3236 :
3237 : /************************************************************************/
3238 : /* SetColorTable() */
3239 : /************************************************************************/
3240 :
3241 : /**
3242 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3243 : * \brief Set the raster color table.
3244 : *
3245 : * The driver will make a copy of all desired data in the colortable. It
3246 : * remains owned by the caller after the call.
3247 : *
3248 : * This method is the same as the C function GDALSetRasterColorTable().
3249 : *
3250 : * @param poCT the color table to apply. This may be NULL to clear the color
3251 : * table (where supported).
3252 : *
3253 : * @return CE_None on success, or CE_Failure on failure. If the action is
3254 : * unsupported by the driver, a value of CE_Failure is returned, but no
3255 : * error is issued.
3256 : */
3257 :
3258 : /**/
3259 : /**/
3260 :
3261 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3262 :
3263 : {
3264 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3265 0 : ReportError(CE_Failure, CPLE_NotSupported,
3266 : "SetColorTable() not supported for this dataset.");
3267 0 : return CE_Failure;
3268 : }
3269 :
3270 : /************************************************************************/
3271 : /* GDALSetRasterColorTable() */
3272 : /************************************************************************/
3273 :
3274 : /**
3275 : * \brief Set the raster color table.
3276 : *
3277 : * @see GDALRasterBand::SetColorTable()
3278 : */
3279 :
3280 107 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3281 : GDALColorTableH hCT)
3282 :
3283 : {
3284 107 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3285 :
3286 107 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3287 107 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3288 : }
3289 :
3290 : /************************************************************************/
3291 : /* HasArbitraryOverviews() */
3292 : /************************************************************************/
3293 :
3294 : /**
3295 : * \brief Check for arbitrary overviews.
3296 : *
3297 : * This returns TRUE if the underlying datastore can compute arbitrary
3298 : * overviews efficiently, such as is the case with OGDI over a network.
3299 : * Datastores with arbitrary overviews don't generally have any fixed
3300 : * overviews, but the RasterIO() method can be used in downsampling mode
3301 : * to get overview data efficiently.
3302 : *
3303 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3304 : *
3305 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3306 : * FALSE.
3307 : */
3308 :
3309 281 : int GDALRasterBand::HasArbitraryOverviews()
3310 :
3311 : {
3312 281 : return FALSE;
3313 : }
3314 :
3315 : /************************************************************************/
3316 : /* GDALHasArbitraryOverviews() */
3317 : /************************************************************************/
3318 :
3319 : /**
3320 : * \brief Check for arbitrary overviews.
3321 : *
3322 : * @see GDALRasterBand::HasArbitraryOverviews()
3323 : */
3324 :
3325 201 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3326 :
3327 : {
3328 201 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3329 :
3330 201 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3331 201 : return poBand->HasArbitraryOverviews();
3332 : }
3333 :
3334 : /************************************************************************/
3335 : /* GetOverviewCount() */
3336 : /************************************************************************/
3337 :
3338 : /**
3339 : * \brief Return the number of overview layers available.
3340 : *
3341 : * This method is the same as the C function GDALGetOverviewCount().
3342 : *
3343 : * @return overview count, zero if none.
3344 : */
3345 :
3346 1087220 : int GDALRasterBand::GetOverviewCount()
3347 :
3348 : {
3349 1744690 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3350 657469 : poDS->AreOverviewsEnabled())
3351 657469 : return poDS->oOvManager.GetOverviewCount(nBand);
3352 :
3353 429755 : return 0;
3354 : }
3355 :
3356 : /************************************************************************/
3357 : /* GDALGetOverviewCount() */
3358 : /************************************************************************/
3359 :
3360 : /**
3361 : * \brief Return the number of overview layers available.
3362 : *
3363 : * @see GDALRasterBand::GetOverviewCount()
3364 : */
3365 :
3366 3359 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3367 :
3368 : {
3369 3359 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3370 :
3371 3359 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3372 3359 : return poBand->GetOverviewCount();
3373 : }
3374 :
3375 : /************************************************************************/
3376 : /* GetOverview() */
3377 : /************************************************************************/
3378 :
3379 : /**
3380 : * \brief Fetch overview raster band object.
3381 : *
3382 : * This method is the same as the C function GDALGetOverview().
3383 : *
3384 : * @param i overview index between 0 and GetOverviewCount()-1.
3385 : *
3386 : * @return overview GDALRasterBand.
3387 : */
3388 :
3389 1021 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3390 :
3391 : {
3392 1880 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3393 859 : poDS->AreOverviewsEnabled())
3394 859 : return poDS->oOvManager.GetOverview(nBand, i);
3395 :
3396 162 : return nullptr;
3397 : }
3398 :
3399 : /************************************************************************/
3400 : /* GDALGetOverview() */
3401 : /************************************************************************/
3402 :
3403 : /**
3404 : * \brief Fetch overview raster band object.
3405 : *
3406 : * @see GDALRasterBand::GetOverview()
3407 : */
3408 :
3409 5717 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3410 :
3411 : {
3412 5717 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3413 :
3414 5717 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3415 5717 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3416 : }
3417 :
3418 : /************************************************************************/
3419 : /* GetRasterSampleOverview() */
3420 : /************************************************************************/
3421 :
3422 : /**
3423 : * \brief Fetch best sampling overview.
3424 : *
3425 : * Returns the most reduced overview of the given band that still satisfies
3426 : * the desired number of samples. This function can be used with zero
3427 : * as the number of desired samples to fetch the most reduced overview.
3428 : * The same band as was passed in will be returned if it has not overviews,
3429 : * or if none of the overviews have enough samples.
3430 : *
3431 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3432 : * and GDALGetRasterSampleOverviewEx().
3433 : *
3434 : * @param nDesiredSamples the returned band will have at least this many
3435 : * pixels.
3436 : *
3437 : * @return optimal overview or the band itself.
3438 : */
3439 :
3440 : GDALRasterBand *
3441 2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3442 :
3443 : {
3444 2009 : GDALRasterBand *poBestBand = this;
3445 :
3446 2009 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3447 :
3448 4029 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3449 : {
3450 2020 : GDALRasterBand *poOBand = GetOverview(iOverview);
3451 :
3452 2020 : if (poOBand == nullptr)
3453 0 : continue;
3454 :
3455 : const double dfOSamples =
3456 2020 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3457 :
3458 2020 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3459 : {
3460 2017 : dfBestSamples = dfOSamples;
3461 2017 : poBestBand = poOBand;
3462 : }
3463 : }
3464 :
3465 2009 : return poBestBand;
3466 : }
3467 :
3468 : /************************************************************************/
3469 : /* GDALGetRasterSampleOverview() */
3470 : /************************************************************************/
3471 :
3472 : /**
3473 : * \brief Fetch best sampling overview.
3474 : *
3475 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3476 : * billion samples.
3477 : *
3478 : * @see GDALRasterBand::GetRasterSampleOverview()
3479 : * @see GDALGetRasterSampleOverviewEx()
3480 : */
3481 :
3482 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3483 : int nDesiredSamples)
3484 :
3485 : {
3486 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3487 :
3488 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3489 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3490 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3491 : }
3492 :
3493 : /************************************************************************/
3494 : /* GDALGetRasterSampleOverviewEx() */
3495 : /************************************************************************/
3496 :
3497 : /**
3498 : * \brief Fetch best sampling overview.
3499 : *
3500 : * @see GDALRasterBand::GetRasterSampleOverview()
3501 : */
3502 :
3503 : GDALRasterBandH CPL_STDCALL
3504 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3505 :
3506 : {
3507 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3508 :
3509 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3510 2000 : return GDALRasterBand::ToHandle(
3511 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3512 : }
3513 :
3514 : /************************************************************************/
3515 : /* BuildOverviews() */
3516 : /************************************************************************/
3517 :
3518 : /**
3519 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3520 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3521 : *
3522 : * If the operation is unsupported for the indicated dataset, then
3523 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3524 : * CPLE_NotSupported.
3525 : *
3526 : * WARNING: Most formats don't support per-band overview computation, but
3527 : * require that overviews are computed for all bands of a dataset, using
3528 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3529 : * is the HFA driver which supports this method.
3530 : *
3531 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3532 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3533 : * applied.
3534 : * @param nOverviews number of overviews to build.
3535 : * @param panOverviewList the list of overview decimation factors to build.
3536 : * @param pfnProgress a function to call to report progress, or NULL.
3537 : * @param pProgressData application data to pass to the progress function.
3538 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3539 : * key=value pairs, or NULL
3540 : *
3541 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3542 : */
3543 :
3544 : /**/
3545 : /**/
3546 :
3547 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3548 : int /*nOverviews*/,
3549 : const int * /*panOverviewList*/,
3550 : GDALProgressFunc /*pfnProgress*/,
3551 : void * /*pProgressData*/,
3552 : CSLConstList /* papszOptions */)
3553 :
3554 : {
3555 0 : ReportError(CE_Failure, CPLE_NotSupported,
3556 : "BuildOverviews() not supported for this dataset.");
3557 :
3558 0 : return (CE_Failure);
3559 : }
3560 :
3561 : /************************************************************************/
3562 : /* GetOffset() */
3563 : /************************************************************************/
3564 :
3565 : /**
3566 : * \brief Fetch the raster value offset.
3567 : *
3568 : * This value (in combination with the GetScale() value) can be used to
3569 : * transform raw pixel values into the units returned by GetUnitType().
3570 : * For example this might be used to store elevations in GUInt16 bands
3571 : * with a precision of 0.1, and starting from -100.
3572 : *
3573 : * Units value = (raw value * scale) + offset
3574 : *
3575 : * Note that applying scale and offset is of the responsibility of the user,
3576 : * and is not done by methods such as RasterIO() or ReadBlock().
3577 : *
3578 : * For file formats that don't know this intrinsically a value of zero
3579 : * is returned.
3580 : *
3581 : * This method is the same as the C function GDALGetRasterOffset().
3582 : *
3583 : * @param pbSuccess pointer to a boolean to use to indicate if the
3584 : * returned value is meaningful or not. May be NULL (default).
3585 : *
3586 : * @return the raster offset.
3587 : */
3588 :
3589 553 : double GDALRasterBand::GetOffset(int *pbSuccess)
3590 :
3591 : {
3592 553 : if (pbSuccess != nullptr)
3593 336 : *pbSuccess = FALSE;
3594 :
3595 553 : return 0.0;
3596 : }
3597 :
3598 : /************************************************************************/
3599 : /* GDALGetRasterOffset() */
3600 : /************************************************************************/
3601 :
3602 : /**
3603 : * \brief Fetch the raster value offset.
3604 : *
3605 : * @see GDALRasterBand::GetOffset()
3606 : */
3607 :
3608 432 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3609 :
3610 : {
3611 432 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3612 :
3613 432 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3614 432 : return poBand->GetOffset(pbSuccess);
3615 : }
3616 :
3617 : /************************************************************************/
3618 : /* SetOffset() */
3619 : /************************************************************************/
3620 :
3621 : /**
3622 : * \fn GDALRasterBand::SetOffset(double)
3623 : * \brief Set scaling offset.
3624 : *
3625 : * Very few formats implement this method. When not implemented it will
3626 : * issue a CPLE_NotSupported error and return CE_Failure.
3627 : *
3628 : * This method is the same as the C function GDALSetRasterOffset().
3629 : *
3630 : * @param dfNewOffset the new offset.
3631 : *
3632 : * @return CE_None or success or CE_Failure on failure.
3633 : */
3634 :
3635 : /**/
3636 : /**/
3637 :
3638 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3639 : {
3640 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3641 0 : ReportError(CE_Failure, CPLE_NotSupported,
3642 : "SetOffset() not supported on this raster band.");
3643 :
3644 0 : return CE_Failure;
3645 : }
3646 :
3647 : /************************************************************************/
3648 : /* GDALSetRasterOffset() */
3649 : /************************************************************************/
3650 :
3651 : /**
3652 : * \brief Set scaling offset.
3653 : *
3654 : * @see GDALRasterBand::SetOffset()
3655 : */
3656 :
3657 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3658 : double dfNewOffset)
3659 :
3660 : {
3661 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3662 :
3663 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3664 86 : return poBand->SetOffset(dfNewOffset);
3665 : }
3666 :
3667 : /************************************************************************/
3668 : /* GetScale() */
3669 : /************************************************************************/
3670 :
3671 : /**
3672 : * \brief Fetch the raster value scale.
3673 : *
3674 : * This value (in combination with the GetOffset() value) can be used to
3675 : * transform raw pixel values into the units returned by GetUnitType().
3676 : * For example this might be used to store elevations in GUInt16 bands
3677 : * with a precision of 0.1, and starting from -100.
3678 : *
3679 : * Units value = (raw value * scale) + offset
3680 : *
3681 : * Note that applying scale and offset is of the responsibility of the user,
3682 : * and is not done by methods such as RasterIO() or ReadBlock().
3683 : *
3684 : * For file formats that don't know this intrinsically a value of one
3685 : * is returned.
3686 : *
3687 : * This method is the same as the C function GDALGetRasterScale().
3688 : *
3689 : * @param pbSuccess pointer to a boolean to use to indicate if the
3690 : * returned value is meaningful or not. May be NULL (default).
3691 : *
3692 : * @return the raster scale.
3693 : */
3694 :
3695 553 : double GDALRasterBand::GetScale(int *pbSuccess)
3696 :
3697 : {
3698 553 : if (pbSuccess != nullptr)
3699 336 : *pbSuccess = FALSE;
3700 :
3701 553 : return 1.0;
3702 : }
3703 :
3704 : /************************************************************************/
3705 : /* GDALGetRasterScale() */
3706 : /************************************************************************/
3707 :
3708 : /**
3709 : * \brief Fetch the raster value scale.
3710 : *
3711 : * @see GDALRasterBand::GetScale()
3712 : */
3713 :
3714 430 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3715 :
3716 : {
3717 430 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3718 :
3719 430 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3720 430 : return poBand->GetScale(pbSuccess);
3721 : }
3722 :
3723 : /************************************************************************/
3724 : /* SetScale() */
3725 : /************************************************************************/
3726 :
3727 : /**
3728 : * \fn GDALRasterBand::SetScale(double)
3729 : * \brief Set scaling ratio.
3730 : *
3731 : * Very few formats implement this method. When not implemented it will
3732 : * issue a CPLE_NotSupported error and return CE_Failure.
3733 : *
3734 : * This method is the same as the C function GDALSetRasterScale().
3735 : *
3736 : * @param dfNewScale the new scale.
3737 : *
3738 : * @return CE_None or success or CE_Failure on failure.
3739 : */
3740 :
3741 : /**/
3742 : /**/
3743 :
3744 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3745 :
3746 : {
3747 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3748 0 : ReportError(CE_Failure, CPLE_NotSupported,
3749 : "SetScale() not supported on this raster band.");
3750 :
3751 0 : return CE_Failure;
3752 : }
3753 :
3754 : /************************************************************************/
3755 : /* GDALSetRasterScale() */
3756 : /************************************************************************/
3757 :
3758 : /**
3759 : * \brief Set scaling ratio.
3760 : *
3761 : * @see GDALRasterBand::SetScale()
3762 : */
3763 :
3764 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3765 :
3766 : {
3767 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3768 :
3769 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3770 87 : return poBand->SetScale(dfNewOffset);
3771 : }
3772 :
3773 : /************************************************************************/
3774 : /* GetUnitType() */
3775 : /************************************************************************/
3776 :
3777 : /**
3778 : * \brief Return raster unit type.
3779 : *
3780 : * Return a name for the units of this raster's values. For instance, it
3781 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3782 : * units are available, a value of "" will be returned. The returned string
3783 : * should not be modified, nor freed by the calling application.
3784 : *
3785 : * This method is the same as the C function GDALGetRasterUnitType().
3786 : *
3787 : * @return unit name string.
3788 : */
3789 :
3790 185 : const char *GDALRasterBand::GetUnitType()
3791 :
3792 : {
3793 185 : return "";
3794 : }
3795 :
3796 : /************************************************************************/
3797 : /* GDALGetRasterUnitType() */
3798 : /************************************************************************/
3799 :
3800 : /**
3801 : * \brief Return raster unit type.
3802 : *
3803 : * @see GDALRasterBand::GetUnitType()
3804 : */
3805 :
3806 1760 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3807 :
3808 : {
3809 1760 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3810 :
3811 1760 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3812 1760 : return poBand->GetUnitType();
3813 : }
3814 :
3815 : /************************************************************************/
3816 : /* SetUnitType() */
3817 : /************************************************************************/
3818 :
3819 : /**
3820 : * \fn GDALRasterBand::SetUnitType(const char*)
3821 : * \brief Set unit type.
3822 : *
3823 : * Set the unit type for a raster band. Values should be one of
3824 : * "" (the default indicating it is unknown), "m" indicating meters,
3825 : * or "ft" indicating feet, though other nonstandard values are allowed.
3826 : *
3827 : * This method is the same as the C function GDALSetRasterUnitType().
3828 : *
3829 : * @param pszNewValue the new unit type value.
3830 : *
3831 : * @return CE_None on success or CE_Failure if not successful, or
3832 : * unsupported.
3833 : */
3834 :
3835 : /**/
3836 : /**/
3837 :
3838 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3839 :
3840 : {
3841 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3842 0 : ReportError(CE_Failure, CPLE_NotSupported,
3843 : "SetUnitType() not supported on this raster band.");
3844 0 : return CE_Failure;
3845 : }
3846 :
3847 : /************************************************************************/
3848 : /* GDALSetRasterUnitType() */
3849 : /************************************************************************/
3850 :
3851 : /**
3852 : * \brief Set unit type.
3853 : *
3854 : * @see GDALRasterBand::SetUnitType()
3855 : *
3856 : */
3857 :
3858 120 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3859 : const char *pszNewValue)
3860 :
3861 : {
3862 120 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3863 :
3864 120 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3865 120 : return poBand->SetUnitType(pszNewValue);
3866 : }
3867 :
3868 : /************************************************************************/
3869 : /* GetXSize() */
3870 : /************************************************************************/
3871 :
3872 : /**
3873 : * \brief Fetch XSize of raster.
3874 : *
3875 : * This method is the same as the C function GDALGetRasterBandXSize().
3876 : *
3877 : * @return the width in pixels of this band.
3878 : */
3879 :
3880 8596630 : int GDALRasterBand::GetXSize() const
3881 :
3882 : {
3883 8596630 : return nRasterXSize;
3884 : }
3885 :
3886 : /************************************************************************/
3887 : /* GDALGetRasterBandXSize() */
3888 : /************************************************************************/
3889 :
3890 : /**
3891 : * \brief Fetch XSize of raster.
3892 : *
3893 : * @see GDALRasterBand::GetXSize()
3894 : */
3895 :
3896 58553 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3897 :
3898 : {
3899 58553 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3900 :
3901 58553 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3902 58553 : return poBand->GetXSize();
3903 : }
3904 :
3905 : /************************************************************************/
3906 : /* GetYSize() */
3907 : /************************************************************************/
3908 :
3909 : /**
3910 : * \brief Fetch YSize of raster.
3911 : *
3912 : * This method is the same as the C function GDALGetRasterBandYSize().
3913 : *
3914 : * @return the height in pixels of this band.
3915 : */
3916 :
3917 4777890 : int GDALRasterBand::GetYSize() const
3918 :
3919 : {
3920 4777890 : return nRasterYSize;
3921 : }
3922 :
3923 : /************************************************************************/
3924 : /* GDALGetRasterBandYSize() */
3925 : /************************************************************************/
3926 :
3927 : /**
3928 : * \brief Fetch YSize of raster.
3929 : *
3930 : * @see GDALRasterBand::GetYSize()
3931 : */
3932 :
3933 57416 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3934 :
3935 : {
3936 57416 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3937 :
3938 57416 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3939 57416 : return poBand->GetYSize();
3940 : }
3941 :
3942 : /************************************************************************/
3943 : /* GetBand() */
3944 : /************************************************************************/
3945 :
3946 : /**
3947 : * \brief Fetch the band number.
3948 : *
3949 : * This method returns the band that this GDALRasterBand objects represents
3950 : * within its dataset. This method may return a value of 0 to indicate
3951 : * GDALRasterBand objects without an apparently relationship to a dataset,
3952 : * such as GDALRasterBands serving as overviews.
3953 : *
3954 : * This method is the same as the C function GDALGetBandNumber().
3955 : *
3956 : * @return band number (1+) or 0 if the band number isn't known.
3957 : */
3958 :
3959 151198 : int GDALRasterBand::GetBand() const
3960 :
3961 : {
3962 151198 : return nBand;
3963 : }
3964 :
3965 : /************************************************************************/
3966 : /* GDALGetBandNumber() */
3967 : /************************************************************************/
3968 :
3969 : /**
3970 : * \brief Fetch the band number.
3971 : *
3972 : * @see GDALRasterBand::GetBand()
3973 : */
3974 :
3975 159 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3976 :
3977 : {
3978 159 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3979 :
3980 159 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3981 159 : return poBand->GetBand();
3982 : }
3983 :
3984 : /************************************************************************/
3985 : /* GetDataset() */
3986 : /************************************************************************/
3987 :
3988 : /**
3989 : * \brief Fetch the owning dataset handle.
3990 : *
3991 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3992 : * such as overviews or other "freestanding" bands.
3993 : *
3994 : * This method is the same as the C function GDALGetBandDataset().
3995 : *
3996 : * @return the pointer to the GDALDataset to which this band belongs, or
3997 : * NULL if this cannot be determined.
3998 : */
3999 :
4000 5039440 : GDALDataset *GDALRasterBand::GetDataset() const
4001 :
4002 : {
4003 5039440 : return poDS;
4004 : }
4005 :
4006 : /************************************************************************/
4007 : /* GDALGetBandDataset() */
4008 : /************************************************************************/
4009 :
4010 : /**
4011 : * \brief Fetch the owning dataset handle.
4012 : *
4013 : * @see GDALRasterBand::GetDataset()
4014 : */
4015 :
4016 362 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4017 :
4018 : {
4019 362 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4020 :
4021 362 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4022 362 : return GDALDataset::ToHandle(poBand->GetDataset());
4023 : }
4024 :
4025 : /************************************************************************/
4026 : /* ComputeFloat16NoDataValue() */
4027 : /************************************************************************/
4028 :
4029 3323 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4030 : double dfNoDataValue,
4031 : int &bGotNoDataValue,
4032 : GFloat16 &hfNoDataValue,
4033 : bool &bGotFloat16NoDataValue)
4034 : {
4035 3323 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4036 : {
4037 7 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4038 7 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4039 : {
4040 7 : hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4041 7 : bGotFloat16NoDataValue = true;
4042 7 : bGotNoDataValue = false;
4043 : }
4044 : }
4045 3323 : }
4046 :
4047 : /************************************************************************/
4048 : /* ComputeFloatNoDataValue() */
4049 : /************************************************************************/
4050 :
4051 3323 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4052 : double dfNoDataValue,
4053 : int &bGotNoDataValue,
4054 : float &fNoDataValue,
4055 : bool &bGotFloatNoDataValue)
4056 : {
4057 3323 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4058 : {
4059 117 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4060 117 : if (GDALIsValueInRange<float>(dfNoDataValue))
4061 : {
4062 117 : fNoDataValue = static_cast<float>(dfNoDataValue);
4063 117 : bGotFloatNoDataValue = true;
4064 117 : bGotNoDataValue = false;
4065 : }
4066 : }
4067 3319 : else if (eDataType == GDT_Int16 && bGotNoDataValue &&
4068 113 : GDALIsValueExactAs<int16_t>(dfNoDataValue))
4069 : {
4070 113 : fNoDataValue = static_cast<float>(dfNoDataValue);
4071 113 : bGotFloatNoDataValue = true;
4072 : }
4073 3126 : else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
4074 33 : GDALIsValueExactAs<uint16_t>(dfNoDataValue))
4075 : {
4076 33 : fNoDataValue = static_cast<float>(dfNoDataValue);
4077 33 : bGotFloatNoDataValue = true;
4078 : }
4079 3067 : else if (eDataType == GDT_Float16 && bGotNoDataValue &&
4080 7 : GDALIsValueExactAs<GFloat16>(dfNoDataValue))
4081 : {
4082 7 : fNoDataValue = static_cast<float>(dfNoDataValue);
4083 7 : bGotFloatNoDataValue = true;
4084 : }
4085 3323 : }
4086 :
4087 : /************************************************************************/
4088 : /* struct GDALNoDataValues */
4089 : /************************************************************************/
4090 :
4091 : /**
4092 : * \brief No-data-values for all types
4093 : *
4094 : * The functions below pass various no-data-values around. To avoid
4095 : * long argument lists, this struct collects the no-data-values for
4096 : * all types into a single, convenient place.
4097 : **/
4098 :
4099 : struct GDALNoDataValues
4100 : {
4101 : int bGotNoDataValue;
4102 : double dfNoDataValue;
4103 :
4104 : bool bGotInt64NoDataValue;
4105 : int64_t nInt64NoDataValue;
4106 :
4107 : bool bGotUInt64NoDataValue;
4108 : uint64_t nUInt64NoDataValue;
4109 :
4110 : bool bGotFloatNoDataValue;
4111 : float fNoDataValue;
4112 :
4113 : bool bGotFloat16NoDataValue;
4114 : GFloat16 hfNoDataValue;
4115 :
4116 3423 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4117 3423 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4118 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4119 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4120 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4121 3423 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4122 : {
4123 3423 : if (eDataType == GDT_Int64)
4124 : {
4125 62 : int nGot = false;
4126 62 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4127 62 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4128 62 : if (bGotInt64NoDataValue)
4129 : {
4130 10 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4131 10 : bGotNoDataValue =
4132 10 : nInt64NoDataValue <=
4133 20 : std::numeric_limits<int64_t>::max() - 1024 &&
4134 10 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4135 : }
4136 : else
4137 52 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4138 : }
4139 3361 : else if (eDataType == GDT_UInt64)
4140 : {
4141 38 : int nGot = false;
4142 38 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4143 38 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4144 38 : if (bGotUInt64NoDataValue)
4145 : {
4146 10 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4147 10 : bGotNoDataValue =
4148 10 : nUInt64NoDataValue <=
4149 20 : std::numeric_limits<uint64_t>::max() - 2048 &&
4150 10 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4151 : }
4152 : else
4153 28 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4154 : }
4155 : else
4156 : {
4157 3323 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4158 3323 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4159 :
4160 3323 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4161 3323 : fNoDataValue, bGotFloatNoDataValue);
4162 :
4163 3323 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4164 3323 : hfNoDataValue, bGotFloat16NoDataValue);
4165 : }
4166 3423 : }
4167 : };
4168 :
4169 : /************************************************************************/
4170 : /* ARE_REAL_EQUAL() */
4171 : /************************************************************************/
4172 :
4173 28 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4174 : {
4175 : using std::abs;
4176 56 : return dfVal1 == dfVal2 || /* Should cover infinity */
4177 28 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4178 28 : abs(dfVal1 + dfVal2) * ulp;
4179 : }
4180 :
4181 : /************************************************************************/
4182 : /* GetHistogram() */
4183 : /************************************************************************/
4184 :
4185 : /**
4186 : * \brief Compute raster histogram.
4187 : *
4188 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4189 : *
4190 : * For example to compute a simple 256 entry histogram of eight bit data,
4191 : * the following would be suitable. The unusual bounds are to ensure that
4192 : * bucket boundaries don't fall right on integer values causing possible errors
4193 : * due to rounding after scaling.
4194 : \code{.cpp}
4195 : GUIntBig anHistogram[256];
4196 :
4197 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4198 : GDALDummyProgress, nullptr );
4199 : \endcode
4200 : *
4201 : * Note that setting bApproxOK will generally result in a subsampling of the
4202 : * file, and will utilize overviews if available. It should generally
4203 : * produce a representative histogram for the data that is suitable for use
4204 : * in generating histogram based luts for instance. Generally bApproxOK is
4205 : * much faster than an exactly computed histogram.
4206 : *
4207 : * This method is the same as the C functions GDALGetRasterHistogram() and
4208 : * GDALGetRasterHistogramEx().
4209 : *
4210 : * @param dfMin the lower bound of the histogram.
4211 : * @param dfMax the upper bound of the histogram.
4212 : * @param nBuckets the number of buckets in panHistogram.
4213 : * @param panHistogram array into which the histogram totals are placed.
4214 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4215 : * mapped into panHistogram[0], and values above will be mapped into
4216 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4217 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4218 : * @param pfnProgress function to report progress to completion.
4219 : * @param pProgressData application data to pass to pfnProgress.
4220 : *
4221 : * @return CE_None on success, or CE_Failure if something goes wrong.
4222 : */
4223 :
4224 46 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4225 : GUIntBig *panHistogram,
4226 : int bIncludeOutOfRange, int bApproxOK,
4227 : GDALProgressFunc pfnProgress,
4228 : void *pProgressData)
4229 :
4230 : {
4231 46 : CPLAssert(nullptr != panHistogram);
4232 :
4233 46 : if (pfnProgress == nullptr)
4234 30 : pfnProgress = GDALDummyProgress;
4235 :
4236 : /* -------------------------------------------------------------------- */
4237 : /* If we have overviews, use them for the histogram. */
4238 : /* -------------------------------------------------------------------- */
4239 46 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4240 : {
4241 : // FIXME: should we use the most reduced overview here or use some
4242 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4243 : // does?
4244 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4245 :
4246 0 : if (poBestOverview != this)
4247 : {
4248 0 : return poBestOverview->GetHistogram(
4249 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4250 0 : bApproxOK, pfnProgress, pProgressData);
4251 : }
4252 : }
4253 :
4254 : /* -------------------------------------------------------------------- */
4255 : /* Read actual data and build histogram. */
4256 : /* -------------------------------------------------------------------- */
4257 46 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4258 : {
4259 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4260 0 : return CE_Failure;
4261 : }
4262 :
4263 : // Written this way to deal with NaN
4264 46 : if (!(dfMax > dfMin))
4265 : {
4266 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4267 : "dfMax should be strictly greater than dfMin");
4268 5 : return CE_Failure;
4269 : }
4270 :
4271 : GDALRasterIOExtraArg sExtraArg;
4272 41 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4273 :
4274 41 : const double dfScale = nBuckets / (dfMax - dfMin);
4275 41 : if (dfScale == 0 || !std::isfinite(dfScale))
4276 : {
4277 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4278 : "dfMin and dfMax should be finite values such that "
4279 : "nBuckets / (dfMax - dfMin) is non-zero");
4280 5 : return CE_Failure;
4281 : }
4282 36 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4283 :
4284 36 : GDALNoDataValues sNoDataValues(this, eDataType);
4285 36 : GDALRasterBand *poMaskBand = nullptr;
4286 36 : if (!sNoDataValues.bGotNoDataValue)
4287 : {
4288 34 : const int l_nMaskFlags = GetMaskFlags();
4289 36 : if (l_nMaskFlags != GMF_ALL_VALID &&
4290 2 : GetColorInterpretation() != GCI_AlphaBand)
4291 : {
4292 2 : poMaskBand = GetMaskBand();
4293 : }
4294 : }
4295 :
4296 36 : bool bSignedByte = false;
4297 36 : if (eDataType == GDT_UInt8)
4298 : {
4299 26 : EnablePixelTypeSignedByteWarning(false);
4300 : const char *pszPixelType =
4301 26 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
4302 26 : EnablePixelTypeSignedByteWarning(true);
4303 26 : bSignedByte =
4304 26 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4305 : }
4306 :
4307 36 : if (bApproxOK && HasArbitraryOverviews())
4308 : {
4309 : /* --------------------------------------------------------------------
4310 : */
4311 : /* Figure out how much the image should be reduced to get an */
4312 : /* approximate value. */
4313 : /* --------------------------------------------------------------------
4314 : */
4315 : const double dfReduction =
4316 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4317 : GDALSTAT_APPROX_NUMSAMPLES);
4318 :
4319 0 : int nXReduced = nRasterXSize;
4320 0 : int nYReduced = nRasterYSize;
4321 0 : if (dfReduction > 1.0)
4322 : {
4323 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4324 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4325 :
4326 : // Catch the case of huge resizing ratios here
4327 0 : if (nXReduced == 0)
4328 0 : nXReduced = 1;
4329 0 : if (nYReduced == 0)
4330 0 : nYReduced = 1;
4331 : }
4332 :
4333 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4334 : nXReduced, nYReduced);
4335 0 : if (!pData)
4336 0 : return CE_Failure;
4337 :
4338 : const CPLErr eErr =
4339 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4340 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4341 0 : if (eErr != CE_None)
4342 : {
4343 0 : CPLFree(pData);
4344 0 : return eErr;
4345 : }
4346 :
4347 0 : GByte *pabyMaskData = nullptr;
4348 0 : if (poMaskBand)
4349 : {
4350 : pabyMaskData =
4351 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4352 0 : if (!pabyMaskData)
4353 : {
4354 0 : CPLFree(pData);
4355 0 : return CE_Failure;
4356 : }
4357 :
4358 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4359 : pabyMaskData, nXReduced, nYReduced,
4360 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
4361 : {
4362 0 : CPLFree(pData);
4363 0 : CPLFree(pabyMaskData);
4364 0 : return CE_Failure;
4365 : }
4366 : }
4367 :
4368 : // This isn't the fastest way to do this, but is easier for now.
4369 0 : for (int iY = 0; iY < nYReduced; iY++)
4370 : {
4371 0 : for (int iX = 0; iX < nXReduced; iX++)
4372 : {
4373 0 : const int iOffset = iX + iY * nXReduced;
4374 0 : double dfValue = 0.0;
4375 :
4376 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4377 0 : continue;
4378 :
4379 0 : switch (eDataType)
4380 : {
4381 0 : case GDT_UInt8:
4382 : {
4383 0 : if (bSignedByte)
4384 0 : dfValue =
4385 0 : static_cast<signed char *>(pData)[iOffset];
4386 : else
4387 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4388 0 : break;
4389 : }
4390 0 : case GDT_Int8:
4391 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4392 0 : break;
4393 0 : case GDT_UInt16:
4394 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4395 0 : break;
4396 0 : case GDT_Int16:
4397 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4398 0 : break;
4399 0 : case GDT_UInt32:
4400 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4401 0 : break;
4402 0 : case GDT_Int32:
4403 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4404 0 : break;
4405 0 : case GDT_UInt64:
4406 0 : dfValue = static_cast<double>(
4407 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4408 0 : break;
4409 0 : case GDT_Int64:
4410 0 : dfValue = static_cast<double>(
4411 0 : static_cast<GInt64 *>(pData)[iOffset]);
4412 0 : break;
4413 0 : case GDT_Float16:
4414 : {
4415 : using namespace std;
4416 0 : const GFloat16 hfValue =
4417 0 : static_cast<GFloat16 *>(pData)[iOffset];
4418 0 : if (isnan(hfValue) ||
4419 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4420 0 : ARE_REAL_EQUAL(hfValue,
4421 : sNoDataValues.hfNoDataValue)))
4422 0 : continue;
4423 0 : dfValue = hfValue;
4424 0 : break;
4425 : }
4426 0 : case GDT_Float32:
4427 : {
4428 0 : const float fValue =
4429 0 : static_cast<float *>(pData)[iOffset];
4430 0 : if (std::isnan(fValue) ||
4431 0 : (sNoDataValues.bGotFloatNoDataValue &&
4432 0 : ARE_REAL_EQUAL(fValue,
4433 : sNoDataValues.fNoDataValue)))
4434 0 : continue;
4435 0 : dfValue = double(fValue);
4436 0 : break;
4437 : }
4438 0 : case GDT_Float64:
4439 0 : dfValue = static_cast<double *>(pData)[iOffset];
4440 0 : if (std::isnan(dfValue))
4441 0 : continue;
4442 0 : break;
4443 0 : case GDT_CInt16:
4444 : {
4445 0 : const double dfReal =
4446 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4447 0 : const double dfImag =
4448 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4449 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4450 0 : continue;
4451 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4452 : }
4453 0 : break;
4454 0 : case GDT_CInt32:
4455 : {
4456 0 : const double dfReal =
4457 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4458 0 : const double dfImag =
4459 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4460 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4461 0 : continue;
4462 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4463 : }
4464 0 : break;
4465 0 : case GDT_CFloat16:
4466 : {
4467 : const double dfReal =
4468 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4469 : const double dfImag =
4470 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4471 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4472 0 : continue;
4473 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4474 0 : break;
4475 : }
4476 0 : case GDT_CFloat32:
4477 : {
4478 0 : const double dfReal =
4479 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4480 0 : const double dfImag = double(
4481 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4482 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4483 0 : continue;
4484 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4485 0 : break;
4486 : }
4487 0 : case GDT_CFloat64:
4488 : {
4489 0 : const double dfReal =
4490 0 : static_cast<double *>(pData)[iOffset * 2];
4491 0 : const double dfImag =
4492 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4493 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4494 0 : continue;
4495 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4496 0 : break;
4497 : }
4498 0 : case GDT_Unknown:
4499 : case GDT_TypeCount:
4500 0 : CPLAssert(false);
4501 : }
4502 :
4503 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4504 0 : sNoDataValues.bGotNoDataValue &&
4505 0 : (GDALDataTypeIsInteger(eDataType)
4506 0 : ? dfValue == sNoDataValues.dfNoDataValue
4507 0 : : ARE_REAL_EQUAL(dfValue,
4508 : sNoDataValues.dfNoDataValue)))
4509 0 : continue;
4510 :
4511 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4512 : // finite, the result of the multiplication cannot be NaN
4513 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4514 :
4515 0 : if (dfIndex < 0)
4516 : {
4517 0 : if (bIncludeOutOfRange)
4518 0 : panHistogram[0]++;
4519 : }
4520 0 : else if (dfIndex >= nBuckets)
4521 : {
4522 0 : if (bIncludeOutOfRange)
4523 0 : ++panHistogram[nBuckets - 1];
4524 : }
4525 : else
4526 : {
4527 0 : ++panHistogram[static_cast<int>(dfIndex)];
4528 : }
4529 : }
4530 : }
4531 :
4532 0 : CPLFree(pData);
4533 0 : CPLFree(pabyMaskData);
4534 : }
4535 : else // No arbitrary overviews.
4536 : {
4537 36 : if (!InitBlockInfo())
4538 0 : return CE_Failure;
4539 :
4540 : /* --------------------------------------------------------------------
4541 : */
4542 : /* Figure out the ratio of blocks we will read to get an */
4543 : /* approximate value. */
4544 : /* --------------------------------------------------------------------
4545 : */
4546 :
4547 36 : int nSampleRate = 1;
4548 36 : if (bApproxOK)
4549 : {
4550 8 : nSampleRate = static_cast<int>(std::max(
4551 16 : 1.0,
4552 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4553 : // We want to avoid probing only the first column of blocks for
4554 : // a square shaped raster, because it is not unlikely that it may
4555 : // be padding only (#6378).
4556 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4557 1 : nSampleRate += 1;
4558 : }
4559 :
4560 36 : GByte *pabyMaskData = nullptr;
4561 36 : if (poMaskBand)
4562 : {
4563 : pabyMaskData = static_cast<GByte *>(
4564 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4565 2 : if (!pabyMaskData)
4566 : {
4567 0 : return CE_Failure;
4568 : }
4569 : }
4570 :
4571 : /* --------------------------------------------------------------------
4572 : */
4573 : /* Read the blocks, and add to histogram. */
4574 : /* --------------------------------------------------------------------
4575 : */
4576 36 : for (GIntBig iSampleBlock = 0;
4577 163 : iSampleBlock <
4578 163 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4579 127 : iSampleBlock += nSampleRate)
4580 : {
4581 127 : if (!pfnProgress(
4582 127 : static_cast<double>(iSampleBlock) /
4583 127 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4584 : "Compute Histogram", pProgressData))
4585 : {
4586 0 : CPLFree(pabyMaskData);
4587 0 : return CE_Failure;
4588 : }
4589 :
4590 127 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4591 127 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4592 :
4593 127 : int nXCheck = 0, nYCheck = 0;
4594 127 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4595 :
4596 129 : if (poMaskBand &&
4597 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4598 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4599 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4600 2 : 0, nBlockXSize, nullptr) != CE_None)
4601 : {
4602 0 : CPLFree(pabyMaskData);
4603 0 : return CE_Failure;
4604 : }
4605 :
4606 127 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4607 127 : if (poBlock == nullptr)
4608 : {
4609 0 : CPLFree(pabyMaskData);
4610 0 : return CE_Failure;
4611 : }
4612 :
4613 127 : void *pData = poBlock->GetDataRef();
4614 :
4615 : // this is a special case for a common situation.
4616 127 : if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4617 89 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4618 86 : nXCheck == nBlockXSize && nBuckets == 256)
4619 : {
4620 86 : const GPtrDiff_t nPixels =
4621 86 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4622 86 : GByte *pabyData = static_cast<GByte *>(pData);
4623 :
4624 79640 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4625 : {
4626 79554 : if (pabyMaskData && pabyMaskData[i] == 0)
4627 0 : continue;
4628 79554 : if (!(sNoDataValues.bGotNoDataValue &&
4629 512 : (pabyData[i] ==
4630 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4631 : {
4632 79298 : panHistogram[pabyData[i]]++;
4633 : }
4634 : }
4635 :
4636 86 : poBlock->DropLock();
4637 86 : continue; // To next sample block.
4638 : }
4639 :
4640 : // This isn't the fastest way to do this, but is easier for now.
4641 261 : for (int iY = 0; iY < nYCheck; iY++)
4642 : {
4643 36395 : for (int iX = 0; iX < nXCheck; iX++)
4644 : {
4645 36175 : const GPtrDiff_t iOffset =
4646 36175 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4647 :
4648 36175 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4649 2 : continue;
4650 :
4651 36173 : double dfValue = 0.0;
4652 :
4653 36173 : switch (eDataType)
4654 : {
4655 19716 : case GDT_UInt8:
4656 : {
4657 19716 : if (bSignedByte)
4658 0 : dfValue =
4659 0 : static_cast<signed char *>(pData)[iOffset];
4660 : else
4661 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4662 19716 : break;
4663 : }
4664 1 : case GDT_Int8:
4665 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4666 1 : break;
4667 16384 : case GDT_UInt16:
4668 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4669 16384 : break;
4670 3 : case GDT_Int16:
4671 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4672 3 : break;
4673 4 : case GDT_UInt32:
4674 4 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4675 4 : break;
4676 60 : case GDT_Int32:
4677 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4678 60 : break;
4679 0 : case GDT_UInt64:
4680 0 : dfValue = static_cast<double>(
4681 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4682 0 : break;
4683 0 : case GDT_Int64:
4684 0 : dfValue = static_cast<double>(
4685 0 : static_cast<GInt64 *>(pData)[iOffset]);
4686 0 : break;
4687 0 : case GDT_Float16:
4688 : {
4689 : using namespace std;
4690 0 : const GFloat16 hfValue =
4691 0 : static_cast<GFloat16 *>(pData)[iOffset];
4692 0 : if (isnan(hfValue) ||
4693 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4694 0 : ARE_REAL_EQUAL(hfValue,
4695 : sNoDataValues.hfNoDataValue)))
4696 0 : continue;
4697 0 : dfValue = hfValue;
4698 0 : break;
4699 : }
4700 3 : case GDT_Float32:
4701 : {
4702 3 : const float fValue =
4703 3 : static_cast<float *>(pData)[iOffset];
4704 6 : if (std::isnan(fValue) ||
4705 6 : (sNoDataValues.bGotFloatNoDataValue &&
4706 3 : ARE_REAL_EQUAL(fValue,
4707 : sNoDataValues.fNoDataValue)))
4708 0 : continue;
4709 3 : dfValue = double(fValue);
4710 3 : break;
4711 : }
4712 2 : case GDT_Float64:
4713 2 : dfValue = static_cast<double *>(pData)[iOffset];
4714 2 : if (std::isnan(dfValue))
4715 0 : continue;
4716 2 : break;
4717 0 : case GDT_CInt16:
4718 : {
4719 0 : double dfReal =
4720 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4721 0 : double dfImag =
4722 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4723 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4724 0 : break;
4725 : }
4726 0 : case GDT_CInt32:
4727 : {
4728 0 : double dfReal =
4729 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4730 0 : double dfImag =
4731 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4732 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4733 0 : break;
4734 : }
4735 0 : case GDT_CFloat16:
4736 : {
4737 : double dfReal =
4738 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4739 : double dfImag =
4740 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4741 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4742 0 : continue;
4743 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4744 0 : break;
4745 : }
4746 0 : case GDT_CFloat32:
4747 : {
4748 0 : double dfReal = double(
4749 0 : static_cast<float *>(pData)[iOffset * 2]);
4750 0 : double dfImag = double(
4751 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4752 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4753 0 : continue;
4754 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4755 0 : break;
4756 : }
4757 0 : case GDT_CFloat64:
4758 : {
4759 0 : double dfReal =
4760 0 : static_cast<double *>(pData)[iOffset * 2];
4761 0 : double dfImag =
4762 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4763 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4764 0 : continue;
4765 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4766 0 : break;
4767 : }
4768 0 : case GDT_Unknown:
4769 : case GDT_TypeCount:
4770 0 : CPLAssert(false);
4771 : CPLFree(pabyMaskData);
4772 : return CE_Failure;
4773 : }
4774 :
4775 36173 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4776 72350 : sNoDataValues.bGotNoDataValue &&
4777 4 : (GDALDataTypeIsInteger(eDataType)
4778 4 : ? dfValue == sNoDataValues.dfNoDataValue
4779 0 : : ARE_REAL_EQUAL(dfValue,
4780 : sNoDataValues.dfNoDataValue)))
4781 1 : continue;
4782 :
4783 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4784 : // and finite, the result of the multiplication cannot be
4785 : // NaN
4786 36172 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4787 :
4788 36172 : if (dfIndex < 0)
4789 : {
4790 1 : if (bIncludeOutOfRange)
4791 1 : panHistogram[0]++;
4792 : }
4793 36171 : else if (dfIndex >= nBuckets)
4794 : {
4795 7 : if (bIncludeOutOfRange)
4796 4 : ++panHistogram[nBuckets - 1];
4797 : }
4798 : else
4799 : {
4800 36164 : ++panHistogram[static_cast<int>(dfIndex)];
4801 : }
4802 : }
4803 : }
4804 :
4805 41 : poBlock->DropLock();
4806 : }
4807 :
4808 36 : CPLFree(pabyMaskData);
4809 : }
4810 :
4811 36 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4812 :
4813 36 : return CE_None;
4814 : }
4815 :
4816 : /************************************************************************/
4817 : /* GDALGetRasterHistogram() */
4818 : /************************************************************************/
4819 :
4820 : /**
4821 : * \brief Compute raster histogram.
4822 : *
4823 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4824 : * exceeding 2 billion.
4825 : *
4826 : * @see GDALRasterBand::GetHistogram()
4827 : * @see GDALGetRasterHistogramEx()
4828 : */
4829 :
4830 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4831 : double dfMax, int nBuckets,
4832 : int *panHistogram,
4833 : int bIncludeOutOfRange, int bApproxOK,
4834 : GDALProgressFunc pfnProgress,
4835 : void *pProgressData)
4836 :
4837 : {
4838 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4839 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4840 :
4841 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4842 :
4843 : GUIntBig *panHistogramTemp =
4844 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4845 0 : if (panHistogramTemp == nullptr)
4846 : {
4847 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4848 : "Out of memory in GDALGetRasterHistogram().");
4849 0 : return CE_Failure;
4850 : }
4851 :
4852 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4853 : bIncludeOutOfRange, bApproxOK,
4854 0 : pfnProgress, pProgressData);
4855 :
4856 0 : if (eErr == CE_None)
4857 : {
4858 0 : for (int i = 0; i < nBuckets; i++)
4859 : {
4860 0 : if (panHistogramTemp[i] > INT_MAX)
4861 : {
4862 0 : CPLError(CE_Warning, CPLE_AppDefined,
4863 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4864 : " exceeds maximum 32 bit value",
4865 0 : i, panHistogramTemp[i]);
4866 0 : panHistogram[i] = INT_MAX;
4867 : }
4868 : else
4869 : {
4870 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4871 : }
4872 : }
4873 : }
4874 :
4875 0 : CPLFree(panHistogramTemp);
4876 :
4877 0 : return eErr;
4878 : }
4879 :
4880 : /************************************************************************/
4881 : /* GDALGetRasterHistogramEx() */
4882 : /************************************************************************/
4883 :
4884 : /**
4885 : * \brief Compute raster histogram.
4886 : *
4887 : * @see GDALRasterBand::GetHistogram()
4888 : *
4889 : */
4890 :
4891 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4892 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4893 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4894 : GDALProgressFunc pfnProgress, void *pProgressData)
4895 :
4896 : {
4897 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4898 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4899 :
4900 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4901 :
4902 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4903 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4904 26 : pProgressData);
4905 : }
4906 :
4907 : /************************************************************************/
4908 : /* GetDefaultHistogram() */
4909 : /************************************************************************/
4910 :
4911 : /**
4912 : * \brief Fetch default raster histogram.
4913 : *
4914 : * The default method in GDALRasterBand will compute a default histogram. This
4915 : * method is overridden by derived classes (such as GDALPamRasterBand,
4916 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4917 : * stored histogram.
4918 : *
4919 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4920 : * GDALGetDefaultHistogramEx().
4921 : *
4922 : * @param pdfMin pointer to double value that will contain the lower bound of
4923 : * the histogram.
4924 : * @param pdfMax pointer to double value that will contain the upper bound of
4925 : * the histogram.
4926 : * @param pnBuckets pointer to int value that will contain the number of buckets
4927 : * in *ppanHistogram.
4928 : * @param ppanHistogram pointer to array into which the histogram totals are
4929 : * placed. To be freed with VSIFree
4930 : * @param bForce TRUE to force the computation. If FALSE and no default
4931 : * histogram is available, the method will return CE_Warning
4932 : * @param pfnProgress function to report progress to completion.
4933 : * @param pProgressData application data to pass to pfnProgress.
4934 : *
4935 : * @return CE_None on success, CE_Failure if something goes wrong, or
4936 : * CE_Warning if no default histogram is available.
4937 : */
4938 :
4939 28 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4940 : int *pnBuckets,
4941 : GUIntBig **ppanHistogram, int bForce,
4942 : GDALProgressFunc pfnProgress,
4943 : void *pProgressData)
4944 :
4945 : {
4946 28 : CPLAssert(nullptr != pnBuckets);
4947 28 : CPLAssert(nullptr != ppanHistogram);
4948 28 : CPLAssert(nullptr != pdfMin);
4949 28 : CPLAssert(nullptr != pdfMax);
4950 :
4951 28 : *pnBuckets = 0;
4952 28 : *ppanHistogram = nullptr;
4953 :
4954 28 : if (!bForce)
4955 5 : return CE_Warning;
4956 :
4957 23 : int nBuckets = 256;
4958 :
4959 23 : bool bSignedByte = false;
4960 23 : if (eDataType == GDT_UInt8)
4961 : {
4962 20 : EnablePixelTypeSignedByteWarning(false);
4963 : const char *pszPixelType =
4964 20 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
4965 20 : EnablePixelTypeSignedByteWarning(true);
4966 20 : bSignedByte =
4967 20 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4968 : }
4969 :
4970 23 : if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4971 : {
4972 20 : *pdfMin = -0.5;
4973 20 : *pdfMax = 255.5;
4974 : }
4975 3 : else if (GetRasterDataType() == GDT_Int8)
4976 : {
4977 1 : *pdfMin = -128 - 0.5;
4978 1 : *pdfMax = 127 + 0.5;
4979 : }
4980 : else
4981 : {
4982 :
4983 : const CPLErr eErr =
4984 2 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4985 2 : if (eErr != CE_None)
4986 0 : return eErr;
4987 2 : if (*pdfMin == *pdfMax)
4988 : {
4989 1 : nBuckets = 1;
4990 1 : *pdfMin -= 0.5;
4991 1 : *pdfMax += 0.5;
4992 : }
4993 : else
4994 : {
4995 1 : const double dfHalfBucket =
4996 1 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4997 1 : *pdfMin -= dfHalfBucket;
4998 1 : *pdfMax += dfHalfBucket;
4999 : }
5000 : }
5001 :
5002 23 : *ppanHistogram =
5003 23 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
5004 23 : if (*ppanHistogram == nullptr)
5005 : {
5006 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
5007 : "Out of memory in GetDefaultHistogram().");
5008 0 : return CE_Failure;
5009 : }
5010 :
5011 23 : *pnBuckets = nBuckets;
5012 46 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
5013 23 : TRUE, FALSE, pfnProgress, pProgressData);
5014 23 : if (eErr != CE_None)
5015 : {
5016 0 : *pnBuckets = 0;
5017 : }
5018 23 : return eErr;
5019 : }
5020 :
5021 : /************************************************************************/
5022 : /* GDALGetDefaultHistogram() */
5023 : /************************************************************************/
5024 :
5025 : /**
5026 : * \brief Fetch default raster histogram.
5027 : *
5028 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5029 : * exceeding 2 billion.
5030 : *
5031 : * @see GDALRasterBand::GDALGetDefaultHistogram()
5032 : * @see GDALGetRasterHistogramEx()
5033 : */
5034 :
5035 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5036 : double *pdfMin, double *pdfMax,
5037 : int *pnBuckets, int **ppanHistogram,
5038 : int bForce,
5039 : GDALProgressFunc pfnProgress,
5040 : void *pProgressData)
5041 :
5042 : {
5043 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5044 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5045 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5046 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5047 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5048 :
5049 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5050 0 : GUIntBig *panHistogramTemp = nullptr;
5051 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5052 : &panHistogramTemp, bForce,
5053 0 : pfnProgress, pProgressData);
5054 0 : if (eErr == CE_None)
5055 : {
5056 0 : const int nBuckets = *pnBuckets;
5057 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5058 0 : if (*ppanHistogram == nullptr)
5059 : {
5060 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5061 : "Out of memory in GDALGetDefaultHistogram().");
5062 0 : VSIFree(panHistogramTemp);
5063 0 : return CE_Failure;
5064 : }
5065 :
5066 0 : for (int i = 0; i < nBuckets; ++i)
5067 : {
5068 0 : if (panHistogramTemp[i] > INT_MAX)
5069 : {
5070 0 : CPLError(CE_Warning, CPLE_AppDefined,
5071 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5072 : " exceeds maximum 32 bit value",
5073 0 : i, panHistogramTemp[i]);
5074 0 : (*ppanHistogram)[i] = INT_MAX;
5075 : }
5076 : else
5077 : {
5078 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5079 : }
5080 : }
5081 :
5082 0 : CPLFree(panHistogramTemp);
5083 : }
5084 : else
5085 : {
5086 0 : *ppanHistogram = nullptr;
5087 : }
5088 :
5089 0 : return eErr;
5090 : }
5091 :
5092 : /************************************************************************/
5093 : /* GDALGetDefaultHistogramEx() */
5094 : /************************************************************************/
5095 :
5096 : /**
5097 : * \brief Fetch default raster histogram.
5098 : *
5099 : * @see GDALRasterBand::GetDefaultHistogram()
5100 : *
5101 : */
5102 :
5103 : CPLErr CPL_STDCALL
5104 31 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5105 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5106 : GDALProgressFunc pfnProgress, void *pProgressData)
5107 :
5108 : {
5109 31 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5110 31 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5111 31 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5112 31 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5113 31 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5114 :
5115 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5116 31 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5117 31 : bForce, pfnProgress, pProgressData);
5118 : }
5119 :
5120 : /************************************************************************/
5121 : /* AdviseRead() */
5122 : /************************************************************************/
5123 :
5124 : /**
5125 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5126 : * \brief Advise driver of upcoming read requests.
5127 : *
5128 : * Some GDAL drivers operate more efficiently if they know in advance what
5129 : * set of upcoming read requests will be made. The AdviseRead() method allows
5130 : * an application to notify the driver of the region of interest,
5131 : * and at what resolution the region will be read.
5132 : *
5133 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5134 : * accelerate access via some drivers.
5135 : *
5136 : * Depending on call paths, drivers might receive several calls to
5137 : * AdviseRead() with the same parameters.
5138 : *
5139 : * @param nXOff The pixel offset to the top left corner of the region
5140 : * of the band to be accessed. This would be zero to start from the left side.
5141 : *
5142 : * @param nYOff The line offset to the top left corner of the region
5143 : * of the band to be accessed. This would be zero to start from the top.
5144 : *
5145 : * @param nXSize The width of the region of the band to be accessed in pixels.
5146 : *
5147 : * @param nYSize The height of the region of the band to be accessed in lines.
5148 : *
5149 : * @param nBufXSize the width of the buffer image into which the desired region
5150 : * is to be read, or from which it is to be written.
5151 : *
5152 : * @param nBufYSize the height of the buffer image into which the desired
5153 : * region is to be read, or from which it is to be written.
5154 : *
5155 : * @param eBufType the type of the pixel values in the pData data buffer. The
5156 : * pixel values will automatically be translated to/from the GDALRasterBand
5157 : * data type as needed.
5158 : *
5159 : * @param papszOptions a list of name=value strings with special control
5160 : * options. Normally this is NULL.
5161 : *
5162 : * @return CE_Failure if the request is invalid and CE_None if it works or
5163 : * is ignored.
5164 : */
5165 :
5166 : /**/
5167 : /**/
5168 :
5169 115074 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5170 : int /*nYSize*/, int /*nBufXSize*/,
5171 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5172 : CSLConstList /*papszOptions*/)
5173 : {
5174 115074 : return CE_None;
5175 : }
5176 :
5177 : /************************************************************************/
5178 : /* GDALRasterAdviseRead() */
5179 : /************************************************************************/
5180 :
5181 : /**
5182 : * \brief Advise driver of upcoming read requests.
5183 : *
5184 : * @see GDALRasterBand::AdviseRead()
5185 : */
5186 :
5187 4 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5188 : int nYOff, int nXSize, int nYSize,
5189 : int nBufXSize, int nBufYSize,
5190 : GDALDataType eDT,
5191 : CSLConstList papszOptions)
5192 :
5193 : {
5194 4 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5195 :
5196 4 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5197 4 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5198 : nBufYSize, eDT,
5199 4 : const_cast<char **>(papszOptions));
5200 : }
5201 :
5202 : /************************************************************************/
5203 : /* GetStatistics() */
5204 : /************************************************************************/
5205 :
5206 : /**
5207 : * \brief Fetch image statistics.
5208 : *
5209 : * Returns the minimum, maximum, mean and standard deviation of all
5210 : * pixel values in this band. If approximate statistics are sufficient,
5211 : * the bApproxOK flag can be set to true in which case overviews, or a
5212 : * subset of image tiles may be used in computing the statistics.
5213 : *
5214 : * If bForce is FALSE results will only be returned if it can be done
5215 : * quickly (i.e. without scanning the image, typically by using pre-existing
5216 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5217 : * returned efficiently, the method will return CE_Warning but no warning will
5218 : * be issued. This is a non-standard use of the CE_Warning return value
5219 : * to indicate "nothing done".
5220 : *
5221 : * If bForce is TRUE, and results are quickly available without scanning the
5222 : * image, they will be used. If bForce is TRUE and results are not quickly
5223 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5224 : * which will scan the image.
5225 : *
5226 : * To always force recomputation of statistics, use ComputeStatistics() instead
5227 : * of this method.
5228 : *
5229 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5230 : * will generally cache statistics in the .pam file allowing fast fetch
5231 : * after the first request.
5232 : *
5233 : * This method is the same as the C function GDALGetRasterStatistics().
5234 : *
5235 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5236 : * or a subset of all tiles.
5237 : *
5238 : * @param bForce If FALSE statistics will only be returned if it can
5239 : * be done without rescanning the image. If TRUE, statistics computation will
5240 : * be forced if pre-existing values are not quickly available.
5241 : *
5242 : * @param pdfMin Location into which to load image minimum (may be NULL).
5243 : *
5244 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5245 : *
5246 : * @param pdfMean Location into which to load image mean (may be NULL).
5247 : *
5248 : * @param pdfStdDev Location into which to load image standard deviation
5249 : * (may be NULL).
5250 : *
5251 : * @return CE_None on success, CE_Warning if no values returned,
5252 : * CE_Failure if an error occurs.
5253 : */
5254 :
5255 678 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5256 : double *pdfMax, double *pdfMean,
5257 : double *pdfStdDev)
5258 :
5259 : {
5260 : /* -------------------------------------------------------------------- */
5261 : /* Do we already have metadata items for the requested values? */
5262 : /* -------------------------------------------------------------------- */
5263 1356 : if ((pdfMin == nullptr ||
5264 678 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5265 206 : (pdfMax == nullptr ||
5266 206 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5267 1562 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5268 206 : (pdfStdDev == nullptr ||
5269 206 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5270 : {
5271 206 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5272 : {
5273 199 : if (pdfMin != nullptr)
5274 199 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5275 199 : if (pdfMax != nullptr)
5276 199 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5277 199 : if (pdfMean != nullptr)
5278 199 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5279 199 : if (pdfStdDev != nullptr)
5280 199 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5281 :
5282 199 : return CE_None;
5283 : }
5284 : }
5285 :
5286 : /* -------------------------------------------------------------------- */
5287 : /* Does the driver already know the min/max? */
5288 : /* -------------------------------------------------------------------- */
5289 479 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5290 : {
5291 2 : int bSuccessMin = FALSE;
5292 2 : int bSuccessMax = FALSE;
5293 :
5294 2 : const double dfMin = GetMinimum(&bSuccessMin);
5295 2 : const double dfMax = GetMaximum(&bSuccessMax);
5296 :
5297 2 : if (bSuccessMin && bSuccessMax)
5298 : {
5299 0 : if (pdfMin != nullptr)
5300 0 : *pdfMin = dfMin;
5301 0 : if (pdfMax != nullptr)
5302 0 : *pdfMax = dfMax;
5303 0 : return CE_None;
5304 : }
5305 : }
5306 :
5307 : /* -------------------------------------------------------------------- */
5308 : /* Either return without results, or force computation. */
5309 : /* -------------------------------------------------------------------- */
5310 479 : if (!bForce)
5311 195 : return CE_Warning;
5312 : else
5313 284 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5314 284 : GDALDummyProgress, nullptr, nullptr);
5315 : }
5316 :
5317 : /************************************************************************/
5318 : /* GDALGetRasterStatistics() */
5319 : /************************************************************************/
5320 :
5321 : /**
5322 : * \brief Fetch image statistics.
5323 : *
5324 : * @see GDALRasterBand::GetStatistics()
5325 : */
5326 :
5327 325 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5328 : int bForce, double *pdfMin,
5329 : double *pdfMax, double *pdfMean,
5330 : double *pdfStdDev)
5331 :
5332 : {
5333 325 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5334 :
5335 325 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5336 325 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5337 325 : pdfStdDev);
5338 : }
5339 :
5340 : /************************************************************************/
5341 : /* GDALUInt128 */
5342 : /************************************************************************/
5343 :
5344 : #ifdef HAVE_UINT128_T
5345 : class GDALUInt128
5346 : {
5347 : __uint128_t val;
5348 :
5349 1218 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5350 : {
5351 1218 : }
5352 :
5353 : public:
5354 812 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5355 : {
5356 : // Evaluates to just a single mul on x86_64
5357 812 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5358 : }
5359 :
5360 406 : GDALUInt128 operator-(const GDALUInt128 &other) const
5361 : {
5362 406 : return GDALUInt128(val - other.val);
5363 : }
5364 :
5365 395 : operator double() const
5366 : {
5367 395 : return static_cast<double>(val);
5368 : }
5369 : };
5370 : #else
5371 :
5372 : #if defined(_MSC_VER) && defined(_M_X64)
5373 : #include <intrin.h>
5374 : #endif
5375 :
5376 : class GDALUInt128
5377 : {
5378 : GUIntBig low, high;
5379 :
5380 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5381 : {
5382 : }
5383 :
5384 : public:
5385 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5386 : {
5387 : #if defined(_MSC_VER) && defined(_M_X64)
5388 : GUIntBig highRes;
5389 : GUIntBig lowRes = _umul128(first, second, &highRes);
5390 : return GDALUInt128(lowRes, highRes);
5391 : #else
5392 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5393 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5394 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5395 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5396 : GUIntBig highRes = 0;
5397 : const GUIntBig firstLowSecondHigh =
5398 : static_cast<GUIntBig>(firstLow) * secondHigh;
5399 : const GUIntBig firstHighSecondLow =
5400 : static_cast<GUIntBig>(firstHigh) * secondLow;
5401 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5402 : if (middleTerm < firstLowSecondHigh) // check for overflow
5403 : highRes += static_cast<GUIntBig>(1) << 32;
5404 : const GUIntBig firstLowSecondLow =
5405 : static_cast<GUIntBig>(firstLow) * secondLow;
5406 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5407 : if (lowRes < firstLowSecondLow) // check for overflow
5408 : highRes++;
5409 : highRes +=
5410 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5411 : return GDALUInt128(lowRes, highRes);
5412 : #endif
5413 : }
5414 :
5415 : GDALUInt128 operator-(const GDALUInt128 &other) const
5416 : {
5417 : GUIntBig highRes = high - other.high;
5418 : GUIntBig lowRes = low - other.low;
5419 : if (lowRes > low) // check for underflow
5420 : --highRes;
5421 : return GDALUInt128(lowRes, highRes);
5422 : }
5423 :
5424 : operator double() const
5425 : {
5426 : const double twoPow64 = 18446744073709551616.0;
5427 : return high * twoPow64 + low;
5428 : }
5429 : };
5430 : #endif
5431 :
5432 : /************************************************************************/
5433 : /* ComputeStatisticsInternal() */
5434 : /************************************************************************/
5435 :
5436 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5437 : // not needed.
5438 : #define static_cast_for_coverity_scan static_cast
5439 :
5440 : // The rationale for below optimizations is detailed in statistics.txt
5441 :
5442 : // Use with T = GByte or GUInt16 only !
5443 : template <class T, bool COMPUTE_OTHER_STATS>
5444 : struct ComputeStatisticsInternalGeneric
5445 : {
5446 301 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5447 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5448 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5449 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5450 : {
5451 : static_assert(std::is_same<T, GByte>::value ||
5452 : std::is_same<T, GUInt16>::value,
5453 : "bad type for T");
5454 301 : if (bHasNoData)
5455 : {
5456 : // General case
5457 700 : for (int iY = 0; iY < nYCheck; iY++)
5458 : {
5459 161945 : for (int iX = 0; iX < nXCheck; iX++)
5460 : {
5461 161413 : const GPtrDiff_t iOffset =
5462 161413 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5463 161413 : const GUInt32 nValue = pData[iOffset];
5464 161413 : if (nValue == nNoDataValue)
5465 339 : continue;
5466 161074 : if (nValue < nMin)
5467 64 : nMin = nValue;
5468 161074 : if (nValue > nMax)
5469 179 : nMax = nValue;
5470 : if constexpr (COMPUTE_OTHER_STATS)
5471 : {
5472 159334 : nValidCount++;
5473 159334 : nSum += nValue;
5474 159334 : nSumSquare +=
5475 159334 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5476 159334 : nValue;
5477 : }
5478 : }
5479 : }
5480 : if constexpr (COMPUTE_OTHER_STATS)
5481 : {
5482 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5483 : }
5484 : }
5485 153 : else if (nMin == std::numeric_limits<T>::lowest() &&
5486 20 : nMax == std::numeric_limits<T>::max())
5487 : {
5488 : if constexpr (COMPUTE_OTHER_STATS)
5489 : {
5490 : // Optimization when there is no nodata and we know we have already
5491 : // reached the min and max
5492 416 : for (int iY = 0; iY < nYCheck; iY++)
5493 : {
5494 : int iX;
5495 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5496 : {
5497 1600 : const GPtrDiff_t iOffset =
5498 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5499 1600 : const GUIntBig nValue = pData[iOffset];
5500 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5501 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5502 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5503 1600 : nSum += nValue;
5504 1600 : nSumSquare += nValue * nValue;
5505 1600 : nSum += nValue2;
5506 1600 : nSumSquare += nValue2 * nValue2;
5507 1600 : nSum += nValue3;
5508 1600 : nSumSquare += nValue3 * nValue3;
5509 1600 : nSum += nValue4;
5510 1600 : nSumSquare += nValue4 * nValue4;
5511 : }
5512 414 : for (; iX < nXCheck; ++iX)
5513 : {
5514 10 : const GPtrDiff_t iOffset =
5515 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5516 10 : const GUIntBig nValue = pData[iOffset];
5517 10 : nSum += nValue;
5518 10 : nSumSquare += nValue * nValue;
5519 : }
5520 : }
5521 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5522 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5523 : }
5524 : }
5525 : else
5526 : {
5527 6531 : for (int iY = 0; iY < nYCheck; iY++)
5528 : {
5529 : int iX;
5530 1329024 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5531 : {
5532 1322620 : const GPtrDiff_t iOffset =
5533 1322620 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5534 1322620 : const GUInt32 nValue = pData[iOffset];
5535 1322620 : const GUInt32 nValue2 = pData[iOffset + 1];
5536 1322620 : if (nValue < nValue2)
5537 : {
5538 2329 : if (nValue < nMin)
5539 53 : nMin = nValue;
5540 2329 : if (nValue2 > nMax)
5541 123 : nMax = nValue2;
5542 : }
5543 : else
5544 : {
5545 1320289 : if (nValue2 < nMin)
5546 67 : nMin = nValue2;
5547 1320289 : if (nValue > nMax)
5548 219 : nMax = nValue;
5549 : }
5550 : if constexpr (COMPUTE_OTHER_STATS)
5551 : {
5552 1315560 : nSum += nValue;
5553 1315560 : nSumSquare +=
5554 1315560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5555 1315560 : nValue;
5556 1315560 : nSum += nValue2;
5557 1315560 : nSumSquare +=
5558 1315560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5559 1315560 : nValue2;
5560 : }
5561 : }
5562 6410 : if (iX < nXCheck)
5563 : {
5564 31 : const GPtrDiff_t iOffset =
5565 31 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5566 31 : const GUInt32 nValue = pData[iOffset];
5567 31 : if (nValue < nMin)
5568 19 : nMin = nValue;
5569 31 : if (nValue > nMax)
5570 22 : nMax = nValue;
5571 : if (COMPUTE_OTHER_STATS)
5572 : {
5573 19 : nSum += nValue;
5574 19 : nSumSquare +=
5575 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5576 19 : nValue;
5577 : }
5578 : }
5579 : }
5580 : if constexpr (COMPUTE_OTHER_STATS)
5581 : {
5582 62 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5583 62 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5584 : }
5585 : }
5586 301 : }
5587 : };
5588 :
5589 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5590 : // using 64bit accumulators in internal loops. This also slightly helps in
5591 : // 64bit mode.
5592 : template <bool COMPUTE_OTHER_STATS>
5593 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5594 : {
5595 13972 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5596 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5597 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5598 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5599 : {
5600 13972 : int nOuterLoops = nXCheck / 65536;
5601 13972 : if (nXCheck % 65536)
5602 13972 : nOuterLoops++;
5603 :
5604 13972 : if (bHasNoData)
5605 : {
5606 : // General case
5607 23961 : for (int iY = 0; iY < nYCheck; iY++)
5608 : {
5609 13285 : int iX = 0;
5610 26570 : for (int k = 0; k < nOuterLoops; k++)
5611 : {
5612 13285 : int iMax = iX + 65536;
5613 13285 : if (iMax > nXCheck)
5614 13285 : iMax = nXCheck;
5615 13285 : GUInt32 nSum32bit = 0;
5616 13285 : GUInt32 nSumSquare32bit = 0;
5617 13285 : GUInt32 nValidCount32bit = 0;
5618 13285 : GUInt32 nSampleCount32bit = 0;
5619 20723572 : for (; iX < iMax; iX++)
5620 : {
5621 20710287 : const GPtrDiff_t iOffset =
5622 20710287 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5623 20710287 : const GUInt32 nValue = pData[iOffset];
5624 :
5625 20710287 : nSampleCount32bit++;
5626 20710287 : if (nValue == nNoDataValue)
5627 20354020 : continue;
5628 356216 : if (nValue < nMin)
5629 401 : nMin = nValue;
5630 356216 : if (nValue > nMax)
5631 942 : nMax = nValue;
5632 : if constexpr (COMPUTE_OTHER_STATS)
5633 : {
5634 32367 : nValidCount32bit++;
5635 32367 : nSum32bit += nValue;
5636 32367 : nSumSquare32bit += nValue * nValue;
5637 : }
5638 : }
5639 : if constexpr (COMPUTE_OTHER_STATS)
5640 : {
5641 985 : nSampleCount += nSampleCount32bit;
5642 985 : nValidCount += nValidCount32bit;
5643 985 : nSum += nSum32bit;
5644 985 : nSumSquare += nSumSquare32bit;
5645 : }
5646 : }
5647 : }
5648 : }
5649 3296 : else if (nMin == 0 && nMax == 255)
5650 : {
5651 : if constexpr (COMPUTE_OTHER_STATS)
5652 : {
5653 : // Optimization when there is no nodata and we know we have already
5654 : // reached the min and max
5655 2850 : for (int iY = 0; iY < nYCheck; iY++)
5656 : {
5657 2818 : int iX = 0;
5658 5636 : for (int k = 0; k < nOuterLoops; k++)
5659 : {
5660 2818 : int iMax = iX + 65536;
5661 2818 : if (iMax > nXCheck)
5662 2818 : iMax = nXCheck;
5663 2818 : GUInt32 nSum32bit = 0;
5664 2818 : GUInt32 nSumSquare32bit = 0;
5665 177298 : for (; iX + 3 < iMax; iX += 4)
5666 : {
5667 174480 : const GPtrDiff_t iOffset =
5668 174480 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5669 174480 : const GUInt32 nValue = pData[iOffset];
5670 174480 : const GUInt32 nValue2 = pData[iOffset + 1];
5671 174480 : const GUInt32 nValue3 = pData[iOffset + 2];
5672 174480 : const GUInt32 nValue4 = pData[iOffset + 3];
5673 174480 : nSum32bit += nValue;
5674 174480 : nSumSquare32bit += nValue * nValue;
5675 174480 : nSum32bit += nValue2;
5676 174480 : nSumSquare32bit += nValue2 * nValue2;
5677 174480 : nSum32bit += nValue3;
5678 174480 : nSumSquare32bit += nValue3 * nValue3;
5679 174480 : nSum32bit += nValue4;
5680 174480 : nSumSquare32bit += nValue4 * nValue4;
5681 : }
5682 2818 : nSum += nSum32bit;
5683 2818 : nSumSquare += nSumSquare32bit;
5684 : }
5685 2824 : for (; iX < nXCheck; ++iX)
5686 : {
5687 6 : const GPtrDiff_t iOffset =
5688 6 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5689 6 : const GUIntBig nValue = pData[iOffset];
5690 6 : nSum += nValue;
5691 6 : nSumSquare += nValue * nValue;
5692 : }
5693 : }
5694 32 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5695 32 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5696 32 : }
5697 : }
5698 : else
5699 : {
5700 9234 : for (int iY = 0; iY < nYCheck; iY++)
5701 : {
5702 5970 : int iX = 0;
5703 11940 : for (int k = 0; k < nOuterLoops; k++)
5704 : {
5705 5970 : int iMax = iX + 65536;
5706 5970 : if (iMax > nXCheck)
5707 5970 : iMax = nXCheck;
5708 5970 : GUInt32 nSum32bit = 0;
5709 5970 : GUInt32 nSumSquare32bit = 0;
5710 344985 : for (; iX + 1 < iMax; iX += 2)
5711 : {
5712 339015 : const GPtrDiff_t iOffset =
5713 339015 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5714 339015 : const GUInt32 nValue = pData[iOffset];
5715 339015 : const GUInt32 nValue2 = pData[iOffset + 1];
5716 339015 : if (nValue < nValue2)
5717 : {
5718 8155 : if (nValue < nMin)
5719 237 : nMin = nValue;
5720 8155 : if (nValue2 > nMax)
5721 230 : nMax = nValue2;
5722 : }
5723 : else
5724 : {
5725 330860 : if (nValue2 < nMin)
5726 367 : nMin = nValue2;
5727 330860 : if (nValue > nMax)
5728 849 : nMax = nValue;
5729 : }
5730 : if constexpr (COMPUTE_OTHER_STATS)
5731 : {
5732 315626 : nSum32bit += nValue;
5733 315626 : nSumSquare32bit += nValue * nValue;
5734 315626 : nSum32bit += nValue2;
5735 315626 : nSumSquare32bit += nValue2 * nValue2;
5736 : }
5737 : }
5738 : if constexpr (COMPUTE_OTHER_STATS)
5739 : {
5740 2651 : nSum += nSum32bit;
5741 2651 : nSumSquare += nSumSquare32bit;
5742 : }
5743 : }
5744 5970 : if (iX < nXCheck)
5745 : {
5746 1542 : const GPtrDiff_t iOffset =
5747 1542 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5748 1542 : const GUInt32 nValue = pData[iOffset];
5749 1542 : if (nValue < nMin)
5750 118 : nMin = nValue;
5751 1542 : if (nValue > nMax)
5752 104 : nMax = nValue;
5753 : if constexpr (COMPUTE_OTHER_STATS)
5754 : {
5755 322 : nSum += nValue;
5756 322 : nSumSquare +=
5757 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5758 322 : nValue;
5759 : }
5760 : }
5761 : }
5762 : if constexpr (COMPUTE_OTHER_STATS)
5763 : {
5764 939 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5765 939 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5766 : }
5767 : }
5768 13972 : }
5769 : };
5770 :
5771 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5772 : {
5773 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5774 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5775 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5776 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5777 : {
5778 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5779 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5780 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5781 : }
5782 : };
5783 :
5784 : constexpr int ALIGNMENT_AVX2_OPTIM = 32;
5785 :
5786 : #if (defined(__x86_64__) || defined(_M_X64) || \
5787 : defined(USE_NEON_OPTIMIZATIONS)) && \
5788 : (defined(__GNUC__) || defined(_MSC_VER))
5789 :
5790 : #include "gdal_avx2_emulation.hpp"
5791 :
5792 : #define ZERO256 GDALmm256_setzero_si256()
5793 :
5794 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5795 : static void
5796 21924 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5797 : // assumed to be aligned on 256 bits
5798 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5799 : GUIntBig &nSum, GUIntBig &nSumSquare,
5800 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5801 : {
5802 : // 32-byte alignment may not be enforced by linker, so do it at hand
5803 : GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
5804 : ALIGNMENT_AVX2_OPTIM +
5805 : (COMPUTE_OTHER_STATS
5806 : ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
5807 : : 0)];
5808 21924 : GByte *paby32ByteAligned =
5809 : aby32ByteUnaligned +
5810 21924 : (ALIGNMENT_AVX2_OPTIM -
5811 21924 : (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
5812 : ALIGNMENT_AVX2_OPTIM));
5813 21924 : GByte *pabyMin = paby32ByteAligned;
5814 21924 : GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
5815 21924 : GUInt32 *panSum = COMPUTE_OTHER_STATS
5816 : ? reinterpret_cast<GUInt32 *>(
5817 : paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
5818 : : nullptr;
5819 21924 : GUInt32 *panSumSquare =
5820 : COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
5821 : paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
5822 : : nullptr;
5823 :
5824 21924 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
5825 :
5826 21924 : GPtrDiff_t i = 0;
5827 : // Make sure that sumSquare can fit on uint32
5828 : // * 8 since we can hold 8 sums per vector register
5829 21924 : const int nMaxIterationsPerInnerLoop =
5830 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5831 21924 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5832 21924 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5833 21924 : nOuterLoops++;
5834 :
5835 : GDALm256i ymm_min =
5836 21924 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5837 21924 : GDALm256i ymm_max = ymm_min;
5838 21924 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5839 :
5840 43848 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5841 : {
5842 21924 : const auto iMax =
5843 21924 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5844 :
5845 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5846 21924 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5847 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5848 21924 : ZERO256; // holds 8 uint32 sums
5849 774522 : for (; i + 31 < iMax; i += 32)
5850 : {
5851 752598 : const GDALm256i ymm = GDALmm256_load_si256(
5852 752598 : reinterpret_cast<const GDALm256i *>(pData + i));
5853 : if (COMPUTE_MIN)
5854 : {
5855 292537 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5856 : }
5857 : if (COMPUTE_MAX)
5858 : {
5859 649698 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5860 : }
5861 :
5862 : if constexpr (COMPUTE_OTHER_STATS)
5863 : {
5864 : // Extract even-8bit values
5865 : const GDALm256i ymm_even =
5866 536880 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5867 : // Compute square of those 16 values as 32 bit result
5868 : // and add adjacent pairs
5869 : const GDALm256i ymm_even_square =
5870 536880 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5871 : // Add to the sumsquare accumulator
5872 : ymm_sumsquare =
5873 536880 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5874 :
5875 : // Extract odd-8bit values
5876 536880 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5877 : const GDALm256i ymm_odd_square =
5878 536880 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5879 : ymm_sumsquare =
5880 536880 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5881 :
5882 : // Now compute the sums
5883 536880 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5884 : GDALmm256_sad_epu8(ymm, ZERO256));
5885 : }
5886 : }
5887 :
5888 : if constexpr (COMPUTE_OTHER_STATS)
5889 : {
5890 10688 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5891 : ymm_sum);
5892 10688 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5893 : ymm_sumsquare);
5894 :
5895 10688 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5896 10688 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5897 10688 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5898 10688 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5899 : panSumSquare[7];
5900 : }
5901 : }
5902 :
5903 : if constexpr (COMPUTE_MIN)
5904 : {
5905 9033 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5906 : }
5907 : if constexpr (COMPUTE_MAX)
5908 : {
5909 17416 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5910 : }
5911 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5912 : {
5913 610236 : for (int j = 0; j < 32; j++)
5914 : {
5915 : if constexpr (COMPUTE_MIN)
5916 : {
5917 289056 : if (pabyMin[j] < nMin)
5918 1254 : nMin = pabyMin[j];
5919 : }
5920 : if constexpr (COMPUTE_MAX)
5921 : {
5922 557312 : if (pabyMax[j] > nMax)
5923 1803 : nMax = pabyMax[j];
5924 : }
5925 : }
5926 : }
5927 :
5928 235842 : for (; i < nBlockPixels; i++)
5929 : {
5930 213918 : const GUInt32 nValue = pData[i];
5931 : if constexpr (COMPUTE_MIN)
5932 : {
5933 89242 : if (nValue < nMin)
5934 2 : nMin = nValue;
5935 : }
5936 : if constexpr (COMPUTE_MAX)
5937 : {
5938 210261 : if (nValue > nMax)
5939 1150 : nMax = nValue;
5940 : }
5941 : if constexpr (COMPUTE_OTHER_STATS)
5942 : {
5943 77203 : nSum += nValue;
5944 77203 : nSumSquare +=
5945 77203 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5946 : }
5947 : }
5948 :
5949 : if constexpr (COMPUTE_OTHER_STATS)
5950 : {
5951 10688 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5952 10688 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5953 : }
5954 21924 : }
5955 :
5956 : // SSE2/AVX2 optimization for GByte case
5957 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5958 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5959 : // there are strictly equivalent to 2 parallel SSE2 streams.
5960 : template <bool COMPUTE_OTHER_STATS>
5961 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5962 : {
5963 31065 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5964 : // assumed to be aligned on 256 bits
5965 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5966 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5967 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5968 : GUIntBig &nValidCount)
5969 : {
5970 31065 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5971 31065 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5972 11610 : nMin <= nMax)
5973 : {
5974 : // 32-byte alignment may not be enforced by linker, so do it at hand
5975 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5976 1492 : GByte *paby32ByteAligned =
5977 : aby32ByteUnaligned +
5978 1492 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5979 1492 : GByte *pabyMin = paby32ByteAligned;
5980 1492 : GByte *pabyMax = paby32ByteAligned + 32;
5981 1492 : GUInt32 *panSum =
5982 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5983 1492 : GUInt32 *panSumSquare =
5984 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5985 :
5986 1492 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5987 :
5988 1492 : GPtrDiff_t i = 0;
5989 : // Make sure that sumSquare can fit on uint32
5990 : // * 8 since we can hold 8 sums per vector register
5991 1492 : const int nMaxIterationsPerInnerLoop =
5992 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5993 1492 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5994 1492 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5995 1492 : nOuterLoops++;
5996 :
5997 : const GDALm256i ymm_nodata =
5998 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5999 : // any non noData value in [min,max] would do.
6000 : const GDALm256i ymm_neutral =
6001 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
6002 1492 : GDALm256i ymm_min = ymm_neutral;
6003 1492 : GDALm256i ymm_max = ymm_neutral;
6004 : [[maybe_unused]] const auto ymm_mask_8bits =
6005 1492 : GDALmm256_set1_epi16(0xFF);
6006 :
6007 1492 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
6008 1492 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
6009 1492 : const bool bComputeMinMax =
6010 1492 : nMin > nMinThreshold || nMax < nMaxThreshold;
6011 :
6012 2984 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
6013 : {
6014 1492 : const auto iMax =
6015 1492 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6016 :
6017 : // holds 4 uint32 sums in [0], [2], [4] and [6]
6018 1492 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
6019 : // holds 8 uint32 sums
6020 1492 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
6021 : // holds 4 uint32 sums in [0], [2], [4] and [6]
6022 1492 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
6023 1492 : const auto iInit = i;
6024 18982 : for (; i + 31 < iMax; i += 32)
6025 : {
6026 17490 : const GDALm256i ymm = GDALmm256_load_si256(
6027 17490 : reinterpret_cast<const GDALm256i *>(pData + i));
6028 :
6029 : // Check which values are nodata
6030 : const GDALm256i ymm_eq_nodata =
6031 17490 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6032 : if constexpr (COMPUTE_OTHER_STATS)
6033 : {
6034 : // Count how many values are nodata (due to cmpeq
6035 : // putting 255 when condition is met, this will actually
6036 : // be 255 times the number of nodata value, spread in 4
6037 : // 64 bits words). We can use add_epi32 as the counter
6038 : // will not overflow uint32
6039 9148 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6040 : ymm_count_nodata_mul_255,
6041 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6042 : }
6043 : // Replace all nodata values by zero for the purpose of sum
6044 : // and sumquare.
6045 : const GDALm256i ymm_nodata_by_zero =
6046 17490 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6047 17490 : if (bComputeMinMax)
6048 : {
6049 : // Replace all nodata values by a neutral value for the
6050 : // purpose of min and max.
6051 : const GDALm256i ymm_nodata_by_neutral =
6052 8720 : GDALmm256_or_si256(
6053 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6054 : ymm_nodata_by_zero);
6055 :
6056 : ymm_min =
6057 8720 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6058 : ymm_max =
6059 8720 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6060 : }
6061 :
6062 : if constexpr (COMPUTE_OTHER_STATS)
6063 : {
6064 : // Extract even-8bit values
6065 9148 : const GDALm256i ymm_even = GDALmm256_and_si256(
6066 : ymm_nodata_by_zero, ymm_mask_8bits);
6067 : // Compute square of those 16 values as 32 bit result
6068 : // and add adjacent pairs
6069 : const GDALm256i ymm_even_square =
6070 9148 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6071 : // Add to the sumsquare accumulator
6072 : ymm_sumsquare =
6073 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6074 :
6075 : // Extract odd-8bit values
6076 : const GDALm256i ymm_odd =
6077 9148 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6078 : const GDALm256i ymm_odd_square =
6079 9148 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6080 : ymm_sumsquare =
6081 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6082 :
6083 : // Now compute the sums
6084 9148 : ymm_sum = GDALmm256_add_epi32(
6085 : ymm_sum,
6086 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6087 : }
6088 : }
6089 :
6090 : if constexpr (COMPUTE_OTHER_STATS)
6091 : {
6092 186 : GUInt32 *panCoutNoDataMul255 = panSum;
6093 186 : GDALmm256_store_si256(
6094 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6095 : ymm_count_nodata_mul_255);
6096 :
6097 186 : nSampleCount += (i - iInit);
6098 :
6099 186 : nValidCount +=
6100 186 : (i - iInit) -
6101 186 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6102 186 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6103 : 255;
6104 :
6105 186 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6106 : ymm_sum);
6107 186 : GDALmm256_store_si256(
6108 : reinterpret_cast<GDALm256i *>(panSumSquare),
6109 : ymm_sumsquare);
6110 186 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6111 186 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6112 186 : panSumSquare[1] + panSumSquare[2] +
6113 186 : panSumSquare[3] + panSumSquare[4] +
6114 186 : panSumSquare[5] + panSumSquare[6] +
6115 : panSumSquare[7];
6116 : }
6117 : }
6118 :
6119 1492 : if (bComputeMinMax)
6120 : {
6121 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6122 : ymm_min);
6123 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6124 : ymm_max);
6125 47190 : for (int j = 0; j < 32; j++)
6126 : {
6127 45760 : if (pabyMin[j] < nMin)
6128 40 : nMin = pabyMin[j];
6129 45760 : if (pabyMax[j] > nMax)
6130 161 : nMax = pabyMax[j];
6131 : }
6132 : }
6133 :
6134 : if constexpr (COMPUTE_OTHER_STATS)
6135 : {
6136 186 : nSampleCount += nBlockPixels - i;
6137 : }
6138 34048 : for (; i < nBlockPixels; i++)
6139 : {
6140 32556 : const GUInt32 nValue = pData[i];
6141 32556 : if (nValue == nNoDataValue)
6142 24923 : continue;
6143 7633 : if (nValue < nMin)
6144 2 : nMin = nValue;
6145 7633 : if (nValue > nMax)
6146 14 : nMax = nValue;
6147 : if constexpr (COMPUTE_OTHER_STATS)
6148 : {
6149 3700 : nValidCount++;
6150 3700 : nSum += nValue;
6151 3700 : nSumSquare +=
6152 3700 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6153 3700 : nValue;
6154 : }
6155 1492 : }
6156 : }
6157 29573 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6158 : {
6159 15568 : if (nMin > 0)
6160 : {
6161 2677 : if (nMax < 255)
6162 : {
6163 : ComputeStatisticsByteNoNodata<true, true,
6164 1601 : COMPUTE_OTHER_STATS>(
6165 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6166 : nSampleCount, nValidCount);
6167 : }
6168 : else
6169 : {
6170 : ComputeStatisticsByteNoNodata<true, false,
6171 1076 : COMPUTE_OTHER_STATS>(
6172 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6173 : nSampleCount, nValidCount);
6174 : }
6175 : }
6176 : else
6177 : {
6178 12891 : if (nMax < 255)
6179 : {
6180 : ComputeStatisticsByteNoNodata<false, true,
6181 9459 : COMPUTE_OTHER_STATS>(
6182 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6183 : nSampleCount, nValidCount);
6184 : }
6185 : else
6186 : {
6187 : ComputeStatisticsByteNoNodata<false, false,
6188 3432 : COMPUTE_OTHER_STATS>(
6189 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6190 : nSampleCount, nValidCount);
6191 : }
6192 : }
6193 : }
6194 12664 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6195 33 : (nBlockXSize % 32) == 0)
6196 : {
6197 6389 : for (int iY = 0; iY < nYCheck; iY++)
6198 : {
6199 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6200 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6201 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6202 33 : }
6203 : }
6204 : else
6205 : {
6206 13972 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6207 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6208 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6209 : }
6210 31065 : }
6211 : };
6212 :
6213 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6214 578 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6215 : GUIntBig i)
6216 : {
6217 578 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6218 578 : }
6219 :
6220 : // AVX2/SSE2 optimization for GUInt16 case
6221 : template <bool COMPUTE_OTHER_STATS>
6222 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6223 : {
6224 2153 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6225 : // assumed to be aligned on 128 bits
6226 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6227 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6228 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6229 : GUIntBig &nValidCount)
6230 : {
6231 2153 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6232 2153 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6233 : {
6234 1852 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6235 :
6236 1852 : GPtrDiff_t i = 0;
6237 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6238 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6239 : // Furthermore the shift is also needed to use madd_epi16
6240 1852 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6241 1852 : GDALm256i ymm_min = GDALmm256_load_si256(
6242 1852 : reinterpret_cast<const GDALm256i *>(pData + i));
6243 1852 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6244 1852 : GDALm256i ymm_max = ymm_min;
6245 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6246 1852 : ZERO256; // holds 4 uint64 sums
6247 :
6248 : // Make sure that sum can fit on uint32
6249 : // * 8 since we can hold 8 sums per vector register
6250 1852 : const int nMaxIterationsPerInnerLoop =
6251 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6252 1852 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6253 1852 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6254 1852 : nOuterLoops++;
6255 :
6256 1852 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6257 : [[maybe_unused]] const auto ymm_mask_16bits =
6258 1852 : GDALmm256_set1_epi32(0xFFFF);
6259 : [[maybe_unused]] const auto ymm_mask_32bits =
6260 1852 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6261 :
6262 1852 : GUIntBig nSumThis = 0;
6263 3728 : for (int k = 0; k < nOuterLoops; k++)
6264 : {
6265 1876 : const auto iMax =
6266 1876 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6267 :
6268 : [[maybe_unused]] GDALm256i ymm_sum =
6269 1876 : ZERO256; // holds 8 uint32 sums
6270 1112456 : for (; i + 15 < iMax; i += 16)
6271 : {
6272 1110580 : const GDALm256i ymm = GDALmm256_load_si256(
6273 1110580 : reinterpret_cast<const GDALm256i *>(pData + i));
6274 : const GDALm256i ymm_shifted =
6275 1110580 : GDALmm256_add_epi16(ymm, ymm_m32768);
6276 1110580 : if (bComputeMinMax)
6277 : {
6278 1092542 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6279 1092542 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6280 : }
6281 :
6282 : if constexpr (COMPUTE_OTHER_STATS)
6283 : {
6284 : // Note: the int32 range can overflow for (0-32768)^2 +
6285 : // (0-32768)^2 = 0x80000000, but as we know the result
6286 : // is positive, this is OK as we interpret is a uint32.
6287 : const GDALm256i ymm_square =
6288 243562 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6289 243562 : ymm_sumsquare = GDALmm256_add_epi64(
6290 : ymm_sumsquare,
6291 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6292 243562 : ymm_sumsquare = GDALmm256_add_epi64(
6293 : ymm_sumsquare,
6294 : GDALmm256_srli_epi64(ymm_square, 32));
6295 :
6296 : // Now compute the sums
6297 243562 : ymm_sum = GDALmm256_add_epi32(
6298 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6299 243562 : ymm_sum = GDALmm256_add_epi32(
6300 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6301 : }
6302 : }
6303 :
6304 : if constexpr (COMPUTE_OTHER_STATS)
6305 : {
6306 : GUInt32 anSum[8];
6307 578 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6308 : ymm_sum);
6309 578 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6310 578 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6311 578 : anSum[6] + anSum[7];
6312 : }
6313 : }
6314 :
6315 1852 : if (bComputeMinMax)
6316 : {
6317 : GUInt16 anMin[16];
6318 : GUInt16 anMax[16];
6319 :
6320 : // Unshift the result
6321 1770 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6322 1770 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6323 1770 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6324 : ymm_min);
6325 1770 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6326 : ymm_max);
6327 30090 : for (int j = 0; j < 16; j++)
6328 : {
6329 28320 : if (anMin[j] < nMin)
6330 394 : nMin = anMin[j];
6331 28320 : if (anMax[j] > nMax)
6332 571 : nMax = anMax[j];
6333 : }
6334 : }
6335 :
6336 : if constexpr (COMPUTE_OTHER_STATS)
6337 : {
6338 : GUIntBig anSumSquare[4];
6339 578 : GDALmm256_storeu_si256(
6340 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6341 578 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6342 : anSumSquare[3];
6343 :
6344 : // Unshift the sum of squares
6345 578 : UnshiftSumSquare(nSumSquare, nSumThis,
6346 : static_cast<GUIntBig>(i));
6347 :
6348 578 : nSum += nSumThis;
6349 :
6350 1022 : for (; i < nBlockPixels; i++)
6351 : {
6352 444 : const GUInt32 nValue = pData[i];
6353 444 : if (nValue < nMin)
6354 2 : nMin = nValue;
6355 444 : if (nValue > nMax)
6356 2 : nMax = nValue;
6357 444 : nSum += nValue;
6358 444 : nSumSquare +=
6359 444 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6360 444 : nValue;
6361 : }
6362 :
6363 578 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6364 578 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6365 1852 : }
6366 : }
6367 : else
6368 : {
6369 301 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6370 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6371 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6372 : }
6373 2153 : }
6374 : };
6375 :
6376 : #endif
6377 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6378 : // defined(_MSC_VER))
6379 :
6380 : /************************************************************************/
6381 : /* GetPixelValue() */
6382 : /************************************************************************/
6383 :
6384 15872500 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6385 : const void *pData, GPtrDiff_t iOffset,
6386 : const GDALNoDataValues &sNoDataValues,
6387 : bool &bValid)
6388 : {
6389 15872500 : bValid = true;
6390 15872500 : double dfValue = 0;
6391 15872500 : switch (eDataType)
6392 : {
6393 1400780 : case GDT_UInt8:
6394 : {
6395 1400780 : if (bSignedByte)
6396 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6397 : else
6398 1400590 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6399 1400780 : break;
6400 : }
6401 641 : case GDT_Int8:
6402 641 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6403 641 : break;
6404 200608 : case GDT_UInt16:
6405 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6406 200608 : break;
6407 54336 : case GDT_Int16:
6408 54336 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6409 54336 : break;
6410 10486 : case GDT_UInt32:
6411 10486 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6412 10486 : break;
6413 140220 : case GDT_Int32:
6414 140220 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6415 140220 : break;
6416 60 : case GDT_UInt64:
6417 60 : dfValue = static_cast<double>(
6418 60 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6419 60 : break;
6420 3268 : case GDT_Int64:
6421 3268 : dfValue = static_cast<double>(
6422 3268 : static_cast<const std::int64_t *>(pData)[iOffset]);
6423 3268 : break;
6424 40 : case GDT_Float16:
6425 : {
6426 : using namespace std;
6427 40 : const GFloat16 hfValue =
6428 40 : static_cast<const GFloat16 *>(pData)[iOffset];
6429 74 : if (isnan(hfValue) ||
6430 34 : (sNoDataValues.bGotFloat16NoDataValue &&
6431 28 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6432 : {
6433 6 : bValid = false;
6434 6 : return 0.0;
6435 : }
6436 34 : dfValue = hfValue;
6437 34 : return dfValue;
6438 : }
6439 13644000 : case GDT_Float32:
6440 : {
6441 13644000 : const float fValue = static_cast<const float *>(pData)[iOffset];
6442 27261100 : if (std::isnan(fValue) ||
6443 26886000 : (sNoDataValues.bGotFloatNoDataValue &&
6444 13268900 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6445 : {
6446 26883 : bValid = false;
6447 26883 : return 0.0;
6448 : }
6449 13617100 : dfValue = double(fValue);
6450 13617100 : return dfValue;
6451 : }
6452 400958 : case GDT_Float64:
6453 400958 : dfValue = static_cast<const double *>(pData)[iOffset];
6454 400958 : if (std::isnan(dfValue))
6455 : {
6456 6 : bValid = false;
6457 6 : return 0.0;
6458 : }
6459 400952 : break;
6460 2692 : case GDT_CInt16:
6461 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6462 2692 : break;
6463 2692 : case GDT_CInt32:
6464 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6465 2692 : break;
6466 0 : case GDT_CFloat16:
6467 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6468 0 : if (std::isnan(dfValue))
6469 : {
6470 0 : bValid = false;
6471 0 : return 0.0;
6472 : }
6473 0 : break;
6474 5812 : case GDT_CFloat32:
6475 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6476 5812 : if (std::isnan(dfValue))
6477 : {
6478 0 : bValid = false;
6479 0 : return 0.0;
6480 : }
6481 5812 : break;
6482 5892 : case GDT_CFloat64:
6483 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6484 5892 : if (std::isnan(dfValue))
6485 : {
6486 0 : bValid = false;
6487 0 : return 0.0;
6488 : }
6489 5892 : break;
6490 0 : case GDT_Unknown:
6491 : case GDT_TypeCount:
6492 0 : CPLAssert(false);
6493 : break;
6494 : }
6495 :
6496 2483850 : if (sNoDataValues.bGotNoDataValue &&
6497 255413 : (GDALDataTypeIsInteger(eDataType)
6498 180356 : ? dfValue == sNoDataValues.dfNoDataValue
6499 75057 : : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue)))
6500 : {
6501 4220 : bValid = false;
6502 4220 : return 0.0;
6503 : }
6504 2224220 : return dfValue;
6505 : }
6506 :
6507 : /************************************************************************/
6508 : /* SetValidPercent() */
6509 : /************************************************************************/
6510 :
6511 : //! @cond Doxygen_Suppress
6512 : /**
6513 : * \brief Set percentage of valid (not nodata) pixels.
6514 : *
6515 : * Stores the percentage of valid pixels in the metadata item
6516 : * STATISTICS_VALID_PERCENT
6517 : *
6518 : * @param nSampleCount Number of sampled pixels.
6519 : *
6520 : * @param nValidCount Number of valid pixels.
6521 : */
6522 :
6523 611 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6524 : GUIntBig nValidCount)
6525 : {
6526 611 : if (nValidCount == 0)
6527 : {
6528 15 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6529 : }
6530 596 : else if (nValidCount == nSampleCount)
6531 : {
6532 502 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6533 : }
6534 : else /* nValidCount < nSampleCount */
6535 : {
6536 94 : char szValue[128] = {0};
6537 :
6538 : /* percentage is only an indicator: limit precision */
6539 94 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6540 94 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6541 :
6542 94 : if (EQUAL(szValue, "100"))
6543 : {
6544 : /* don't set 100 percent valid
6545 : * because some of the sampled pixels were nodata */
6546 4 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6547 : }
6548 : else
6549 : {
6550 90 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6551 : }
6552 : }
6553 611 : }
6554 :
6555 : //! @endcond
6556 :
6557 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6558 :
6559 : #ifdef __AVX2__
6560 :
6561 : #define set1_ps _mm256_set1_ps
6562 : #define loadu_ps _mm256_loadu_ps
6563 : #define or_ps _mm256_or_ps
6564 : #define min_ps _mm256_min_ps
6565 : #define max_ps _mm256_max_ps
6566 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6567 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6568 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6569 : #define movemask_ps _mm256_movemask_ps
6570 : #define storeu_ps _mm256_storeu_ps
6571 : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6572 : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6573 :
6574 : #define unpacklo_ps _mm256_unpacklo_ps
6575 : #define castps_pd _mm256_castps_pd
6576 :
6577 : inline __m256 dup_hi_ps(__m256 x)
6578 : {
6579 : const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6580 : return _mm256_permutevar8x32_ps(x, idx);
6581 : }
6582 :
6583 : #define setzero_pd _mm256_setzero_pd
6584 : #define set1_pd _mm256_set1_pd
6585 : #define loadu_pd _mm256_loadu_pd
6586 : #define or_pd _mm256_or_pd
6587 : #define min_pd _mm256_min_pd
6588 : #define max_pd _mm256_max_pd
6589 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6590 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6591 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6592 : #define movemask_pd _mm256_movemask_pd
6593 : #define add_pd _mm256_add_pd
6594 : #define sub_pd _mm256_sub_pd
6595 : #define mul_pd _mm256_mul_pd
6596 : #define div_pd _mm256_div_pd
6597 : #define storeu_pd _mm256_storeu_pd
6598 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6599 : #define blendv_pd _mm256_blendv_pd
6600 : #ifdef __FMA__
6601 : #define fmadd_pd _mm256_fmadd_pd
6602 : #else
6603 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6604 : #endif
6605 :
6606 : #else
6607 :
6608 : #define set1_ps _mm_set1_ps
6609 : #define loadu_ps _mm_loadu_ps
6610 : #define or_ps _mm_or_ps
6611 : #define min_ps _mm_min_ps
6612 : #define max_ps _mm_max_ps
6613 : #define cmpeq_ps _mm_cmpeq_ps
6614 : #define cmpneq_ps _mm_cmpneq_ps
6615 : #define cmpunord_ps _mm_cmpunord_ps
6616 : #define movemask_ps _mm_movemask_ps
6617 : #define storeu_ps _mm_storeu_ps
6618 : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6619 : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6620 : #define unpacklo_ps _mm_unpacklo_ps
6621 : #define castps_pd _mm_castps_pd
6622 : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6623 :
6624 : #define setzero_pd _mm_setzero_pd
6625 : #define set1_pd _mm_set1_pd
6626 : #define loadu_pd _mm_loadu_pd
6627 : #define or_pd _mm_or_pd
6628 : #define min_pd _mm_min_pd
6629 : #define max_pd _mm_max_pd
6630 : #define cmpeq_pd _mm_cmpeq_pd
6631 : #define cmpneq_pd _mm_cmpneq_pd
6632 : #define cmpunord_pd _mm_cmpunord_pd
6633 : #define movemask_pd _mm_movemask_pd
6634 : #define add_pd _mm_add_pd
6635 : #define sub_pd _mm_sub_pd
6636 : #define mul_pd _mm_mul_pd
6637 : #define div_pd _mm_div_pd
6638 : #define storeu_pd _mm_storeu_pd
6639 : #define cvtsd_f64 _mm_cvtsd_f64
6640 : #ifdef __FMA__
6641 : #define fmadd_pd _mm_fmadd_pd
6642 : #else
6643 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6644 : #endif
6645 :
6646 4299340 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6647 : {
6648 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6649 : return _mm_blendv_pd(a, b, mask);
6650 : #else
6651 12898000 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6652 : #endif
6653 : }
6654 : #endif
6655 :
6656 : #define dup_lo_ps(x) unpacklo_ps((x), (x))
6657 :
6658 : /************************************************************************/
6659 : /* ComputeStatisticsFloat32_SSE2() */
6660 : /************************************************************************/
6661 :
6662 : template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6663 : #if defined(__GNUC__)
6664 : __attribute__((noinline))
6665 : #endif
6666 8334 : static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
6667 : [[maybe_unused]] float fNoDataValue,
6668 : int iX, int nCount, float &fMin,
6669 : float &fMax, double &dfBlockMean,
6670 : double &dfBlockM2,
6671 : double &dfBlockValidCount)
6672 : {
6673 8334 : auto vValidCount = setzero_pd();
6674 8334 : const auto vOne = set1_pd(1);
6675 8334 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6676 :
6677 8334 : auto vMin = set1_ps(fMin);
6678 16668 : auto vMax = set1_ps(fMax);
6679 :
6680 8334 : auto vMean_lo = setzero_pd();
6681 8334 : auto vM2_lo = setzero_pd();
6682 :
6683 8334 : auto vMean_hi = setzero_pd();
6684 8334 : auto vM2_hi = setzero_pd();
6685 :
6686 8334 : constexpr int VALS_PER_LOOP =
6687 : static_cast<int>(sizeof(vOne) / sizeof(float));
6688 1258085 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6689 : {
6690 2499510 : const auto vValues = loadu_ps(pafData + iX);
6691 :
6692 : if constexpr (HAS_NAN)
6693 : {
6694 1236117 : auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6695 : if constexpr (HAS_NODATA)
6696 : {
6697 : isNaNOrNoData =
6698 0 : or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6699 : }
6700 1236117 : if (movemask_ps(isNaNOrNoData))
6701 : {
6702 1 : break;
6703 : }
6704 : }
6705 : else if constexpr (HAS_NODATA)
6706 : {
6707 0 : if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6708 : {
6709 0 : break;
6710 : }
6711 : }
6712 :
6713 1249754 : vMin = min_ps(vMin, vValues);
6714 1249754 : vMax = max_ps(vMax, vValues);
6715 :
6716 1249754 : const auto vValues_lo = cvtps_lo_pd(vValues);
6717 2499508 : const auto vValues_hi = cvtps_hi_pd(vValues);
6718 1249754 : [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6719 :
6720 1249754 : vValidCount = add_pd(vValidCount, vOne);
6721 1249754 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6722 :
6723 1249754 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6724 2298362 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6725 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6726 : {
6727 : const auto vMinNotSameAsMax_lo =
6728 1048608 : castps_pd(dup_lo_ps(vMinNotSameAsMax));
6729 1048608 : vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6730 : const auto vNewM2_lo =
6731 2097216 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6732 1048608 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6733 : }
6734 : else
6735 : {
6736 201146 : vMean_lo = vNewMean_lo;
6737 603438 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6738 : }
6739 :
6740 1249754 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6741 2298362 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6742 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6743 : {
6744 : const auto vMinNotSameAsMax_hi =
6745 1048608 : castps_pd(dup_hi_ps(vMinNotSameAsMax));
6746 1048608 : vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6747 : const auto vNewM2_hi =
6748 2097216 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6749 1048608 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6750 : }
6751 : else
6752 : {
6753 201146 : vMean_hi = vNewMean_hi;
6754 603438 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6755 : }
6756 : }
6757 8334 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6758 8334 : if (dfValidVectorCount > 0)
6759 : {
6760 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6761 : storeu_ps(afMin, vMin);
6762 : storeu_ps(afMax, vMax);
6763 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6764 : {
6765 31964 : fMin = std::min(fMin, afMin[i]);
6766 31964 : fMax = std::max(fMax, afMax[i]);
6767 : }
6768 :
6769 : double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6770 : storeu_pd(adfMean, vMean_lo);
6771 : storeu_pd(adfM2, vM2_lo);
6772 7991 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6773 7991 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6774 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6775 : {
6776 31964 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6777 31964 : dfBlockM2 += adfM2[i];
6778 31964 : if (adfMean[i] != dfBlockMean)
6779 : {
6780 13172 : const double dfDelta = adfMean[i] - dfBlockMean;
6781 13172 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6782 13172 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6783 13172 : dfValidVectorCount / dfNewValidCount;
6784 : }
6785 31964 : dfBlockValidCount = dfNewValidCount;
6786 : }
6787 : }
6788 :
6789 8334 : return iX;
6790 : }
6791 :
6792 : /************************************************************************/
6793 : /* ComputeStatisticsFloat64_SSE2() */
6794 : /************************************************************************/
6795 :
6796 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6797 : #if defined(__GNUC__)
6798 : __attribute__((noinline))
6799 : #endif
6800 2370 : static int ComputeStatisticsFloat64_SSE2(const double *padfData,
6801 : [[maybe_unused]] double dfNoDataValue,
6802 : int iX, int nCount, double &dfMin,
6803 : double &dfMax, double &dfBlockMean,
6804 : double &dfBlockM2,
6805 : double &dfBlockValidCount)
6806 : {
6807 2370 : auto vValidCount = setzero_pd();
6808 2370 : const auto vOne = set1_pd(1);
6809 2370 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6810 :
6811 2370 : auto vMin_lo = set1_pd(dfMin);
6812 4740 : auto vMax_lo = set1_pd(dfMax);
6813 2370 : auto vMean_lo = setzero_pd();
6814 2370 : auto vM2_lo = setzero_pd();
6815 :
6816 2370 : auto vMin_hi = vMin_lo;
6817 2370 : auto vMax_hi = vMax_lo;
6818 2370 : auto vMean_hi = setzero_pd();
6819 2370 : auto vM2_hi = setzero_pd();
6820 :
6821 2370 : constexpr int VALS_PER_LOOP =
6822 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6823 107202 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6824 : {
6825 104875 : const auto vValues_lo = loadu_pd(padfData + iX);
6826 209750 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6827 : // Check if there's at least one NaN in both vectors
6828 104875 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6829 : if constexpr (HAS_NODATA)
6830 : {
6831 : isNaNOrNoData =
6832 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6833 : cmpeq_pd(vValues_hi, vNoData)));
6834 : }
6835 104875 : if (movemask_pd(isNaNOrNoData))
6836 : {
6837 43 : break;
6838 : }
6839 :
6840 104832 : vValidCount = add_pd(vValidCount, vOne);
6841 104832 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6842 :
6843 104832 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6844 104832 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6845 104832 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6846 131060 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6847 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6848 : {
6849 26228 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6850 26228 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6851 : const auto vNewM2_lo =
6852 52456 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6853 26228 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6854 : }
6855 : else
6856 : {
6857 78604 : vMean_lo = vNewMean_lo;
6858 235812 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6859 : }
6860 :
6861 104832 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6862 104832 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6863 104832 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6864 131060 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6865 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6866 : {
6867 26228 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6868 26228 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6869 : const auto vNewM2_hi =
6870 52456 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6871 26228 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6872 : }
6873 : else
6874 : {
6875 78604 : vMean_hi = vNewMean_hi;
6876 235812 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6877 : }
6878 : }
6879 2370 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6880 2370 : if (dfValidVectorCount > 0)
6881 : {
6882 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6883 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6884 : storeu_pd(adfMin, vMin_lo);
6885 : storeu_pd(adfMax, vMax_lo);
6886 : storeu_pd(adfMean, vMean_lo);
6887 : storeu_pd(adfM2, vM2_lo);
6888 1801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6889 1801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6890 1801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6891 1801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6892 :
6893 9005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6894 : {
6895 7204 : dfMin = std::min(dfMin, adfMin[i]);
6896 7204 : dfMax = std::max(dfMax, adfMax[i]);
6897 7204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6898 7204 : dfBlockM2 += adfM2[i];
6899 7204 : if (adfMean[i] != dfBlockMean)
6900 : {
6901 5871 : const double dfDelta = adfMean[i] - dfBlockMean;
6902 5871 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6903 5871 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6904 5871 : dfValidVectorCount / dfNewValidCount;
6905 : }
6906 7204 : dfBlockValidCount = dfNewValidCount;
6907 : }
6908 : }
6909 :
6910 2370 : return iX;
6911 : }
6912 :
6913 : #endif
6914 :
6915 : /************************************************************************/
6916 : /* ComputeBlockStatisticsFloat32() */
6917 : /************************************************************************/
6918 :
6919 : template <bool HAS_NAN, bool HAS_NODATA>
6920 4737 : static void ComputeBlockStatisticsFloat32(
6921 : const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6922 : const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6923 : float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6924 : double &dfBlockValidCountInOut)
6925 : {
6926 4737 : float fMin = fMinInOut;
6927 4737 : float fMax = fMaxInOut;
6928 4737 : double dfBlockMean = dfBlockMeanInOut;
6929 4737 : double dfBlockM2 = dfBlockM2InOut;
6930 4737 : double dfBlockValidCount = dfBlockValidCountInOut;
6931 :
6932 13071 : for (int iY = 0; iY < nYCheck; iY++)
6933 : {
6934 8334 : const int iOffset = iY * nBlockXSize;
6935 8334 : if (dfBlockValidCount > 0 && fMin != fMax)
6936 : {
6937 3470 : int iX = 0;
6938 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6939 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6940 : /* bCheckMinEqMax = */ false,
6941 3470 : HAS_NODATA>(
6942 3470 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6943 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6944 : #endif
6945 4011 : for (; iX < nXCheck; iX++)
6946 : {
6947 541 : const float fValue = pafSrcData[iOffset + iX];
6948 : if constexpr (HAS_NAN)
6949 : {
6950 535 : if (std::isnan(fValue))
6951 13 : continue;
6952 : }
6953 : if constexpr (HAS_NODATA)
6954 : {
6955 6 : if (fValue == sNoDataValues.fNoDataValue)
6956 1 : continue;
6957 : }
6958 527 : fMin = std::min(fMin, fValue);
6959 527 : fMax = std::max(fMax, fValue);
6960 527 : dfBlockValidCount += 1.0;
6961 527 : const double dfValue = static_cast<double>(fValue);
6962 527 : const double dfDelta = dfValue - dfBlockMean;
6963 527 : dfBlockMean += dfDelta / dfBlockValidCount;
6964 527 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6965 3470 : }
6966 : }
6967 : else
6968 : {
6969 4864 : int iX = 0;
6970 4864 : if (dfBlockValidCount == 0)
6971 : {
6972 4738 : while (iX < nXCheck)
6973 : {
6974 4738 : const float fValue = pafSrcData[iOffset + iX];
6975 4738 : ++iX;
6976 : if constexpr (HAS_NAN)
6977 : {
6978 2346 : if (std::isnan(fValue))
6979 0 : continue;
6980 : }
6981 : if constexpr (HAS_NODATA)
6982 : {
6983 7 : if (fValue == sNoDataValues.fNoDataValue)
6984 1 : continue;
6985 : }
6986 4737 : fMin = std::min(fMin, fValue);
6987 4737 : fMax = std::max(fMax, fValue);
6988 4737 : dfBlockValidCount = 1;
6989 4737 : dfBlockMean = static_cast<double>(fValue);
6990 4737 : break;
6991 : }
6992 : }
6993 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6994 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6995 : /* bCheckMinEqMax = */ true,
6996 4864 : HAS_NODATA>(
6997 4864 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6998 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6999 : #endif
7000 14994 : for (; iX < nXCheck; iX++)
7001 : {
7002 10130 : const float fValue = pafSrcData[iOffset + iX];
7003 : if constexpr (HAS_NAN)
7004 : {
7005 6873 : if (std::isnan(fValue))
7006 5 : continue;
7007 : }
7008 : if constexpr (HAS_NODATA)
7009 : {
7010 9 : if (fValue == sNoDataValues.fNoDataValue)
7011 2 : continue;
7012 : }
7013 10123 : fMin = std::min(fMin, fValue);
7014 10123 : fMax = std::max(fMax, fValue);
7015 10123 : dfBlockValidCount += 1.0;
7016 10123 : if (fMin != fMax)
7017 : {
7018 3258 : const double dfValue = static_cast<double>(fValue);
7019 3258 : const double dfDelta = dfValue - dfBlockMean;
7020 3258 : dfBlockMean += dfDelta / dfBlockValidCount;
7021 3258 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7022 : }
7023 : }
7024 : }
7025 : }
7026 :
7027 4737 : fMinInOut = fMin;
7028 4737 : fMaxInOut = fMax;
7029 4737 : dfBlockMeanInOut = dfBlockMean;
7030 4737 : dfBlockM2InOut = dfBlockM2;
7031 4737 : dfBlockValidCountInOut = dfBlockValidCount;
7032 4737 : }
7033 :
7034 : /************************************************************************/
7035 : /* StatisticsTaskFloat32 */
7036 : /************************************************************************/
7037 :
7038 : namespace
7039 : {
7040 : struct StatisticsTaskFloat32
7041 : {
7042 : double dfBlockMean = 0;
7043 : double dfBlockM2 = 0;
7044 : double dfBlockValidCount = 0;
7045 : GDALDataType eDataType = GDT_Unknown;
7046 : bool bHasNoData = false;
7047 : GDALNoDataValues *psNoDataValues = nullptr;
7048 : const float *pafSrcData = nullptr;
7049 : float fMin = std::numeric_limits<float>::infinity();
7050 : float fMax = -std::numeric_limits<float>::infinity();
7051 : int nChunkXSize = 0;
7052 : int nXCheck = 0;
7053 : int nYCheck = 0;
7054 :
7055 4737 : void Perform()
7056 : {
7057 4737 : if (GDALDataTypeIsInteger(eDataType))
7058 : {
7059 2391 : if (bHasNoData)
7060 : {
7061 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7062 6 : /* HAS_NODATA = */ true>(
7063 6 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7064 6 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7065 : }
7066 : else
7067 : {
7068 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7069 2385 : /* HAS_NODATA = */ false>(
7070 2385 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7071 2385 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7072 : }
7073 : }
7074 : else
7075 : {
7076 2346 : if (bHasNoData)
7077 : {
7078 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7079 0 : /* HAS_NODATA = */ true>(
7080 0 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7081 0 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7082 : }
7083 : else
7084 : {
7085 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7086 2346 : /* HAS_NODATA = */ false>(
7087 2346 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7088 2346 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7089 : }
7090 : }
7091 4737 : }
7092 : };
7093 : } // namespace
7094 :
7095 : /************************************************************************/
7096 : /* ComputeStatistics() */
7097 : /************************************************************************/
7098 :
7099 : /**
7100 : * \brief Compute image statistics.
7101 : *
7102 : * Returns the minimum, maximum, mean and standard deviation of all
7103 : * pixel values in this band. If approximate statistics are sufficient,
7104 : * the bApproxOK flag can be set to true in which case overviews, or a
7105 : * subset of image tiles may be used in computing the statistics.
7106 : *
7107 : * Once computed, the statistics will generally be "set" back on the
7108 : * raster band using SetStatistics().
7109 : *
7110 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7111 : *
7112 : * This method is the same as the C functions GDALComputeRasterStatistics()
7113 : * and GDALComputeRasterStatisticsEx().
7114 : *
7115 : * @param bApproxOK If TRUE statistics may be computed based on overviews
7116 : * or a subset of all tiles.
7117 : *
7118 : * @param pdfMin Location into which to load image minimum (may be NULL).
7119 : *
7120 : * @param pdfMax Location into which to load image maximum (may be NULL).-
7121 : *
7122 : * @param pdfMean Location into which to load image mean (may be NULL).
7123 : *
7124 : * @param pdfStdDev Location into which to load image standard deviation
7125 : * (may be NULL).
7126 : *
7127 : * @param pfnProgress a function to call to report progress, or NULL.
7128 : *
7129 : * @param pProgressData application data to pass to the progress function.
7130 : *
7131 : * @param papszOptions (added in 3.14) NULL, or NULL terminated list of options.
7132 : * Currently supported option is SET_STATISTICS=FALSE to
7133 : * avoid setting statistics in metadata items.
7134 : *
7135 : * @return CE_None on success, or CE_Failure if an error occurs or processing
7136 : * is terminated by the user.
7137 : */
7138 :
7139 595 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7140 : double *pdfMax, double *pdfMean,
7141 : double *pdfStdDev,
7142 : GDALProgressFunc pfnProgress,
7143 : void *pProgressData,
7144 : CSLConstList papszOptions)
7145 :
7146 : {
7147 595 : if (pfnProgress == nullptr)
7148 256 : pfnProgress = GDALDummyProgress;
7149 :
7150 : const bool bSetStatistics =
7151 595 : CPLFetchBool(papszOptions, "SET_STATISTICS", true);
7152 :
7153 : /* -------------------------------------------------------------------- */
7154 : /* If we have overview bands, use them for statistics. */
7155 : /* -------------------------------------------------------------------- */
7156 595 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7157 : {
7158 : GDALRasterBand *poBand =
7159 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7160 :
7161 3 : if (poBand != this)
7162 : {
7163 6 : CPLErr eErr = poBand->ComputeStatistics(
7164 : FALSE, pdfMin, pdfMax, pdfMean, pdfStdDev, pfnProgress,
7165 3 : pProgressData, papszOptions);
7166 3 : if (eErr == CE_None && bSetStatistics)
7167 : {
7168 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7169 : {
7170 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7171 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7172 : }
7173 :
7174 : /* transfer metadata from overview band to this */
7175 : const char *pszPercentValid =
7176 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7177 :
7178 3 : if (pszPercentValid != nullptr)
7179 : {
7180 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
7181 3 : pszPercentValid);
7182 : }
7183 : }
7184 3 : return eErr;
7185 : }
7186 : }
7187 :
7188 592 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7189 : {
7190 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7191 0 : return CE_Failure;
7192 : }
7193 :
7194 : /* -------------------------------------------------------------------- */
7195 : /* Read actual data and compute statistics. */
7196 : /* -------------------------------------------------------------------- */
7197 : // Using Welford algorithm:
7198 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7199 : // to compute standard deviation in a more numerically robust way than
7200 : // the difference of the sum of square values with the square of the sum.
7201 : // dfMean and dfM2 are updated at each sample.
7202 : // dfM2 is the sum of square of differences to the current mean.
7203 592 : double dfMin = std::numeric_limits<double>::infinity();
7204 592 : double dfMax = -std::numeric_limits<double>::infinity();
7205 592 : double dfMean = 0.0;
7206 592 : double dfM2 = 0.0;
7207 :
7208 : GDALRasterIOExtraArg sExtraArg;
7209 592 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7210 :
7211 592 : GDALNoDataValues sNoDataValues(this, eDataType);
7212 592 : GDALRasterBand *poMaskBand = nullptr;
7213 592 : if (!sNoDataValues.bGotNoDataValue)
7214 : {
7215 518 : const int l_nMaskFlags = GetMaskFlags();
7216 576 : if (l_nMaskFlags != GMF_ALL_VALID &&
7217 58 : GetColorInterpretation() != GCI_AlphaBand)
7218 : {
7219 58 : poMaskBand = GetMaskBand();
7220 : }
7221 : }
7222 :
7223 592 : bool bSignedByte = false;
7224 592 : if (eDataType == GDT_UInt8)
7225 : {
7226 227 : EnablePixelTypeSignedByteWarning(false);
7227 : const char *pszPixelType =
7228 227 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
7229 227 : EnablePixelTypeSignedByteWarning(true);
7230 227 : bSignedByte =
7231 227 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7232 : }
7233 :
7234 592 : GUIntBig nSampleCount = 0;
7235 592 : GUIntBig nValidCount = 0;
7236 :
7237 592 : if (bApproxOK && HasArbitraryOverviews())
7238 : {
7239 : /* --------------------------------------------------------------------
7240 : */
7241 : /* Figure out how much the image should be reduced to get an */
7242 : /* approximate value. */
7243 : /* --------------------------------------------------------------------
7244 : */
7245 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7246 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7247 :
7248 0 : int nXReduced = nRasterXSize;
7249 0 : int nYReduced = nRasterYSize;
7250 0 : if (dfReduction > 1.0)
7251 : {
7252 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7253 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7254 :
7255 : // Catch the case of huge resizing ratios here
7256 0 : if (nXReduced == 0)
7257 0 : nXReduced = 1;
7258 0 : if (nYReduced == 0)
7259 0 : nYReduced = 1;
7260 : }
7261 :
7262 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7263 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7264 :
7265 : const CPLErr eErr =
7266 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7267 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7268 0 : if (eErr != CE_None)
7269 : {
7270 0 : CPLFree(pData);
7271 0 : return eErr;
7272 : }
7273 :
7274 0 : GByte *pabyMaskData = nullptr;
7275 0 : if (poMaskBand)
7276 : {
7277 : pabyMaskData =
7278 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7279 0 : if (!pabyMaskData)
7280 : {
7281 0 : CPLFree(pData);
7282 0 : return CE_Failure;
7283 : }
7284 :
7285 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7286 : pabyMaskData, nXReduced, nYReduced,
7287 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
7288 : {
7289 0 : CPLFree(pData);
7290 0 : CPLFree(pabyMaskData);
7291 0 : return CE_Failure;
7292 : }
7293 : }
7294 :
7295 : /* this isn't the fastest way to do this, but is easier for now */
7296 0 : for (int iY = 0; iY < nYReduced; iY++)
7297 : {
7298 0 : for (int iX = 0; iX < nXReduced; iX++)
7299 : {
7300 0 : const int iOffset = iX + iY * nXReduced;
7301 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7302 0 : continue;
7303 :
7304 0 : bool bValid = true;
7305 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7306 0 : iOffset, sNoDataValues, bValid);
7307 0 : if (!bValid)
7308 0 : continue;
7309 :
7310 0 : dfMin = std::min(dfMin, dfValue);
7311 0 : dfMax = std::max(dfMax, dfValue);
7312 :
7313 0 : nValidCount++;
7314 0 : if (dfMin == dfMax)
7315 : {
7316 0 : if (nValidCount == 1)
7317 0 : dfMean = dfMin;
7318 : }
7319 : else
7320 : {
7321 0 : const double dfDelta = dfValue - dfMean;
7322 0 : dfMean += dfDelta / nValidCount;
7323 0 : dfM2 += dfDelta * (dfValue - dfMean);
7324 : }
7325 : }
7326 : }
7327 :
7328 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7329 :
7330 0 : CPLFree(pData);
7331 0 : CPLFree(pabyMaskData);
7332 : }
7333 :
7334 : else // No arbitrary overviews.
7335 : {
7336 592 : if (!InitBlockInfo())
7337 265 : return CE_Failure;
7338 :
7339 : /* --------------------------------------------------------------------
7340 : */
7341 : /* Figure out the ratio of blocks we will read to get an */
7342 : /* approximate value. */
7343 : /* --------------------------------------------------------------------
7344 : */
7345 592 : int nSampleRate = 1;
7346 592 : if (bApproxOK)
7347 : {
7348 44 : nSampleRate = static_cast<int>(std::max(
7349 88 : 1.0,
7350 44 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7351 : // We want to avoid probing only the first column of blocks for
7352 : // a square shaped raster, because it is not unlikely that it may
7353 : // be padding only (#6378)
7354 44 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7355 1 : nSampleRate += 1;
7356 : }
7357 592 : if (nSampleRate == 1)
7358 558 : bApproxOK = false;
7359 :
7360 : // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7361 : // for each block, and possibly for the whole raster.
7362 592 : if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7363 324 : eDataType == GDT_UInt16))
7364 : {
7365 : // We can do integer computation on the whole raster in the Byte case
7366 : // only if the number of pixels explored is lower than
7367 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7368 : // Should be 99.99999% of cases.
7369 : // For GUInt16, this limits to raster of 4 giga pixels
7370 :
7371 : const bool bIntegerStats =
7372 475 : ((eDataType == GDT_UInt8 &&
7373 210 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7374 210 : nSampleRate <
7375 210 : GUINTBIG_MAX / (255U * 255U) /
7376 210 : (static_cast<GUInt64>(nBlockXSize) *
7377 210 : static_cast<GUInt64>(nBlockYSize))) ||
7378 55 : (eDataType == GDT_UInt16 &&
7379 55 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7380 55 : nSampleRate <
7381 55 : GUINTBIG_MAX / (65535U * 65535U) /
7382 55 : (static_cast<GUInt64>(nBlockXSize) *
7383 585 : static_cast<GUInt64>(nBlockYSize)))) &&
7384 : // Can be set to NO for easier debugging of the !bIntegerStats
7385 : // case which requires huge rasters to trigger
7386 265 : CPLTestBool(
7387 265 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7388 :
7389 265 : const GUInt32 nMaxValueType =
7390 265 : (eDataType == GDT_UInt8) ? 255 : 65535;
7391 265 : GUInt32 nMin = nMaxValueType;
7392 265 : GUInt32 nMax = 0;
7393 265 : GUIntBig nSum = 0;
7394 265 : GUIntBig nSumSquare = 0;
7395 : // If no valid nodata, map to invalid value (256 for Byte)
7396 265 : const GUInt32 nNoDataValue =
7397 302 : (sNoDataValues.bGotNoDataValue &&
7398 37 : sNoDataValues.dfNoDataValue >= 0 &&
7399 37 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7400 37 : fabs(sNoDataValues.dfNoDataValue -
7401 37 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7402 : 1e-10)) < 1e-10)
7403 302 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7404 : : nMaxValueType + 1;
7405 :
7406 265 : int nChunkXSize = nBlockXSize;
7407 265 : int nChunkYSize = nBlockYSize;
7408 265 : int nChunksPerRow = nBlocksPerRow;
7409 265 : int nChunksPerCol = nBlocksPerColumn;
7410 :
7411 265 : int nThreads = 1;
7412 265 : if (nChunkYSize > 1)
7413 : {
7414 118 : nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7415 : /* bDefaultToAllCPUs = */ false);
7416 : }
7417 :
7418 265 : int nNewChunkXSize = nChunkXSize;
7419 265 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
7420 273 : if (!bApproxOK && nThreads > 1 &&
7421 8 : MayMultiBlockReadingBeMultiThreaded())
7422 : {
7423 4 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7424 4 : const size_t nChunkPixels =
7425 4 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7426 8 : if (nRAMAmount > 0 &&
7427 : nChunkPixels <=
7428 4 : std::numeric_limits<size_t>::max() / nDTSize)
7429 : {
7430 4 : const size_t nBlockSize = nDTSize * nChunkPixels;
7431 4 : const int64_t nBlockCount = nRAMAmount / nBlockSize;
7432 4 : if (nBlockCount >= 2)
7433 : {
7434 4 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7435 12 : nChunkXSize * std::min<int64_t>(
7436 : nBlockCount,
7437 8 : (std::numeric_limits<int>::max() -
7438 8 : ALIGNMENT_AVX2_OPTIM) /
7439 4 : nChunkPixels),
7440 8 : nRasterXSize));
7441 :
7442 4 : CPLAssert(nChunkXSize <
7443 : std::numeric_limits<int>::max() /
7444 : nChunkYSize);
7445 : }
7446 : }
7447 : }
7448 :
7449 265 : std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
7450 265 : GByte *pabyTemp = nullptr;
7451 265 : if (nNewChunkXSize != nBlockXSize)
7452 : {
7453 4 : pabyTempUnaligned.reset(static_cast<GByte *>(
7454 4 : VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
7455 : ALIGNMENT_AVX2_OPTIM)));
7456 4 : if (pabyTempUnaligned)
7457 : {
7458 4 : pabyTemp = reinterpret_cast<GByte *>(
7459 4 : reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
7460 : (ALIGNMENT_AVX2_OPTIM -
7461 4 : (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
7462 : ALIGNMENT_AVX2_OPTIM)));
7463 4 : nChunkXSize = nNewChunkXSize;
7464 : nChunksPerRow =
7465 4 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7466 : }
7467 : }
7468 :
7469 265 : for (GIntBig iSampleBlock = 0;
7470 13176 : iSampleBlock <
7471 13176 : static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7472 12911 : iSampleBlock += nSampleRate)
7473 : {
7474 12915 : const int iYBlock =
7475 12915 : static_cast<int>(iSampleBlock / nChunksPerRow);
7476 12915 : const int iXBlock =
7477 12915 : static_cast<int>(iSampleBlock % nChunksPerRow);
7478 :
7479 : const int nXCheck =
7480 12915 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7481 : const int nYCheck =
7482 12915 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7483 :
7484 12915 : GDALRasterBlock *poBlock = nullptr;
7485 12915 : if (pabyTemp)
7486 : {
7487 12 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7488 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7489 : pabyTemp, nXCheck, nYCheck, eDataType, 0,
7490 6 : static_cast<GSpacing>(nChunkXSize) * nDTSize,
7491 6 : nullptr) != CE_None)
7492 : {
7493 4 : return CE_Failure;
7494 : }
7495 : }
7496 : else
7497 : {
7498 12909 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7499 12909 : if (poBlock == nullptr)
7500 : {
7501 2 : return CE_Failure;
7502 : }
7503 : }
7504 :
7505 : const void *const pData =
7506 12911 : poBlock ? poBlock->GetDataRef() : pabyTemp;
7507 :
7508 12911 : GUIntBig nBlockSum = 0;
7509 12911 : GUIntBig nBlockSumSquare = 0;
7510 12911 : GUIntBig nBlockSampleCount = 0;
7511 12911 : GUIntBig nBlockValidCount = 0;
7512 12911 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7513 12911 : GUIntBig &nBlockSumSquareRef =
7514 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7515 12911 : GUIntBig &nBlockSampleCountRef =
7516 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7517 12911 : GUIntBig &nBlockValidCountRef =
7518 : bIntegerStats ? nValidCount : nBlockValidCount;
7519 :
7520 12911 : if (eDataType == GDT_UInt8)
7521 : {
7522 : ComputeStatisticsInternal<
7523 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7524 12215 : f(nXCheck, nChunkXSize, nYCheck,
7525 : static_cast<const GByte *>(pData),
7526 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7527 : nMax, nBlockSumRef, nBlockSumSquareRef,
7528 : nBlockSampleCountRef, nBlockValidCountRef);
7529 : }
7530 : else
7531 : {
7532 : ComputeStatisticsInternal<
7533 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7534 696 : f(nXCheck, nChunkXSize, nYCheck,
7535 : static_cast<const GUInt16 *>(pData),
7536 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7537 : nMax, nBlockSumRef, nBlockSumSquareRef,
7538 : nBlockSampleCountRef, nBlockValidCountRef);
7539 : }
7540 :
7541 12911 : if (poBlock)
7542 12907 : poBlock->DropLock();
7543 :
7544 12911 : if (!bIntegerStats)
7545 : {
7546 169 : nSampleCount += nBlockSampleCount;
7547 169 : if (nBlockValidCount)
7548 : {
7549 : // Update the global mean and M2 (the difference of the
7550 : // square to the mean) from the values of the block
7551 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7552 169 : const double dfBlockValidCount =
7553 169 : static_cast<double>(nBlockValidCount);
7554 169 : const double dfBlockMean =
7555 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7556 : const double dfBlockM2 =
7557 169 : static_cast<double>(
7558 169 : GDALUInt128::Mul(nBlockSumSquare,
7559 169 : nBlockValidCount) -
7560 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7561 169 : dfBlockValidCount;
7562 169 : const double dfDelta = dfBlockMean - dfMean;
7563 169 : const auto nNewValidCount =
7564 169 : nValidCount + nBlockValidCount;
7565 169 : const double dfNewValidCount =
7566 : static_cast<double>(nNewValidCount);
7567 169 : dfMean +=
7568 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7569 169 : dfM2 +=
7570 169 : dfBlockM2 + dfDelta * dfDelta *
7571 169 : static_cast<double>(nValidCount) *
7572 169 : dfBlockValidCount / dfNewValidCount;
7573 169 : nValidCount = nNewValidCount;
7574 : }
7575 : }
7576 :
7577 12911 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7578 12911 : (static_cast<double>(nChunksPerRow) *
7579 : nChunksPerCol),
7580 : "Compute Statistics", pProgressData))
7581 : {
7582 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7583 : "User terminated");
7584 0 : return CE_Failure;
7585 : }
7586 : }
7587 :
7588 261 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7589 : {
7590 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7591 0 : return CE_Failure;
7592 : }
7593 :
7594 261 : double dfStdDev = 0;
7595 261 : if (bIntegerStats)
7596 : {
7597 237 : if (nValidCount)
7598 226 : dfMean = static_cast<double>(nSum) / nValidCount;
7599 :
7600 : // To avoid potential precision issues when doing the difference,
7601 : // we need to do that computation on 128 bit rather than casting
7602 : // to double
7603 : const GDALUInt128 nTmpForStdDev(
7604 237 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7605 474 : GDALUInt128::Mul(nSum, nSum));
7606 237 : dfStdDev =
7607 237 : nValidCount > 0
7608 237 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7609 : : 0.0;
7610 : }
7611 24 : else if (nValidCount > 0)
7612 : {
7613 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7614 : }
7615 :
7616 : /// Save computed information
7617 261 : if (bSetStatistics)
7618 : {
7619 260 : if (nValidCount > 0)
7620 : {
7621 249 : if (bApproxOK)
7622 : {
7623 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7624 : }
7625 225 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7626 : {
7627 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7628 : }
7629 249 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7630 : }
7631 :
7632 260 : SetValidPercent(nSampleCount, nValidCount);
7633 : }
7634 :
7635 : /* --------------------------------------------------------------------
7636 : */
7637 : /* Record results. */
7638 : /* --------------------------------------------------------------------
7639 : */
7640 261 : if (pdfMin != nullptr)
7641 258 : *pdfMin = nValidCount ? nMin : 0;
7642 261 : if (pdfMax != nullptr)
7643 258 : *pdfMax = nValidCount ? nMax : 0;
7644 :
7645 261 : if (pdfMean != nullptr)
7646 254 : *pdfMean = dfMean;
7647 :
7648 261 : if (pdfStdDev != nullptr)
7649 254 : *pdfStdDev = dfStdDev;
7650 :
7651 261 : if (nValidCount > 0)
7652 250 : return CE_None;
7653 :
7654 11 : ReportError(CE_Failure, CPLE_AppDefined,
7655 : "Failed to compute statistics, no valid pixels found "
7656 : "in sampling.");
7657 11 : return CE_Failure;
7658 : }
7659 :
7660 327 : GByte *pabyMaskData = nullptr;
7661 327 : if (poMaskBand)
7662 : {
7663 : pabyMaskData = static_cast<GByte *>(
7664 58 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7665 58 : if (!pabyMaskData)
7666 : {
7667 0 : return CE_Failure;
7668 : }
7669 : }
7670 :
7671 327 : float fMin = std::numeric_limits<float>::infinity();
7672 327 : float fMax = -std::numeric_limits<float>::infinity();
7673 : bool bFloat32Optim =
7674 141 : (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7675 327 : eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7676 213 : !pabyMaskData &&
7677 867 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7678 213 : CPLTestBool(
7679 327 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7680 0 : std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7681 :
7682 327 : int nChunkXSize = nBlockXSize;
7683 327 : int nChunkYSize = nBlockYSize;
7684 327 : int nChunksPerRow = nBlocksPerRow;
7685 327 : int nChunksPerCol = nBlocksPerColumn;
7686 :
7687 : #define nBlockXSize use_nChunkXSize_instead
7688 : #define nBlockYSize use_nChunkYSize_instead
7689 : #define nBlocksPerRow use_nChunksPerRow_instead
7690 : #define nBlocksPerColumn use_nChunksPerCol_instead
7691 :
7692 327 : int nThreads = 1;
7693 327 : CPLWorkerThreadPool *psThreadPool = nullptr;
7694 327 : if (bFloat32Optim)
7695 : {
7696 211 : if (nChunkYSize > 1)
7697 : {
7698 15 : nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7699 : /* bDefaultToAllCPUs = */ false);
7700 : }
7701 :
7702 211 : int nNewChunkXSize = nChunkXSize;
7703 215 : if (!bApproxOK && nThreads > 1 &&
7704 4 : MayMultiBlockReadingBeMultiThreaded())
7705 : {
7706 0 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7707 0 : const size_t nChunkPixels =
7708 0 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7709 0 : if (nRAMAmount > 0 &&
7710 : nChunkPixels <=
7711 0 : std::numeric_limits<size_t>::max() / sizeof(float))
7712 : {
7713 0 : const size_t nBlockSizeAsFloat32 =
7714 : sizeof(float) * nChunkPixels;
7715 0 : const int64_t nBlockCount =
7716 0 : nRAMAmount / nBlockSizeAsFloat32;
7717 0 : if (nBlockCount >= 2)
7718 : {
7719 0 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7720 0 : nChunkXSize * std::min<int64_t>(
7721 : nBlockCount,
7722 0 : std::numeric_limits<int>::max() /
7723 0 : nChunkPixels),
7724 0 : nRasterXSize));
7725 :
7726 0 : CPLAssert(nChunkXSize <
7727 : std::numeric_limits<int>::max() /
7728 : nChunkYSize);
7729 : }
7730 : }
7731 : }
7732 211 : if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7733 : {
7734 187 : pafTemp.reset(static_cast<float *>(
7735 187 : VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7736 187 : bFloat32Optim = pafTemp != nullptr;
7737 187 : if (bFloat32Optim)
7738 : {
7739 187 : nChunkXSize = nNewChunkXSize;
7740 : nChunksPerRow =
7741 187 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7742 : }
7743 : }
7744 211 : CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7745 : nChunkXSize, nChunkYSize);
7746 : }
7747 :
7748 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7749 : const bool bFloat64Optim =
7750 26 : eDataType == GDT_Float64 && !pabyMaskData &&
7751 379 : nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7752 26 : CPLTestBool(
7753 327 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7754 : #endif
7755 :
7756 327 : std::vector<StatisticsTaskFloat32> tasksFloat32;
7757 :
7758 327 : for (GIntBig iSampleBlock = 0;
7759 6055 : iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7760 5728 : iSampleBlock += nSampleRate)
7761 : {
7762 5728 : const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7763 5728 : const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7764 :
7765 : const int nXCheck =
7766 5728 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7767 : const int nYCheck =
7768 5728 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7769 :
7770 6313 : if (poMaskBand &&
7771 585 : poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7772 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7773 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7774 : 0, nChunkXSize, nullptr) != CE_None)
7775 : {
7776 0 : CPLFree(pabyMaskData);
7777 0 : return CE_Failure;
7778 : }
7779 :
7780 5728 : GDALRasterBlock *poBlock = nullptr;
7781 5728 : if (pafTemp)
7782 : {
7783 2393 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7784 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7785 2393 : pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7786 2393 : static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7787 2393 : nullptr) != CE_None)
7788 : {
7789 0 : CPLFree(pabyMaskData);
7790 0 : return CE_Failure;
7791 : }
7792 : }
7793 : else
7794 : {
7795 3335 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7796 3335 : if (poBlock == nullptr)
7797 : {
7798 0 : CPLFree(pabyMaskData);
7799 0 : return CE_Failure;
7800 : }
7801 : }
7802 :
7803 : const void *const pData =
7804 5728 : poBlock ? poBlock->GetDataRef() : pafTemp.get();
7805 :
7806 5728 : if (bFloat32Optim)
7807 : {
7808 4737 : const float *const pafSrcData =
7809 : static_cast<const float *>(pData);
7810 :
7811 4743 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7812 6 : !std::isnan(sNoDataValues.fNoDataValue);
7813 4737 : const int nTasks = std::min(nYCheck, nThreads);
7814 4737 : const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7815 4737 : tasksFloat32.clear();
7816 9478 : for (int i = 0; i < nTasks; ++i)
7817 : {
7818 4741 : StatisticsTaskFloat32 task;
7819 4741 : task.eDataType = eDataType;
7820 4741 : task.bHasNoData = bHasNoData;
7821 4741 : task.psNoDataValues = &sNoDataValues;
7822 4741 : task.nChunkXSize = nChunkXSize;
7823 4741 : task.fMin = fMin;
7824 4741 : task.fMax = fMax;
7825 4741 : task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7826 4741 : nRowsPerTask *
7827 4741 : nChunkXSize;
7828 4741 : task.nXCheck = nXCheck;
7829 4741 : task.nYCheck =
7830 4741 : std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7831 4741 : tasksFloat32.emplace_back(std::move(task));
7832 : }
7833 4737 : if (psThreadPool)
7834 : {
7835 0 : auto poJobQueue = psThreadPool->CreateJobQueue();
7836 0 : for (auto &task : tasksFloat32)
7837 : {
7838 0 : poJobQueue->SubmitJob([&task]() { task.Perform(); });
7839 : }
7840 0 : poJobQueue->WaitCompletion();
7841 : }
7842 : else
7843 : {
7844 4737 : tasksFloat32[0].Perform();
7845 : }
7846 :
7847 9478 : for (const auto &task : tasksFloat32)
7848 : {
7849 4741 : if (task.dfBlockValidCount > 0)
7850 : {
7851 4737 : fMin = std::min(fMin, task.fMin);
7852 4737 : fMax = std::max(fMax, task.fMax);
7853 :
7854 : // Update the global mean and M2 (the difference of the
7855 : // square to the mean) from the values of the block
7856 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7857 4737 : const auto nNewValidCount =
7858 4737 : nValidCount +
7859 4737 : static_cast<int>(task.dfBlockValidCount);
7860 4737 : dfM2 += task.dfBlockM2;
7861 4737 : if (task.dfBlockMean != dfMean)
7862 : {
7863 1173 : if (nValidCount == 0)
7864 : {
7865 52 : dfMean = task.dfBlockMean;
7866 : }
7867 : else
7868 : {
7869 1121 : const double dfDelta =
7870 1121 : task.dfBlockMean - dfMean;
7871 1121 : const double dfNewValidCount =
7872 : static_cast<double>(nNewValidCount);
7873 1121 : dfMean += dfDelta * (task.dfBlockValidCount /
7874 : dfNewValidCount);
7875 1121 : dfM2 += dfDelta * dfDelta *
7876 1121 : static_cast<double>(nValidCount) *
7877 1121 : task.dfBlockValidCount /
7878 : dfNewValidCount;
7879 : }
7880 : }
7881 4737 : nValidCount = nNewValidCount;
7882 : }
7883 : }
7884 : }
7885 :
7886 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7887 991 : else if (bFloat64Optim)
7888 : {
7889 : const bool bHasNoData =
7890 566 : sNoDataValues.bGotNoDataValue &&
7891 269 : !std::isnan(sNoDataValues.dfNoDataValue);
7892 297 : double dfBlockMean = 0;
7893 297 : double dfBlockM2 = 0;
7894 297 : double dfBlockValidCount = 0;
7895 2667 : for (int iY = 0; iY < nYCheck; iY++)
7896 : {
7897 2370 : const int iOffset = iY * nChunkXSize;
7898 2370 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7899 : {
7900 1817 : int iX = 0;
7901 1817 : if (bHasNoData)
7902 : {
7903 : iX = ComputeStatisticsFloat64_SSE2<
7904 : /* bCheckMinEqMax = */ false,
7905 387 : /* bHasNoData = */ true>(
7906 387 : static_cast<const double *>(pData) + iOffset,
7907 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7908 : dfMax, dfBlockMean, dfBlockM2,
7909 : dfBlockValidCount);
7910 : }
7911 : else
7912 : {
7913 : iX = ComputeStatisticsFloat64_SSE2<
7914 : /* bCheckMinEqMax = */ false,
7915 1430 : /* bHasNoData = */ false>(
7916 1430 : static_cast<const double *>(pData) + iOffset,
7917 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7918 : dfMax, dfBlockMean, dfBlockM2,
7919 : dfBlockValidCount);
7920 : }
7921 2959 : for (; iX < nXCheck; iX++)
7922 : {
7923 1142 : const double dfValue = static_cast<const double *>(
7924 1142 : pData)[iOffset + iX];
7925 1665 : if (std::isnan(dfValue) ||
7926 523 : (bHasNoData &&
7927 523 : dfValue == sNoDataValues.dfNoDataValue))
7928 59 : continue;
7929 1083 : dfMin = std::min(dfMin, dfValue);
7930 1083 : dfMax = std::max(dfMax, dfValue);
7931 1083 : dfBlockValidCount += 1.0;
7932 1083 : const double dfDelta = dfValue - dfBlockMean;
7933 1083 : dfBlockMean += dfDelta / dfBlockValidCount;
7934 1083 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7935 1817 : }
7936 : }
7937 : else
7938 : {
7939 553 : int iX = 0;
7940 553 : if (dfBlockValidCount == 0)
7941 : {
7942 7676 : for (; iX < nXCheck; iX++)
7943 : {
7944 7642 : const double dfValue =
7945 : static_cast<const double *>(
7946 7642 : pData)[iOffset + iX];
7947 15256 : if (std::isnan(dfValue) ||
7948 7614 : (bHasNoData &&
7949 7614 : dfValue == sNoDataValues.dfNoDataValue))
7950 7377 : continue;
7951 265 : dfMin = std::min(dfMin, dfValue);
7952 265 : dfMax = std::max(dfMax, dfValue);
7953 265 : dfBlockValidCount = 1;
7954 265 : dfBlockMean = dfValue;
7955 265 : iX++;
7956 265 : break;
7957 : }
7958 : }
7959 553 : if (bHasNoData)
7960 : {
7961 : iX = ComputeStatisticsFloat64_SSE2<
7962 : /* bCheckMinEqMax = */ true,
7963 398 : /* bHasNoData = */ true>(
7964 398 : static_cast<const double *>(pData) + iOffset,
7965 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7966 : dfMax, dfBlockMean, dfBlockM2,
7967 : dfBlockValidCount);
7968 : }
7969 : else
7970 : {
7971 : iX = ComputeStatisticsFloat64_SSE2<
7972 : /* bCheckMinEqMax = */ true,
7973 155 : /* bHasNoData = */ false>(
7974 155 : static_cast<const double *>(pData) + iOffset,
7975 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7976 : dfMax, dfBlockMean, dfBlockM2,
7977 : dfBlockValidCount);
7978 : }
7979 1124 : for (; iX < nXCheck; iX++)
7980 : {
7981 571 : const double dfValue = static_cast<const double *>(
7982 571 : pData)[iOffset + iX];
7983 1103 : if (std::isnan(dfValue) ||
7984 532 : (bHasNoData &&
7985 532 : dfValue == sNoDataValues.dfNoDataValue))
7986 146 : continue;
7987 425 : dfMin = std::min(dfMin, dfValue);
7988 425 : dfMax = std::max(dfMax, dfValue);
7989 425 : dfBlockValidCount += 1.0;
7990 425 : if (dfMin != dfMax)
7991 : {
7992 150 : const double dfDelta = dfValue - dfBlockMean;
7993 150 : dfBlockMean += dfDelta / dfBlockValidCount;
7994 150 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7995 : }
7996 : }
7997 : }
7998 : }
7999 :
8000 297 : if (dfBlockValidCount > 0)
8001 : {
8002 : // Update the global mean and M2 (the difference of the
8003 : // square to the mean) from the values of the block
8004 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
8005 265 : const auto nNewValidCount =
8006 265 : nValidCount + static_cast<int>(dfBlockValidCount);
8007 265 : dfM2 += dfBlockM2;
8008 265 : if (dfBlockMean != dfMean)
8009 : {
8010 252 : if (nValidCount == 0)
8011 : {
8012 23 : dfMean = dfBlockMean;
8013 : }
8014 : else
8015 : {
8016 229 : const double dfDelta = dfBlockMean - dfMean;
8017 229 : const double dfNewValidCount =
8018 : static_cast<double>(nNewValidCount);
8019 229 : dfMean +=
8020 229 : dfDelta * (dfBlockValidCount / dfNewValidCount);
8021 229 : dfM2 += dfDelta * dfDelta *
8022 229 : static_cast<double>(nValidCount) *
8023 229 : dfBlockValidCount / dfNewValidCount;
8024 : }
8025 : }
8026 265 : nValidCount = nNewValidCount;
8027 : }
8028 : }
8029 : #endif // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
8030 :
8031 : else
8032 : {
8033 : // This isn't the fastest way to do this, but is easier for now.
8034 6050 : for (int iY = 0; iY < nYCheck; iY++)
8035 : {
8036 5356 : if (nValidCount && dfMin != dfMax)
8037 : {
8038 712993 : for (int iX = 0; iX < nXCheck; iX++)
8039 : {
8040 708476 : const GPtrDiff_t iOffset =
8041 708476 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8042 708476 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8043 9654 : continue;
8044 :
8045 698849 : bool bValid = true;
8046 : double dfValue =
8047 698849 : GetPixelValue(eDataType, bSignedByte, pData,
8048 698849 : iOffset, sNoDataValues, bValid);
8049 :
8050 698849 : if (!bValid)
8051 27 : continue;
8052 :
8053 698822 : dfMin = std::min(dfMin, dfValue);
8054 698822 : dfMax = std::max(dfMax, dfValue);
8055 :
8056 698822 : nValidCount++;
8057 698822 : const double dfDelta = dfValue - dfMean;
8058 698822 : dfMean += dfDelta / nValidCount;
8059 698822 : dfM2 += dfDelta * (dfValue - dfMean);
8060 4517 : }
8061 : }
8062 : else
8063 : {
8064 839 : int iX = 0;
8065 839 : if (nValidCount == 0)
8066 : {
8067 94430 : for (; iX < nXCheck; iX++)
8068 : {
8069 94373 : const GPtrDiff_t iOffset =
8070 94373 : iX +
8071 94373 : static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8072 94373 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8073 94281 : continue;
8074 :
8075 92 : bool bValid = true;
8076 92 : double dfValue = GetPixelValue(
8077 : eDataType, bSignedByte, pData, iOffset,
8078 : sNoDataValues, bValid);
8079 :
8080 92 : if (!bValid)
8081 0 : continue;
8082 :
8083 92 : dfMin = dfValue;
8084 92 : dfMax = dfValue;
8085 92 : dfMean = dfValue;
8086 92 : nValidCount = 1;
8087 92 : iX++;
8088 92 : break;
8089 : }
8090 : }
8091 167023 : for (; iX < nXCheck; iX++)
8092 : {
8093 166184 : const GPtrDiff_t iOffset =
8094 166184 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8095 166184 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8096 376 : continue;
8097 :
8098 165823 : bool bValid = true;
8099 : double dfValue =
8100 165823 : GetPixelValue(eDataType, bSignedByte, pData,
8101 165823 : iOffset, sNoDataValues, bValid);
8102 :
8103 165823 : if (!bValid)
8104 15 : continue;
8105 :
8106 165808 : dfMin = std::min(dfMin, dfValue);
8107 165808 : dfMax = std::max(dfMax, dfValue);
8108 :
8109 165808 : nValidCount++;
8110 165808 : if (dfMin != dfMax)
8111 : {
8112 2637 : const double dfDelta = dfValue - dfMean;
8113 2637 : dfMean += dfDelta / nValidCount;
8114 2637 : dfM2 += dfDelta * (dfValue - dfMean);
8115 : }
8116 : }
8117 : }
8118 : }
8119 : }
8120 :
8121 5728 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8122 :
8123 5728 : if (poBlock)
8124 3335 : poBlock->DropLock();
8125 :
8126 5728 : if (!pfnProgress(
8127 5728 : static_cast<double>(iSampleBlock) /
8128 5728 : (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8129 : "Compute Statistics", pProgressData))
8130 : {
8131 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8132 0 : CPLFree(pabyMaskData);
8133 0 : return CE_Failure;
8134 : }
8135 : }
8136 :
8137 : #undef nBlockXSize
8138 : #undef nBlockYSize
8139 : #undef nBlocksPerRow
8140 : #undef nBlocksPerColumn
8141 :
8142 327 : if (bFloat32Optim)
8143 : {
8144 211 : dfMin = static_cast<double>(fMin);
8145 211 : dfMax = static_cast<double>(fMax);
8146 : }
8147 327 : CPLFree(pabyMaskData);
8148 : }
8149 :
8150 327 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8151 : {
8152 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8153 0 : return CE_Failure;
8154 : }
8155 :
8156 : /* -------------------------------------------------------------------- */
8157 : /* Save computed information. */
8158 : /* -------------------------------------------------------------------- */
8159 327 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8160 :
8161 327 : if (nValidCount > 0)
8162 : {
8163 326 : if (bSetStatistics)
8164 : {
8165 324 : if (bApproxOK)
8166 : {
8167 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8168 : }
8169 316 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8170 : {
8171 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8172 : }
8173 324 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8174 : }
8175 : }
8176 : else
8177 : {
8178 1 : dfMin = 0.0;
8179 1 : dfMax = 0.0;
8180 : }
8181 :
8182 327 : if (bSetStatistics)
8183 325 : SetValidPercent(nSampleCount, nValidCount);
8184 :
8185 : /* -------------------------------------------------------------------- */
8186 : /* Record results. */
8187 : /* -------------------------------------------------------------------- */
8188 327 : if (pdfMin != nullptr)
8189 319 : *pdfMin = dfMin;
8190 327 : if (pdfMax != nullptr)
8191 319 : *pdfMax = dfMax;
8192 :
8193 327 : if (pdfMean != nullptr)
8194 318 : *pdfMean = dfMean;
8195 :
8196 327 : if (pdfStdDev != nullptr)
8197 313 : *pdfStdDev = dfStdDev;
8198 :
8199 327 : if (nValidCount > 0)
8200 326 : return CE_None;
8201 :
8202 1 : ReportError(
8203 : CE_Failure, CPLE_AppDefined,
8204 : "Failed to compute statistics, no valid pixels found in sampling.");
8205 1 : return CE_Failure;
8206 : }
8207 :
8208 : /************************************************************************/
8209 : /* GDALComputeRasterStatistics() */
8210 : /************************************************************************/
8211 :
8212 : /**
8213 : * \brief Compute image statistics.
8214 : *
8215 : * @see GDALComputeRasterStatisticsEx()
8216 : * @see GDALRasterBand::ComputeStatistics()
8217 : */
8218 :
8219 0 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8220 : int bApproxOK, double *pdfMin,
8221 : double *pdfMax, double *pdfMean,
8222 : double *pdfStdDev,
8223 : GDALProgressFunc pfnProgress,
8224 : void *pProgressData)
8225 :
8226 : {
8227 0 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8228 :
8229 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8230 :
8231 0 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8232 : pdfStdDev, pfnProgress, pProgressData,
8233 0 : nullptr);
8234 : }
8235 :
8236 : /************************************************************************/
8237 : /* GDALComputeRasterStatisticsEx() */
8238 : /************************************************************************/
8239 :
8240 : /**
8241 : * \brief Compute image statistics.
8242 : *
8243 : * @see GDALRasterBand::ComputeStatistics()
8244 : *
8245 : * @since 3.14
8246 : */
8247 :
8248 242 : CPLErr GDALComputeRasterStatisticsEx(GDALRasterBandH hBand, int bApproxOK,
8249 : double *pdfMin, double *pdfMax,
8250 : double *pdfMean, double *pdfStdDev,
8251 : GDALProgressFunc pfnProgress,
8252 : void *pProgressData,
8253 : CSLConstList papszOptions)
8254 :
8255 : {
8256 242 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatisticsEx", CE_Failure);
8257 :
8258 242 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8259 :
8260 242 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8261 : pdfStdDev, pfnProgress, pProgressData,
8262 242 : papszOptions);
8263 : }
8264 :
8265 : /************************************************************************/
8266 : /* SetStatistics() */
8267 : /************************************************************************/
8268 :
8269 : /**
8270 : * \brief Set statistics on band.
8271 : *
8272 : * This method can be used to store min/max/mean/standard deviation
8273 : * statistics on a raster band.
8274 : *
8275 : * The default implementation stores them as metadata, and will only work
8276 : * on formats that can save arbitrary metadata. This method cannot detect
8277 : * whether metadata will be properly saved and so may return CE_None even
8278 : * if the statistics will never be saved.
8279 : *
8280 : * This method is the same as the C function GDALSetRasterStatistics().
8281 : *
8282 : * @param dfMin minimum pixel value.
8283 : *
8284 : * @param dfMax maximum pixel value.
8285 : *
8286 : * @param dfMean mean (average) of all pixel values.
8287 : *
8288 : * @param dfStdDev Standard deviation of all pixel values.
8289 : *
8290 : * @return CE_None on success or CE_Failure on failure.
8291 : */
8292 :
8293 606 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8294 : double dfStdDev)
8295 :
8296 : {
8297 606 : char szValue[128] = {0};
8298 :
8299 606 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8300 606 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
8301 :
8302 606 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8303 606 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8304 :
8305 606 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8306 606 : SetMetadataItem("STATISTICS_MEAN", szValue);
8307 :
8308 606 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8309 606 : SetMetadataItem("STATISTICS_STDDEV", szValue);
8310 :
8311 606 : return CE_None;
8312 : }
8313 :
8314 : /************************************************************************/
8315 : /* GDALSetRasterStatistics() */
8316 : /************************************************************************/
8317 :
8318 : /**
8319 : * \brief Set statistics on band.
8320 : *
8321 : * @see GDALRasterBand::SetStatistics()
8322 : */
8323 :
8324 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8325 : double dfMax, double dfMean,
8326 : double dfStdDev)
8327 :
8328 : {
8329 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8330 :
8331 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8332 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8333 : }
8334 :
8335 : /************************************************************************/
8336 : /* ComputeRasterMinMax() */
8337 : /************************************************************************/
8338 :
8339 : template <class T, bool HAS_NODATA>
8340 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8341 : T *pMax)
8342 : {
8343 2 : T min0 = *pMin;
8344 2 : T max0 = *pMax;
8345 2 : T min1 = *pMin;
8346 2 : T max1 = *pMax;
8347 : size_t i;
8348 2 : for (i = 0; i + 1 < nElts; i += 2)
8349 : {
8350 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8351 : {
8352 0 : min0 = std::min(min0, buffer[i]);
8353 0 : max0 = std::max(max0, buffer[i]);
8354 : }
8355 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8356 : {
8357 0 : min1 = std::min(min1, buffer[i + 1]);
8358 0 : max1 = std::max(max1, buffer[i + 1]);
8359 : }
8360 : }
8361 2 : T min = std::min(min0, min1);
8362 2 : T max = std::max(max0, max1);
8363 2 : if (i < nElts)
8364 : {
8365 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8366 : {
8367 2 : min = std::min(min, buffer[i]);
8368 2 : max = std::max(max, buffer[i]);
8369 : }
8370 : }
8371 2 : *pMin = min;
8372 2 : *pMax = max;
8373 2 : }
8374 :
8375 : template <GDALDataType eDataType, bool bSignedByte>
8376 : static void
8377 6749 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8378 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8379 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
8380 : {
8381 6749 : double dfLocalMin = dfMin;
8382 6749 : double dfLocalMax = dfMax;
8383 :
8384 22149 : for (int iY = 0; iY < nYCheck; iY++)
8385 : {
8386 14858651 : for (int iX = 0; iX < nXCheck; iX++)
8387 : {
8388 14843195 : const GPtrDiff_t iOffset =
8389 14843195 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8390 14843195 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8391 109852 : continue;
8392 14760222 : bool bValid = true;
8393 14760222 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8394 : iOffset, sNoDataValues, bValid);
8395 14760222 : if (!bValid)
8396 26871 : continue;
8397 :
8398 14733422 : dfLocalMin = std::min(dfLocalMin, dfValue);
8399 14733422 : dfLocalMax = std::max(dfLocalMax, dfValue);
8400 : }
8401 : }
8402 :
8403 6749 : dfMin = dfLocalMin;
8404 6749 : dfMax = dfLocalMax;
8405 6749 : }
8406 :
8407 6749 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8408 : bool bSignedByte, int nXCheck, int nYCheck,
8409 : int nBlockXSize,
8410 : const GDALNoDataValues &sNoDataValues,
8411 : const GByte *pabyMaskData, double &dfMin,
8412 : double &dfMax)
8413 : {
8414 6749 : switch (eDataType)
8415 : {
8416 0 : case GDT_Unknown:
8417 0 : CPLAssert(false);
8418 : break;
8419 666 : case GDT_UInt8:
8420 666 : if (bSignedByte)
8421 : {
8422 3 : ComputeMinMaxGeneric<GDT_UInt8, true>(
8423 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8424 : pabyMaskData, dfMin, dfMax);
8425 : }
8426 : else
8427 : {
8428 663 : ComputeMinMaxGeneric<GDT_UInt8, false>(
8429 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8430 : pabyMaskData, dfMin, dfMax);
8431 : }
8432 666 : break;
8433 4 : case GDT_Int8:
8434 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8435 : nBlockXSize, sNoDataValues,
8436 : pabyMaskData, dfMin, dfMax);
8437 4 : break;
8438 969 : case GDT_UInt16:
8439 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8440 : nBlockXSize, sNoDataValues,
8441 : pabyMaskData, dfMin, dfMax);
8442 969 : break;
8443 2 : case GDT_Int16:
8444 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8445 : nBlockXSize, sNoDataValues,
8446 : pabyMaskData, dfMin, dfMax);
8447 2 : break;
8448 3 : case GDT_UInt32:
8449 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8450 : nBlockXSize, sNoDataValues,
8451 : pabyMaskData, dfMin, dfMax);
8452 3 : break;
8453 3 : case GDT_Int32:
8454 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8455 : nBlockXSize, sNoDataValues,
8456 : pabyMaskData, dfMin, dfMax);
8457 3 : break;
8458 4 : case GDT_UInt64:
8459 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8460 : nBlockXSize, sNoDataValues,
8461 : pabyMaskData, dfMin, dfMax);
8462 4 : break;
8463 4 : case GDT_Int64:
8464 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8465 : nBlockXSize, sNoDataValues,
8466 : pabyMaskData, dfMin, dfMax);
8467 4 : break;
8468 2 : case GDT_Float16:
8469 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8470 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8471 : pabyMaskData, dfMin, dfMax);
8472 2 : break;
8473 4981 : case GDT_Float32:
8474 4981 : ComputeMinMaxGeneric<GDT_Float32, false>(
8475 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8476 : pabyMaskData, dfMin, dfMax);
8477 4981 : break;
8478 1 : case GDT_Float64:
8479 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8480 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8481 : pabyMaskData, dfMin, dfMax);
8482 1 : break;
8483 9 : case GDT_CInt16:
8484 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8485 : nBlockXSize, sNoDataValues,
8486 : pabyMaskData, dfMin, dfMax);
8487 9 : break;
8488 9 : case GDT_CInt32:
8489 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8490 : nBlockXSize, sNoDataValues,
8491 : pabyMaskData, dfMin, dfMax);
8492 9 : break;
8493 0 : case GDT_CFloat16:
8494 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8495 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8496 : pabyMaskData, dfMin, dfMax);
8497 0 : break;
8498 75 : case GDT_CFloat32:
8499 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8500 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8501 : pabyMaskData, dfMin, dfMax);
8502 75 : break;
8503 17 : case GDT_CFloat64:
8504 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8505 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8506 : pabyMaskData, dfMin, dfMax);
8507 17 : break;
8508 0 : case GDT_TypeCount:
8509 0 : CPLAssert(false);
8510 : break;
8511 : }
8512 6749 : }
8513 :
8514 215 : static bool ComputeMinMaxGenericIterBlocks(
8515 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8516 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8517 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8518 : double &dfMin, double &dfMax)
8519 :
8520 : {
8521 215 : GByte *pabyMaskData = nullptr;
8522 : int nBlockXSize, nBlockYSize;
8523 215 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8524 :
8525 215 : if (poMaskBand)
8526 : {
8527 : pabyMaskData =
8528 151 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8529 151 : if (!pabyMaskData)
8530 : {
8531 0 : return false;
8532 : }
8533 : }
8534 :
8535 6964 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8536 6749 : iSampleBlock += nSampleRate)
8537 : {
8538 6749 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8539 6749 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8540 :
8541 6749 : int nXCheck = 0, nYCheck = 0;
8542 6749 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8543 :
8544 13375 : if (poMaskBand &&
8545 6626 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8546 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8547 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8548 : nBlockXSize, nullptr) != CE_None)
8549 : {
8550 0 : CPLFree(pabyMaskData);
8551 0 : return false;
8552 : }
8553 :
8554 6749 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8555 6749 : if (poBlock == nullptr)
8556 : {
8557 0 : CPLFree(pabyMaskData);
8558 0 : return false;
8559 : }
8560 :
8561 6749 : void *const pData = poBlock->GetDataRef();
8562 :
8563 6749 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8564 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8565 : dfMax);
8566 :
8567 6749 : poBlock->DropLock();
8568 : }
8569 :
8570 215 : CPLFree(pabyMaskData);
8571 215 : return true;
8572 : }
8573 :
8574 : /**
8575 : * \brief Compute the min/max values for a band.
8576 : *
8577 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8578 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8579 : * get an approximate min/max. If the band has a nodata value it will
8580 : * be excluded from the minimum and maximum.
8581 : *
8582 : * If bApprox is FALSE, then all pixels will be read and used to compute
8583 : * an exact range.
8584 : *
8585 : * This method is the same as the C function GDALComputeRasterMinMax().
8586 : *
8587 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8588 : * FALSE.
8589 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8590 : * maximum (adfMinMax[1]) are returned.
8591 : *
8592 : * @return CE_None on success or CE_Failure on failure.
8593 : */
8594 :
8595 1975 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8596 : {
8597 : /* -------------------------------------------------------------------- */
8598 : /* Does the driver already know the min/max? */
8599 : /* -------------------------------------------------------------------- */
8600 1975 : if (bApproxOK)
8601 : {
8602 23 : int bSuccessMin = FALSE;
8603 23 : int bSuccessMax = FALSE;
8604 :
8605 23 : double dfMin = GetMinimum(&bSuccessMin);
8606 23 : double dfMax = GetMaximum(&bSuccessMax);
8607 :
8608 23 : if (bSuccessMin && bSuccessMax)
8609 : {
8610 1 : adfMinMax[0] = dfMin;
8611 1 : adfMinMax[1] = dfMax;
8612 1 : return CE_None;
8613 : }
8614 : }
8615 :
8616 : /* -------------------------------------------------------------------- */
8617 : /* If we have overview bands, use them for min/max. */
8618 : /* -------------------------------------------------------------------- */
8619 : // cppcheck-suppress knownConditionTrueFalse
8620 1974 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8621 : {
8622 : GDALRasterBand *poBand =
8623 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8624 :
8625 0 : if (poBand != this)
8626 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8627 : }
8628 :
8629 : /* -------------------------------------------------------------------- */
8630 : /* Read actual data and compute minimum and maximum. */
8631 : /* -------------------------------------------------------------------- */
8632 1974 : GDALNoDataValues sNoDataValues(this, eDataType);
8633 1974 : GDALRasterBand *poMaskBand = nullptr;
8634 1974 : if (!sNoDataValues.bGotNoDataValue)
8635 : {
8636 1610 : const int l_nMaskFlags = GetMaskFlags();
8637 1761 : if (l_nMaskFlags != GMF_ALL_VALID &&
8638 151 : GetColorInterpretation() != GCI_AlphaBand)
8639 : {
8640 151 : poMaskBand = GetMaskBand();
8641 : }
8642 : }
8643 :
8644 1974 : if (!bApproxOK &&
8645 1952 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8646 1792 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8647 1566 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8648 1520 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8649 1952 : eDataType == GDT_Float64) &&
8650 : !poMaskBand)
8651 : {
8652 1610 : CPLErr eErr = ComputeRasterMinMaxLocation(
8653 805 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8654 805 : if (eErr == CE_Warning)
8655 : {
8656 8 : ReportError(CE_Failure, CPLE_AppDefined,
8657 : "Failed to compute min/max, no valid pixels found in "
8658 : "sampling.");
8659 8 : eErr = CE_Failure;
8660 : }
8661 805 : return eErr;
8662 : }
8663 :
8664 1169 : bool bSignedByte = false;
8665 1169 : if (eDataType == GDT_UInt8)
8666 : {
8667 827 : EnablePixelTypeSignedByteWarning(false);
8668 : const char *pszPixelType =
8669 827 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
8670 827 : EnablePixelTypeSignedByteWarning(true);
8671 827 : bSignedByte =
8672 827 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8673 : }
8674 :
8675 : GDALRasterIOExtraArg sExtraArg;
8676 1169 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8677 :
8678 2338 : GUInt32 nMin = (eDataType == GDT_UInt8)
8679 1169 : ? 255
8680 : : 65535; // used for GByte & GUInt16 cases
8681 1169 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8682 1169 : GInt16 nMinInt16 =
8683 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8684 1169 : GInt16 nMaxInt16 =
8685 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8686 1169 : double dfMin =
8687 : std::numeric_limits<double>::infinity(); // used for generic code path
8688 1169 : double dfMax =
8689 : -std::numeric_limits<double>::infinity(); // used for generic code path
8690 1169 : const bool bUseOptimizedPath =
8691 1397 : !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8692 228 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8693 :
8694 : const auto ComputeMinMaxForBlock =
8695 20309 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8696 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8697 116446 : int nYCheck)
8698 : {
8699 20309 : if (eDataType == GDT_UInt8 && !bSignedByte)
8700 : {
8701 : const bool bHasNoData =
8702 11612 : sNoDataValues.bGotNoDataValue &&
8703 30462 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8704 11612 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8705 11612 : sNoDataValues.dfNoDataValue;
8706 18850 : const GUInt32 nNoDataValue =
8707 18850 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8708 : : 0;
8709 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8710 : ComputeStatisticsInternal<GByte,
8711 : /* COMPUTE_OTHER_STATS = */ false>::
8712 18850 : f(nXCheck, nBufferWidth, nYCheck,
8713 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8714 18850 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8715 : }
8716 1459 : else if (eDataType == GDT_UInt16)
8717 : {
8718 : const bool bHasNoData =
8719 124 : sNoDataValues.bGotNoDataValue &&
8720 1581 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8721 124 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8722 124 : sNoDataValues.dfNoDataValue;
8723 1457 : const GUInt32 nNoDataValue =
8724 1457 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8725 : : 0;
8726 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8727 : ComputeStatisticsInternal<GUInt16,
8728 : /* COMPUTE_OTHER_STATS = */ false>::
8729 1457 : f(nXCheck, nBufferWidth, nYCheck,
8730 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8731 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8732 : }
8733 2 : else if (eDataType == GDT_Int16)
8734 : {
8735 : const bool bHasNoData =
8736 0 : sNoDataValues.bGotNoDataValue &&
8737 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8738 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8739 0 : sNoDataValues.dfNoDataValue;
8740 2 : if (bHasNoData)
8741 : {
8742 0 : const int16_t nNoDataValue =
8743 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8744 0 : for (int iY = 0; iY < nYCheck; iY++)
8745 : {
8746 0 : ComputeMinMax<int16_t, true>(
8747 0 : static_cast<const int16_t *>(pData) +
8748 0 : static_cast<size_t>(iY) * nBufferWidth,
8749 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8750 : }
8751 : }
8752 : else
8753 : {
8754 4 : for (int iY = 0; iY < nYCheck; iY++)
8755 : {
8756 2 : ComputeMinMax<int16_t, false>(
8757 2 : static_cast<const int16_t *>(pData) +
8758 2 : static_cast<size_t>(iY) * nBufferWidth,
8759 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8760 : }
8761 : }
8762 : }
8763 20309 : };
8764 :
8765 1169 : if (bApproxOK && HasArbitraryOverviews())
8766 : {
8767 : /* --------------------------------------------------------------------
8768 : */
8769 : /* Figure out how much the image should be reduced to get an */
8770 : /* approximate value. */
8771 : /* --------------------------------------------------------------------
8772 : */
8773 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8774 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8775 :
8776 0 : int nXReduced = nRasterXSize;
8777 0 : int nYReduced = nRasterYSize;
8778 0 : if (dfReduction > 1.0)
8779 : {
8780 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8781 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8782 :
8783 : // Catch the case of huge resizing ratios here
8784 0 : if (nXReduced == 0)
8785 0 : nXReduced = 1;
8786 0 : if (nYReduced == 0)
8787 0 : nYReduced = 1;
8788 : }
8789 :
8790 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8791 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8792 :
8793 : const CPLErr eErr =
8794 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8795 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8796 0 : if (eErr != CE_None)
8797 : {
8798 0 : CPLFree(pData);
8799 0 : return eErr;
8800 : }
8801 :
8802 0 : GByte *pabyMaskData = nullptr;
8803 0 : if (poMaskBand)
8804 : {
8805 : pabyMaskData =
8806 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8807 0 : if (!pabyMaskData)
8808 : {
8809 0 : CPLFree(pData);
8810 0 : return CE_Failure;
8811 : }
8812 :
8813 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8814 : pabyMaskData, nXReduced, nYReduced,
8815 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
8816 : {
8817 0 : CPLFree(pData);
8818 0 : CPLFree(pabyMaskData);
8819 0 : return CE_Failure;
8820 : }
8821 : }
8822 :
8823 0 : if (bUseOptimizedPath)
8824 : {
8825 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8826 : }
8827 : else
8828 : {
8829 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8830 : nYReduced, nXReduced, sNoDataValues,
8831 : pabyMaskData, dfMin, dfMax);
8832 : }
8833 :
8834 0 : CPLFree(pData);
8835 0 : CPLFree(pabyMaskData);
8836 : }
8837 :
8838 : else // No arbitrary overviews
8839 : {
8840 1169 : if (!InitBlockInfo())
8841 0 : return CE_Failure;
8842 :
8843 : /* --------------------------------------------------------------------
8844 : */
8845 : /* Figure out the ratio of blocks we will read to get an */
8846 : /* approximate value. */
8847 : /* --------------------------------------------------------------------
8848 : */
8849 1169 : int nSampleRate = 1;
8850 :
8851 1169 : if (bApproxOK)
8852 : {
8853 22 : nSampleRate = static_cast<int>(std::max(
8854 44 : 1.0,
8855 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8856 : // We want to avoid probing only the first column of blocks for
8857 : // a square shaped raster, because it is not unlikely that it may
8858 : // be padding only (#6378).
8859 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8860 0 : nSampleRate += 1;
8861 : }
8862 :
8863 1169 : if (bUseOptimizedPath)
8864 : {
8865 954 : for (GIntBig iSampleBlock = 0;
8866 21183 : iSampleBlock <
8867 21183 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8868 20229 : iSampleBlock += nSampleRate)
8869 : {
8870 20311 : const int iYBlock =
8871 20311 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8872 20311 : const int iXBlock =
8873 20311 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8874 :
8875 20311 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8876 20311 : if (poBlock == nullptr)
8877 2 : return CE_Failure;
8878 :
8879 20309 : void *const pData = poBlock->GetDataRef();
8880 :
8881 20309 : int nXCheck = 0, nYCheck = 0;
8882 20309 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8883 :
8884 20309 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8885 :
8886 20309 : poBlock->DropLock();
8887 :
8888 20309 : if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8889 4120 : nMax == 255)
8890 80 : break;
8891 : }
8892 : }
8893 : else
8894 : {
8895 215 : const GIntBig nTotalBlocks =
8896 215 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8897 215 : if (!ComputeMinMaxGenericIterBlocks(
8898 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8899 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8900 : {
8901 0 : return CE_Failure;
8902 : }
8903 : }
8904 : }
8905 :
8906 1167 : if (bUseOptimizedPath)
8907 : {
8908 952 : if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8909 : {
8910 951 : dfMin = nMin;
8911 951 : dfMax = nMax;
8912 : }
8913 1 : else if (eDataType == GDT_Int16)
8914 : {
8915 1 : dfMin = nMinInt16;
8916 1 : dfMax = nMaxInt16;
8917 : }
8918 : }
8919 :
8920 1167 : if (dfMin > dfMax)
8921 : {
8922 24 : adfMinMax[0] = 0;
8923 24 : adfMinMax[1] = 0;
8924 24 : ReportError(
8925 : CE_Failure, CPLE_AppDefined,
8926 : "Failed to compute min/max, no valid pixels found in sampling.");
8927 24 : return CE_Failure;
8928 : }
8929 :
8930 1143 : adfMinMax[0] = dfMin;
8931 1143 : adfMinMax[1] = dfMax;
8932 :
8933 1143 : return CE_None;
8934 : }
8935 :
8936 : /************************************************************************/
8937 : /* GDALComputeRasterMinMax() */
8938 : /************************************************************************/
8939 :
8940 : /**
8941 : * \brief Compute the min/max values for a band.
8942 : *
8943 : * @see GDALRasterBand::ComputeRasterMinMax()
8944 : *
8945 : * @note Prior to GDAL 3.6, this function returned void
8946 : */
8947 :
8948 1825 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8949 : double adfMinMax[2])
8950 :
8951 : {
8952 1825 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8953 :
8954 1825 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8955 1825 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8956 : }
8957 :
8958 : /************************************************************************/
8959 : /* ComputeRasterMinMaxLocation() */
8960 : /************************************************************************/
8961 :
8962 : /**
8963 : * \brief Compute the min/max values for a band, and their location.
8964 : *
8965 : * Pixels whose value matches the nodata value or are masked by the mask
8966 : * band are ignored.
8967 : *
8968 : * If the minimum or maximum value is hit in several locations, it is not
8969 : * specified which one will be returned.
8970 : *
8971 : * @param[out] pdfMin Pointer to the minimum value.
8972 : * @param[out] pdfMax Pointer to the maximum value.
8973 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8974 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8975 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8976 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8977 : *
8978 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8979 : * CE_Failure in case of error.
8980 : *
8981 : * @since GDAL 3.11
8982 : */
8983 :
8984 821 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8985 : double *pdfMax, int *pnMinX,
8986 : int *pnMinY, int *pnMaxX,
8987 : int *pnMaxY)
8988 : {
8989 821 : int nMinX = -1;
8990 821 : int nMinY = -1;
8991 821 : int nMaxX = -1;
8992 821 : int nMaxY = -1;
8993 821 : double dfMin = std::numeric_limits<double>::infinity();
8994 821 : double dfMax = -std::numeric_limits<double>::infinity();
8995 821 : if (pdfMin)
8996 818 : *pdfMin = dfMin;
8997 821 : if (pdfMax)
8998 818 : *pdfMax = dfMax;
8999 821 : if (pnMinX)
9000 14 : *pnMinX = nMinX;
9001 821 : if (pnMinY)
9002 14 : *pnMinY = nMinY;
9003 821 : if (pnMaxX)
9004 14 : *pnMaxX = nMaxX;
9005 821 : if (pnMaxY)
9006 14 : *pnMaxY = nMaxY;
9007 :
9008 821 : if (GDALDataTypeIsComplex(eDataType))
9009 : {
9010 0 : CPLError(CE_Failure, CPLE_NotSupported,
9011 : "Complex data type not supported");
9012 0 : return CE_Failure;
9013 : }
9014 :
9015 821 : if (!InitBlockInfo())
9016 0 : return CE_Failure;
9017 :
9018 821 : GDALNoDataValues sNoDataValues(this, eDataType);
9019 821 : GDALRasterBand *poMaskBand = nullptr;
9020 821 : if (!sNoDataValues.bGotNoDataValue)
9021 : {
9022 587 : const int l_nMaskFlags = GetMaskFlags();
9023 588 : if (l_nMaskFlags != GMF_ALL_VALID &&
9024 1 : GetColorInterpretation() != GCI_AlphaBand)
9025 : {
9026 1 : poMaskBand = GetMaskBand();
9027 : }
9028 : }
9029 :
9030 821 : bool bSignedByte = false;
9031 821 : if (eDataType == GDT_UInt8)
9032 : {
9033 7 : EnablePixelTypeSignedByteWarning(false);
9034 : const char *pszPixelType =
9035 7 : GetMetadataItem("PIXELTYPE", GDAL_MDD_IMAGE_STRUCTURE);
9036 7 : EnablePixelTypeSignedByteWarning(true);
9037 7 : bSignedByte =
9038 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
9039 : }
9040 :
9041 821 : GByte *pabyMaskData = nullptr;
9042 821 : if (poMaskBand)
9043 : {
9044 : pabyMaskData =
9045 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
9046 1 : if (!pabyMaskData)
9047 : {
9048 0 : return CE_Failure;
9049 : }
9050 : }
9051 :
9052 821 : const GIntBig nTotalBlocks =
9053 821 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
9054 821 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
9055 821 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
9056 8066 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
9057 : {
9058 7248 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
9059 7248 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
9060 :
9061 7248 : int nXCheck = 0, nYCheck = 0;
9062 7248 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
9063 :
9064 7250 : if (poMaskBand &&
9065 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
9066 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
9067 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
9068 2 : nBlockXSize, nullptr) != CE_None)
9069 : {
9070 0 : CPLFree(pabyMaskData);
9071 0 : return CE_Failure;
9072 : }
9073 :
9074 7248 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
9075 7248 : if (poBlock == nullptr)
9076 : {
9077 0 : CPLFree(pabyMaskData);
9078 0 : return CE_Failure;
9079 : }
9080 :
9081 7248 : void *const pData = poBlock->GetDataRef();
9082 :
9083 7248 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
9084 : {
9085 5059 : for (int iY = 0; iY < nYCheck; ++iY)
9086 : {
9087 238290 : for (int iX = 0; iX < nXCheck; ++iX)
9088 : {
9089 233478 : const GPtrDiff_t iOffset =
9090 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9091 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
9092 2 : continue;
9093 233476 : bool bValid = true;
9094 : double dfValue =
9095 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
9096 : sNoDataValues, bValid);
9097 233476 : if (!bValid)
9098 0 : continue;
9099 233476 : if (dfValue < dfMin)
9100 : {
9101 606 : dfMin = dfValue;
9102 606 : nMinX = iXBlock * nBlockXSize + iX;
9103 606 : nMinY = iYBlock * nBlockYSize + iY;
9104 : }
9105 233476 : if (dfValue > dfMax)
9106 : {
9107 1515 : dfMax = dfValue;
9108 1515 : nMaxX = iXBlock * nBlockXSize + iX;
9109 1515 : nMaxY = iYBlock * nBlockYSize + iY;
9110 : }
9111 : }
9112 247 : }
9113 : }
9114 : else
9115 : {
9116 7001 : size_t pos_min = 0;
9117 7001 : size_t pos_max = 0;
9118 7001 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
9119 7001 : if (bNeedsMin && bNeedsMax)
9120 : {
9121 13994 : std::tie(pos_min, pos_max) = gdal::minmax_element(
9122 6997 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9123 6997 : eEffectiveDT, CPL_TO_BOOL(sNoDataValues.bGotNoDataValue),
9124 13994 : sNoDataValues.dfNoDataValue);
9125 : }
9126 4 : else if (bNeedsMin)
9127 : {
9128 1 : pos_min = gdal::min_element(
9129 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9130 1 : eEffectiveDT, CPL_TO_BOOL(sNoDataValues.bGotNoDataValue),
9131 : sNoDataValues.dfNoDataValue);
9132 : }
9133 3 : else if (bNeedsMax)
9134 : {
9135 2 : pos_max = gdal::max_element(
9136 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9137 2 : eEffectiveDT, CPL_TO_BOOL(sNoDataValues.bGotNoDataValue),
9138 : sNoDataValues.dfNoDataValue);
9139 : }
9140 :
9141 7001 : if (bNeedsMin)
9142 : {
9143 6998 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
9144 6998 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
9145 6998 : bool bValid = true;
9146 : const double dfMinValueBlock =
9147 6998 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9148 : sNoDataValues, bValid);
9149 6998 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9150 : {
9151 1113 : dfMin = dfMinValueBlock;
9152 1113 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
9153 1113 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
9154 : }
9155 : }
9156 :
9157 7001 : if (bNeedsMax)
9158 : {
9159 6999 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9160 6999 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9161 6999 : bool bValid = true;
9162 : const double dfMaxValueBlock =
9163 6999 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9164 : sNoDataValues, bValid);
9165 6999 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9166 : {
9167 1102 : dfMax = dfMaxValueBlock;
9168 1102 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9169 1102 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9170 : }
9171 : }
9172 : }
9173 :
9174 7248 : poBlock->DropLock();
9175 :
9176 7248 : if (eDataType == GDT_UInt8)
9177 : {
9178 10 : if (bNeedsMin && dfMin == 0)
9179 : {
9180 1 : bNeedsMin = false;
9181 : }
9182 10 : if (bNeedsMax && dfMax == 255)
9183 : {
9184 4 : bNeedsMax = false;
9185 : }
9186 10 : if (!bNeedsMin && !bNeedsMax)
9187 : {
9188 3 : break;
9189 : }
9190 : }
9191 : }
9192 :
9193 821 : CPLFree(pabyMaskData);
9194 :
9195 821 : if (pdfMin)
9196 818 : *pdfMin = dfMin;
9197 821 : if (pdfMax)
9198 818 : *pdfMax = dfMax;
9199 821 : if (pnMinX)
9200 14 : *pnMinX = nMinX;
9201 821 : if (pnMinY)
9202 14 : *pnMinY = nMinY;
9203 821 : if (pnMaxX)
9204 14 : *pnMaxX = nMaxX;
9205 821 : if (pnMaxY)
9206 14 : *pnMaxY = nMaxY;
9207 821 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9208 821 : : CE_None;
9209 : }
9210 :
9211 : /************************************************************************/
9212 : /* GDALComputeRasterMinMaxLocation() */
9213 : /************************************************************************/
9214 :
9215 : /**
9216 : * \brief Compute the min/max values for a band, and their location.
9217 : *
9218 : * @see GDALRasterBand::ComputeRasterMinMax()
9219 : * @since GDAL 3.11
9220 : */
9221 :
9222 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9223 : double *pdfMax, int *pnMinX, int *pnMinY,
9224 : int *pnMaxX, int *pnMaxY)
9225 :
9226 : {
9227 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9228 :
9229 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9230 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9231 14 : pnMaxX, pnMaxY);
9232 : }
9233 :
9234 : /************************************************************************/
9235 : /* SetDefaultHistogram() */
9236 : /************************************************************************/
9237 :
9238 : /* FIXME : add proper documentation */
9239 : /**
9240 : * \brief Set default histogram.
9241 : *
9242 : * This method is the same as the C function GDALSetDefaultHistogram() and
9243 : * GDALSetDefaultHistogramEx()
9244 : */
9245 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9246 : double /* dfMax */,
9247 : int /* nBuckets */,
9248 : GUIntBig * /* panHistogram */)
9249 :
9250 : {
9251 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9252 0 : ReportError(CE_Failure, CPLE_NotSupported,
9253 : "SetDefaultHistogram() not implemented for this format.");
9254 :
9255 0 : return CE_Failure;
9256 : }
9257 :
9258 : /************************************************************************/
9259 : /* GDALSetDefaultHistogram() */
9260 : /************************************************************************/
9261 :
9262 : /**
9263 : * \brief Set default histogram.
9264 : *
9265 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9266 : * 2 billion.
9267 : *
9268 : * @see GDALRasterBand::SetDefaultHistogram()
9269 : * @see GDALSetRasterHistogramEx()
9270 : */
9271 :
9272 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9273 : double dfMax, int nBuckets,
9274 : int *panHistogram)
9275 :
9276 : {
9277 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9278 :
9279 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9280 :
9281 : GUIntBig *panHistogramTemp =
9282 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9283 0 : if (panHistogramTemp == nullptr)
9284 : {
9285 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9286 : "Out of memory in GDALSetDefaultHistogram().");
9287 0 : return CE_Failure;
9288 : }
9289 :
9290 0 : for (int i = 0; i < nBuckets; ++i)
9291 : {
9292 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9293 : }
9294 :
9295 : const CPLErr eErr =
9296 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9297 :
9298 0 : CPLFree(panHistogramTemp);
9299 :
9300 0 : return eErr;
9301 : }
9302 :
9303 : /************************************************************************/
9304 : /* GDALSetDefaultHistogramEx() */
9305 : /************************************************************************/
9306 :
9307 : /**
9308 : * \brief Set default histogram.
9309 : *
9310 : * @see GDALRasterBand::SetDefaultHistogram()
9311 : *
9312 : */
9313 :
9314 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9315 : double dfMin, double dfMax,
9316 : int nBuckets,
9317 : GUIntBig *panHistogram)
9318 :
9319 : {
9320 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9321 :
9322 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9323 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9324 : }
9325 :
9326 : /************************************************************************/
9327 : /* GetDefaultRAT() */
9328 : /************************************************************************/
9329 :
9330 : /**
9331 : * \brief Fetch default Raster Attribute Table.
9332 : *
9333 : * A RAT will be returned if there is a default one associated with the
9334 : * band, otherwise NULL is returned. The returned RAT is owned by the
9335 : * band and should not be deleted by the application.
9336 : *
9337 : * This method is the same as the C function GDALGetDefaultRAT().
9338 : *
9339 : * @return NULL, or a pointer to an internal RAT owned by the band.
9340 : */
9341 :
9342 366 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9343 :
9344 : {
9345 366 : return nullptr;
9346 : }
9347 :
9348 : /************************************************************************/
9349 : /* GDALGetDefaultRAT() */
9350 : /************************************************************************/
9351 :
9352 : /**
9353 : * \brief Fetch default Raster Attribute Table.
9354 : *
9355 : * @see GDALRasterBand::GetDefaultRAT()
9356 : */
9357 :
9358 1371 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9359 :
9360 : {
9361 1371 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9362 :
9363 1371 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9364 1371 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9365 : }
9366 :
9367 : /************************************************************************/
9368 : /* SetDefaultRAT() */
9369 : /************************************************************************/
9370 :
9371 : /**
9372 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9373 : * \brief Set default Raster Attribute Table.
9374 : *
9375 : * Associates a default RAT with the band. If not implemented for the
9376 : * format a CPLE_NotSupported error will be issued. If successful a copy
9377 : * of the RAT is made, the original remains owned by the caller.
9378 : *
9379 : * This method is the same as the C function GDALSetDefaultRAT().
9380 : *
9381 : * @param poRAT the RAT to assign to the band.
9382 : *
9383 : * @return CE_None on success or CE_Failure if unsupported or otherwise
9384 : * failing.
9385 : */
9386 :
9387 : /**/
9388 : /**/
9389 :
9390 : CPLErr
9391 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9392 : {
9393 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9394 : {
9395 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
9396 0 : ReportError(CE_Failure, CPLE_NotSupported,
9397 : "SetDefaultRAT() not implemented for this format.");
9398 0 : CPLPopErrorHandler();
9399 : }
9400 0 : return CE_Failure;
9401 : }
9402 :
9403 : /************************************************************************/
9404 : /* GDALSetDefaultRAT() */
9405 : /************************************************************************/
9406 :
9407 : /**
9408 : * \brief Set default Raster Attribute Table.
9409 : *
9410 : * @see GDALRasterBand::GDALSetDefaultRAT()
9411 : */
9412 :
9413 65 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9414 : GDALRasterAttributeTableH hRAT)
9415 :
9416 : {
9417 65 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9418 :
9419 65 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9420 :
9421 65 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9422 : }
9423 :
9424 : /************************************************************************/
9425 : /* HasNoData() */
9426 : /************************************************************************/
9427 :
9428 141421 : bool GDALRasterBand::HasNoData() const
9429 : {
9430 141421 : int bHaveNoDataRaw = FALSE;
9431 141421 : bool bHaveNoData = false;
9432 141421 : GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9433 141421 : if (eDataType == GDT_Int64)
9434 : {
9435 213 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9436 213 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9437 : }
9438 141208 : else if (eDataType == GDT_UInt64)
9439 : {
9440 161 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9441 161 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9442 : }
9443 : else
9444 : {
9445 141047 : const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9446 141047 : if (bHaveNoDataRaw &&
9447 141047 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9448 : {
9449 1323 : bHaveNoData = true;
9450 : }
9451 : }
9452 141421 : return bHaveNoData;
9453 : }
9454 :
9455 : /************************************************************************/
9456 : /* GetMaskBand() */
9457 : /************************************************************************/
9458 :
9459 : /**
9460 : * \brief Return the mask band associated with the band.
9461 : *
9462 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9463 : * that returns one of four default implementations :
9464 : * <ul>
9465 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9466 : * </li>
9467 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9468 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9469 : * GMF_NODATA | GMF_PER_DATASET.
9470 : * </li>
9471 : * <li>If the band has a nodata value set, an instance of the new
9472 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9473 : * GMF_NODATA.
9474 : * </li>
9475 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9476 : * to apply to this band (specific rules yet to be determined) and that is of
9477 : * type GDT_UInt8 then that alpha band will be returned, and the flags
9478 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9479 : * </li>
9480 : * <li>If neither of the above apply, an instance of the new
9481 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9482 : * pixels. The null flags will return GMF_ALL_VALID.
9483 : * </li>
9484 : * </ul>
9485 : *
9486 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9487 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9488 : *
9489 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9490 : * dataset, with the same name as the main dataset and suffixed with .msk,
9491 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9492 : * main dataset.
9493 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9494 : * level, where xx matches the band number of a band of the main dataset. The
9495 : * value of those items is a combination of the flags GMF_ALL_VALID,
9496 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9497 : * a band, then the other rules explained above will be used to generate a
9498 : * on-the-fly mask band.
9499 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9500 : *
9501 : * This method is the same as the C function GDALGetMaskBand().
9502 : *
9503 : * @return a valid mask band.
9504 : *
9505 : *
9506 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9507 : *
9508 : */
9509 835643 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9510 :
9511 : {
9512 835643 : if (poMask != nullptr)
9513 : {
9514 734749 : if (poMask.IsOwned())
9515 : {
9516 341180 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9517 : {
9518 40477 : if (HasNoData())
9519 : {
9520 9 : InvalidateMaskBand();
9521 : }
9522 : }
9523 300703 : else if (auto poNoDataMaskBand =
9524 300703 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9525 : {
9526 442 : int bHaveNoDataRaw = FALSE;
9527 442 : bool bIsSame = false;
9528 442 : if (eDataType == GDT_Int64)
9529 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9530 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9531 10 : bHaveNoDataRaw;
9532 425 : else if (eDataType == GDT_UInt64)
9533 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9534 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9535 10 : bHaveNoDataRaw;
9536 : else
9537 : {
9538 : const double dfNoDataValue =
9539 408 : GetNoDataValue(&bHaveNoDataRaw);
9540 408 : if (bHaveNoDataRaw)
9541 : {
9542 405 : bIsSame =
9543 405 : std::isnan(dfNoDataValue)
9544 405 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9545 370 : : poNoDataMaskBand->m_dfNoDataValue ==
9546 : dfNoDataValue;
9547 : }
9548 : }
9549 442 : if (!bIsSame)
9550 23 : InvalidateMaskBand();
9551 : }
9552 : }
9553 :
9554 734749 : if (poMask)
9555 734717 : return poMask.get();
9556 : }
9557 :
9558 : /* -------------------------------------------------------------------- */
9559 : /* Check for a mask in a .msk file. */
9560 : /* -------------------------------------------------------------------- */
9561 100926 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9562 : {
9563 50 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9564 50 : if (poMask != nullptr)
9565 : {
9566 47 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9567 47 : return poMask.get();
9568 : }
9569 : }
9570 :
9571 : /* -------------------------------------------------------------------- */
9572 : /* Check for NODATA_VALUES metadata. */
9573 : /* -------------------------------------------------------------------- */
9574 100879 : if (poDS != nullptr)
9575 : {
9576 : const char *pszGDALNoDataValues =
9577 100859 : poDS->GetMetadataItem("NODATA_VALUES");
9578 100859 : if (pszGDALNoDataValues != nullptr)
9579 : {
9580 62 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9581 : pszGDALNoDataValues, " ", FALSE, FALSE);
9582 :
9583 : // Make sure we have as many values as bands.
9584 122 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9585 60 : poDS->GetRasterCount() != 0)
9586 : {
9587 : // Make sure that all bands have the same data type
9588 : // This is clearly not a fundamental condition, just a
9589 : // condition to make implementation easier.
9590 60 : GDALDataType eDT = GDT_Unknown;
9591 60 : int i = 0; // Used after for.
9592 236 : for (; i < poDS->GetRasterCount(); ++i)
9593 : {
9594 176 : if (i == 0)
9595 60 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9596 116 : else if (eDT !=
9597 116 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9598 : {
9599 0 : break;
9600 : }
9601 : }
9602 60 : if (i == poDS->GetRasterCount())
9603 : {
9604 60 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9605 : try
9606 : {
9607 60 : poMask.reset(
9608 120 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9609 : }
9610 0 : catch (const std::bad_alloc &)
9611 : {
9612 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9613 0 : poMask.reset();
9614 : }
9615 60 : CSLDestroy(papszGDALNoDataValues);
9616 60 : return poMask.get();
9617 : }
9618 : else
9619 : {
9620 0 : ReportError(CE_Warning, CPLE_AppDefined,
9621 : "All bands should have the same type in "
9622 : "order the NODATA_VALUES metadata item "
9623 : "to be used as a mask.");
9624 : }
9625 : }
9626 : else
9627 : {
9628 2 : ReportError(
9629 : CE_Warning, CPLE_AppDefined,
9630 : "NODATA_VALUES metadata item doesn't have the same number "
9631 : "of values as the number of bands. "
9632 : "Ignoring it for mask.");
9633 : }
9634 :
9635 2 : CSLDestroy(papszGDALNoDataValues);
9636 : }
9637 : }
9638 :
9639 : /* -------------------------------------------------------------------- */
9640 : /* Check for nodata case. */
9641 : /* -------------------------------------------------------------------- */
9642 100819 : if (HasNoData())
9643 : {
9644 1311 : nMaskFlags = GMF_NODATA;
9645 : try
9646 : {
9647 1311 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9648 : }
9649 0 : catch (const std::bad_alloc &)
9650 : {
9651 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9652 0 : poMask.reset();
9653 : }
9654 1311 : return poMask.get();
9655 : }
9656 :
9657 : /* -------------------------------------------------------------------- */
9658 : /* Check for alpha case. */
9659 : /* -------------------------------------------------------------------- */
9660 99489 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9661 199642 : this == poDS->GetRasterBand(1) &&
9662 645 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9663 : {
9664 233 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9665 : {
9666 189 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9667 189 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9668 189 : return poMask.get();
9669 : }
9670 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9671 : {
9672 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9673 : try
9674 : {
9675 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9676 46 : poDS->GetRasterBand(2)));
9677 : }
9678 0 : catch (const std::bad_alloc &)
9679 : {
9680 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9681 0 : poMask.reset();
9682 : }
9683 23 : return poMask.get();
9684 : }
9685 : }
9686 :
9687 99277 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9688 3334 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9689 199357 : this == poDS->GetRasterBand(3)) &&
9690 2587 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9691 : {
9692 1585 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9693 : {
9694 1529 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9695 1529 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9696 1529 : return poMask.get();
9697 : }
9698 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9699 : {
9700 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9701 : try
9702 : {
9703 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9704 84 : poDS->GetRasterBand(4)));
9705 : }
9706 0 : catch (const std::bad_alloc &)
9707 : {
9708 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9709 0 : poMask.reset();
9710 : }
9711 42 : return poMask.get();
9712 : }
9713 : }
9714 :
9715 : /* -------------------------------------------------------------------- */
9716 : /* Fallback to all valid case. */
9717 : /* -------------------------------------------------------------------- */
9718 97725 : nMaskFlags = GMF_ALL_VALID;
9719 : try
9720 : {
9721 97725 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9722 : }
9723 0 : catch (const std::bad_alloc &)
9724 : {
9725 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9726 0 : poMask.reset();
9727 : }
9728 :
9729 97725 : return poMask.get();
9730 : }
9731 :
9732 : /************************************************************************/
9733 : /* GDALGetMaskBand() */
9734 : /************************************************************************/
9735 :
9736 : /**
9737 : * \brief Return the mask band associated with the band.
9738 : *
9739 : * @see GDALRasterBand::GetMaskBand()
9740 : */
9741 :
9742 11056 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9743 :
9744 : {
9745 11056 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9746 :
9747 11056 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9748 11056 : return poBand->GetMaskBand();
9749 : }
9750 :
9751 : /************************************************************************/
9752 : /* GetMaskFlags() */
9753 : /************************************************************************/
9754 :
9755 : /**
9756 : * \brief Return the status flags of the mask band associated with the band.
9757 : *
9758 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9759 : * the following available definitions that may be extended in the future:
9760 : * <ul>
9761 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9762 : * 255. When used this will normally be the only flag set.
9763 : * </li>
9764 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9765 : * dataset.
9766 : * </li>
9767 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9768 : * and may have values other than 0 and 255.
9769 : * </li>
9770 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9771 : * nodata values. (mutually exclusive of GMF_ALPHA)
9772 : * </li>
9773 : * </ul>
9774 : *
9775 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9776 : * that returns one of four default implementations:
9777 : * <ul>
9778 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9779 : * </li>
9780 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9781 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9782 : * GMF_NODATA | GMF_PER_DATASET.
9783 : * </li>
9784 : * <li>If the band has a nodata value set, an instance of the new
9785 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9786 : * GMF_NODATA.
9787 : * </li>
9788 : * <li>If there is no nodata value, but the dataset has an alpha band that
9789 : * seems to apply to this band (specific rules yet to be determined) and that is
9790 : * of type GDT_UInt8 then that alpha band will be returned, and the flags
9791 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9792 : * </li>
9793 : * <li>If neither of the above apply, an instance of the new
9794 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9795 : * pixels. The null flags will return GMF_ALL_VALID.
9796 : * </li>
9797 : * </ul>
9798 : *
9799 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9800 : * dataset, with the same name as the main dataset and suffixed with .msk,
9801 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9802 : * main dataset.
9803 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9804 : * level, where xx matches the band number of a band of the main dataset. The
9805 : * value of those items is a combination of the flags GMF_ALL_VALID,
9806 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9807 : * a band, then the other rules explained above will be used to generate a
9808 : * on-the-fly mask band.
9809 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9810 : *
9811 : * This method is the same as the C function GDALGetMaskFlags().
9812 : *
9813 : *
9814 : * @return a valid mask band.
9815 : *
9816 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9817 : *
9818 : */
9819 183390 : int GDALRasterBand::GetMaskFlags()
9820 :
9821 : {
9822 : // If we don't have a band yet, force this now so that the masks value
9823 : // will be initialized.
9824 :
9825 183390 : if (poMask == nullptr)
9826 99263 : GetMaskBand();
9827 :
9828 183390 : return nMaskFlags;
9829 : }
9830 :
9831 : /************************************************************************/
9832 : /* GDALGetMaskFlags() */
9833 : /************************************************************************/
9834 :
9835 : /**
9836 : * \brief Return the status flags of the mask band associated with the band.
9837 : *
9838 : * @see GDALRasterBand::GetMaskFlags()
9839 : */
9840 :
9841 10119 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9842 :
9843 : {
9844 10119 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9845 :
9846 10119 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9847 10119 : return poBand->GetMaskFlags();
9848 : }
9849 :
9850 : /************************************************************************/
9851 : /* InvalidateMaskBand() */
9852 : /************************************************************************/
9853 :
9854 : //! @cond Doxygen_Suppress
9855 1880580 : void GDALRasterBand::InvalidateMaskBand()
9856 : {
9857 1880580 : poMask.reset();
9858 1880580 : nMaskFlags = 0;
9859 1880580 : }
9860 :
9861 : //! @endcond
9862 :
9863 : /************************************************************************/
9864 : /* CreateMaskBand() */
9865 : /************************************************************************/
9866 :
9867 : /**
9868 : * \brief Adds a mask band to the current band
9869 : *
9870 : * The default implementation of the CreateMaskBand() method is implemented
9871 : * based on similar rules to the .ovr handling implemented using the
9872 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9873 : * be created with the same basename as the original file, and it will have
9874 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9875 : * The mask images will be deflate compressed tiled images with the same
9876 : * block size as the original image if possible.
9877 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9878 : * level, where xx matches the band number of a band of the main dataset. The
9879 : * value of those items will be the one of the nFlagsIn parameter.
9880 : *
9881 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9882 : * it might be invalidated by CreateMaskBand(). So you have to call
9883 : * GetMaskBand() again.
9884 : *
9885 : * This method is the same as the C function GDALCreateMaskBand().
9886 : *
9887 : *
9888 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9889 : *
9890 : * @return CE_None on success or CE_Failure on an error.
9891 : *
9892 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9893 : * @see GDALDataset::CreateMaskBand()
9894 : *
9895 : */
9896 :
9897 11 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9898 :
9899 : {
9900 11 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9901 : {
9902 11 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9903 11 : if (eErr != CE_None)
9904 1 : return eErr;
9905 :
9906 10 : InvalidateMaskBand();
9907 :
9908 10 : return CE_None;
9909 : }
9910 :
9911 0 : ReportError(CE_Failure, CPLE_NotSupported,
9912 : "CreateMaskBand() not supported for this band.");
9913 :
9914 0 : return CE_Failure;
9915 : }
9916 :
9917 : /************************************************************************/
9918 : /* GDALCreateMaskBand() */
9919 : /************************************************************************/
9920 :
9921 : /**
9922 : * \brief Adds a mask band to the current band
9923 : *
9924 : * @see GDALRasterBand::CreateMaskBand()
9925 : */
9926 :
9927 37 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9928 :
9929 : {
9930 37 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9931 :
9932 37 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9933 37 : return poBand->CreateMaskBand(nFlags);
9934 : }
9935 :
9936 : /************************************************************************/
9937 : /* IsMaskBand() */
9938 : /************************************************************************/
9939 :
9940 : /**
9941 : * \brief Returns whether a band is a mask band.
9942 : *
9943 : * Mask band must be understood in the broad term: it can be a per-dataset
9944 : * mask band, an alpha band, or an implicit mask band.
9945 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9946 : *
9947 : * This method is the same as the C function GDALIsMaskBand().
9948 : *
9949 : * @return true if the band is a mask band.
9950 : *
9951 : * @see GDALDataset::CreateMaskBand()
9952 : *
9953 : * @since GDAL 3.5.0
9954 : *
9955 : */
9956 :
9957 306 : bool GDALRasterBand::IsMaskBand() const
9958 : {
9959 : // The GeoTIFF driver, among others, override this method to
9960 : // also handle external .msk bands.
9961 306 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9962 306 : GCI_AlphaBand;
9963 : }
9964 :
9965 : /************************************************************************/
9966 : /* GDALIsMaskBand() */
9967 : /************************************************************************/
9968 :
9969 : /**
9970 : * \brief Returns whether a band is a mask band.
9971 : *
9972 : * Mask band must be understood in the broad term: it can be a per-dataset
9973 : * mask band, an alpha band, or an implicit mask band.
9974 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9975 : *
9976 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9977 : *
9978 : * @return true if the band is a mask band.
9979 : *
9980 : * @see GDALRasterBand::IsMaskBand()
9981 : *
9982 : * @since GDAL 3.5.0
9983 : *
9984 : */
9985 :
9986 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9987 :
9988 : {
9989 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9990 :
9991 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9992 37 : return poBand->IsMaskBand();
9993 : }
9994 :
9995 : /************************************************************************/
9996 : /* GetMaskValueRange() */
9997 : /************************************************************************/
9998 :
9999 : /**
10000 : * \brief Returns the range of values that a mask band can take.
10001 : *
10002 : * @return the range of values that a mask band can take.
10003 : *
10004 : * @since GDAL 3.5.0
10005 : *
10006 : */
10007 :
10008 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
10009 : {
10010 0 : return GMVR_UNKNOWN;
10011 : }
10012 :
10013 : /************************************************************************/
10014 : /* HasConflictingMaskSources() */
10015 : /************************************************************************/
10016 :
10017 : /**
10018 : * \brief Returns whether a raster band has conflicting mask sources.
10019 : *
10020 : * That is, if more than one of the following conditions is met:
10021 : * - it has a binary mask band (that is not an alpha band)
10022 : * - it has an external mask flags (.msk file)
10023 : * - it has a nodata value
10024 : * - it belongs to a dataset with the NODATA_VALUES metadata item set
10025 : * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
10026 : *
10027 : * @param[out] posDetailMessage Pointer to a string that will contain the
10028 : * details of the conflict.
10029 : * @param bMentionPrioritarySource Whether the mask source used should be
10030 : * mentioned in *posDetailMessage.
10031 : * @since GDAL 3.13.0
10032 : */
10033 :
10034 125 : bool GDALRasterBand::HasConflictingMaskSources(
10035 : std::string *posDetailMessage, bool bMentionPrioritarySource) const
10036 : {
10037 125 : const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
10038 : const bool bHasBinaryMaskBand =
10039 125 : ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
10040 147 : (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
10041 22 : (!bHasExternalMask ||
10042 1 : (poDS && poDS->oOvManager.GetMaskBand(nBand) != this));
10043 125 : const bool bHasNoData = HasNoData();
10044 : const bool bHasNODATA_VALUES =
10045 125 : poDS && poDS->GetMetadataItem("NODATA_VALUES");
10046 : const bool bHasAlphaBand =
10047 246 : poDS &&
10048 121 : poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
10049 125 : GCI_AlphaBand;
10050 : const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
10051 125 : bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
10052 : const size_t nCount =
10053 125 : std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
10054 125 : if (nCount >= 2)
10055 : {
10056 23 : if (posDetailMessage)
10057 : {
10058 17 : *posDetailMessage = "Raster band ";
10059 17 : *posDetailMessage += std::to_string(nBand);
10060 17 : if (poDS && poDS->GetDescription()[0])
10061 : {
10062 11 : *posDetailMessage += " of dataset ";
10063 11 : *posDetailMessage += poDS->GetDescription();
10064 : }
10065 17 : *posDetailMessage += " has several conflicting mask sources:\n";
10066 17 : if (bHasBinaryMaskBand)
10067 4 : *posDetailMessage += "- internal binary mask band\n";
10068 17 : if (bHasExternalMask)
10069 1 : *posDetailMessage += "- external mask band (.msk)\n";
10070 17 : if (bHasNoData)
10071 13 : *posDetailMessage += "- nodata value\n";
10072 17 : if (bHasNODATA_VALUES)
10073 9 : *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
10074 17 : if (bHasAlphaBand)
10075 : *posDetailMessage +=
10076 7 : "- related to a raster band that is an alpha band\n";
10077 17 : if (bMentionPrioritarySource)
10078 : *posDetailMessage +=
10079 6 : "Only the first listed one will be taken into account.";
10080 : }
10081 23 : return true;
10082 : }
10083 102 : return false;
10084 : }
10085 :
10086 : /************************************************************************/
10087 : /* GetIndexColorTranslationTo() */
10088 : /************************************************************************/
10089 :
10090 : /**
10091 : * \brief Compute translation table for color tables.
10092 : *
10093 : * When the raster band has a palette index, it may be useful to compute
10094 : * the "translation" of this palette to the palette of another band.
10095 : * The translation tries to do exact matching first, and then approximate
10096 : * matching if no exact matching is possible.
10097 : * This method returns a table such that table[i] = j where i is an index
10098 : * of the 'this' rasterband and j the corresponding index for the reference
10099 : * rasterband.
10100 : *
10101 : * This method is thought as internal to GDAL and is used for drivers
10102 : * like RPFTOC.
10103 : *
10104 : * The implementation only supports 1-byte palette rasterbands.
10105 : *
10106 : * @param poReferenceBand the raster band
10107 : * @param pTranslationTable an already allocated translation table (at least 256
10108 : * bytes), or NULL to let the method allocate it
10109 : * @param pApproximateMatching a pointer to a flag that is set if the matching
10110 : * is approximate. May be NULL.
10111 : *
10112 : * @return a translation table if the two bands are palette index and that they
10113 : * do not match or NULL in other cases. The table must be freed with CPLFree if
10114 : * NULL was passed for pTranslationTable.
10115 : */
10116 :
10117 : unsigned char *
10118 5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
10119 : unsigned char *pTranslationTable,
10120 : int *pApproximateMatching)
10121 : {
10122 5 : if (poReferenceBand == nullptr)
10123 0 : return nullptr;
10124 :
10125 : // cppcheck-suppress knownConditionTrueFalse
10126 5 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
10127 : // cppcheck-suppress knownConditionTrueFalse
10128 5 : GetColorInterpretation() == GCI_PaletteIndex &&
10129 15 : poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
10130 5 : GetRasterDataType() == GDT_UInt8)
10131 : {
10132 5 : const GDALColorTable *srcColorTable = GetColorTable();
10133 5 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
10134 5 : if (srcColorTable != nullptr && destColorTable != nullptr)
10135 : {
10136 5 : const int nEntries = srcColorTable->GetColorEntryCount();
10137 5 : const int nRefEntries = destColorTable->GetColorEntryCount();
10138 :
10139 5 : int bHasNoDataValueSrc = FALSE;
10140 5 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
10141 5 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
10142 5 : dfNoDataValueSrc <= 255 &&
10143 5 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
10144 0 : bHasNoDataValueSrc = FALSE;
10145 5 : const int noDataValueSrc =
10146 5 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10147 :
10148 5 : int bHasNoDataValueRef = FALSE;
10149 : const double dfNoDataValueRef =
10150 5 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10151 5 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10152 4 : dfNoDataValueRef <= 255 &&
10153 4 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10154 1 : bHasNoDataValueRef = FALSE;
10155 5 : const int noDataValueRef =
10156 5 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10157 :
10158 5 : bool samePalette = false;
10159 :
10160 5 : if (pApproximateMatching)
10161 4 : *pApproximateMatching = FALSE;
10162 :
10163 5 : if (nEntries == nRefEntries &&
10164 4 : bHasNoDataValueSrc == bHasNoDataValueRef &&
10165 4 : (bHasNoDataValueSrc == FALSE ||
10166 : noDataValueSrc == noDataValueRef))
10167 : {
10168 4 : samePalette = true;
10169 872 : for (int i = 0; i < nEntries; ++i)
10170 : {
10171 868 : if (noDataValueSrc == i)
10172 4 : continue;
10173 : const GDALColorEntry *entry =
10174 864 : srcColorTable->GetColorEntry(i);
10175 : const GDALColorEntry *entryRef =
10176 864 : destColorTable->GetColorEntry(i);
10177 864 : if (entry->c1 != entryRef->c1 ||
10178 864 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10179 : {
10180 0 : samePalette = false;
10181 : }
10182 : }
10183 : }
10184 :
10185 5 : if (!samePalette)
10186 : {
10187 1 : if (pTranslationTable == nullptr)
10188 : {
10189 : pTranslationTable = static_cast<unsigned char *>(
10190 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10191 1 : if (pTranslationTable == nullptr)
10192 1 : return nullptr;
10193 : }
10194 :
10195 : // Trying to remap the product palette on the subdataset
10196 : // palette.
10197 5 : for (int i = 0; i < nEntries; ++i)
10198 : {
10199 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10200 : noDataValueSrc == i)
10201 0 : continue;
10202 : const GDALColorEntry *entry =
10203 4 : srcColorTable->GetColorEntry(i);
10204 4 : bool bMatchFound = false;
10205 13 : for (int j = 0; j < nRefEntries; ++j)
10206 : {
10207 10 : if (bHasNoDataValueRef && noDataValueRef == j)
10208 0 : continue;
10209 : const GDALColorEntry *entryRef =
10210 10 : destColorTable->GetColorEntry(j);
10211 10 : if (entry->c1 == entryRef->c1 &&
10212 2 : entry->c2 == entryRef->c2 &&
10213 2 : entry->c3 == entryRef->c3)
10214 : {
10215 1 : pTranslationTable[i] =
10216 : static_cast<unsigned char>(j);
10217 1 : bMatchFound = true;
10218 1 : break;
10219 : }
10220 : }
10221 4 : if (!bMatchFound)
10222 : {
10223 : // No exact match. Looking for closest color now.
10224 3 : int best_j = 0;
10225 3 : int best_distance = 0;
10226 3 : if (pApproximateMatching)
10227 0 : *pApproximateMatching = TRUE;
10228 12 : for (int j = 0; j < nRefEntries; ++j)
10229 : {
10230 : const GDALColorEntry *entryRef =
10231 9 : destColorTable->GetColorEntry(j);
10232 9 : int distance = (entry->c1 - entryRef->c1) *
10233 9 : (entry->c1 - entryRef->c1) +
10234 9 : (entry->c2 - entryRef->c2) *
10235 9 : (entry->c2 - entryRef->c2) +
10236 9 : (entry->c3 - entryRef->c3) *
10237 9 : (entry->c3 - entryRef->c3);
10238 9 : if (j == 0 || distance < best_distance)
10239 : {
10240 7 : best_j = j;
10241 7 : best_distance = distance;
10242 : }
10243 : }
10244 3 : pTranslationTable[i] =
10245 : static_cast<unsigned char>(best_j);
10246 : }
10247 : }
10248 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
10249 0 : pTranslationTable[noDataValueSrc] =
10250 : static_cast<unsigned char>(noDataValueRef);
10251 :
10252 1 : return pTranslationTable;
10253 : }
10254 : }
10255 : }
10256 4 : return nullptr;
10257 : }
10258 :
10259 : /************************************************************************/
10260 : /* SetFlushBlockErr() */
10261 : /************************************************************************/
10262 :
10263 : /**
10264 : * \brief Store that an error occurred while writing a dirty block.
10265 : *
10266 : * This function stores the fact that an error occurred while writing a dirty
10267 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10268 : * flushed when the block cache get full, it is not convenient/possible to
10269 : * report that a dirty block could not be written correctly. This function
10270 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10271 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10272 : * places where the user can easily match the error with the relevant dataset.
10273 : */
10274 :
10275 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10276 : {
10277 0 : eFlushBlockErr = eErr;
10278 0 : }
10279 :
10280 : /************************************************************************/
10281 : /* IncDirtyBlocks() */
10282 : /************************************************************************/
10283 :
10284 : /**
10285 : * \brief Increment/decrement the number of dirty blocks
10286 : */
10287 :
10288 838800 : void GDALRasterBand::IncDirtyBlocks(int nInc)
10289 : {
10290 838800 : if (poBandBlockCache)
10291 838800 : poBandBlockCache->IncDirtyBlocks(nInc);
10292 838800 : }
10293 :
10294 : /************************************************************************/
10295 : /* ReportError() */
10296 : /************************************************************************/
10297 :
10298 : #ifndef DOXYGEN_XML
10299 : /**
10300 : * \brief Emits an error related to a raster band.
10301 : *
10302 : * This function is a wrapper for regular CPLError(). The only difference
10303 : * with CPLError() is that it prepends the error message with the dataset
10304 : * name and the band number.
10305 : *
10306 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10307 : * @param err_no the error number (CPLE_*) from cpl_error.h.
10308 : * @param fmt a printf() style format string. Any additional arguments
10309 : * will be treated as arguments to fill in this format in a manner
10310 : * similar to printf().
10311 : *
10312 : */
10313 :
10314 2505 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10315 : const char *fmt, ...) const
10316 : {
10317 : va_list args;
10318 :
10319 2505 : va_start(args, fmt);
10320 :
10321 2505 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
10322 2505 : pszDSName = CPLGetFilename(pszDSName);
10323 2505 : if (pszDSName[0] != '\0')
10324 : {
10325 2408 : CPLError(eErrClass, err_no, "%s",
10326 4816 : CPLString()
10327 2408 : .Printf("%s, band %d: ", pszDSName, GetBand())
10328 4816 : .append(CPLString().vPrintf(fmt, args))
10329 : .c_str());
10330 : }
10331 : else
10332 : {
10333 97 : CPLErrorV(eErrClass, err_no, fmt, args);
10334 : }
10335 :
10336 2505 : va_end(args);
10337 2505 : }
10338 : #endif
10339 :
10340 : /************************************************************************/
10341 : /* GetVirtualMemAuto() */
10342 : /************************************************************************/
10343 :
10344 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10345 : *
10346 : * Only supported on Linux and Unix systems with mmap() for now.
10347 : *
10348 : * This method allows creating a virtual memory object for a GDALRasterBand,
10349 : * that exposes the whole image data as a virtual array.
10350 : *
10351 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10352 : * specialized implementation, such as for raw files, may also directly use
10353 : * mechanisms of the operating system to create a view of the underlying file
10354 : * into virtual memory ( CPLVirtualMemFileMapNew() )
10355 : *
10356 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10357 : * offer a specialized implementation with direct file mapping, provided that
10358 : * some requirements are met :
10359 : * - for all drivers, the dataset must be backed by a "real" file in the file
10360 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10361 : * must match the native ordering of the CPU.
10362 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10363 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10364 : * the file in sequential order, and be equally spaced (which is generally the
10365 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10366 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10367 : *
10368 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
10369 : * CPLVirtualMemFree() must be called before the raster band object is
10370 : * destroyed.
10371 : *
10372 : * If p is such a pointer and base_type the type matching
10373 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10374 : * accessed with
10375 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10376 : *
10377 : * This method is the same as the C GDALGetVirtualMemAuto() function.
10378 : *
10379 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10380 : * read/write the band.
10381 : *
10382 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
10383 : * one pixel value in the buffer to the start of the next pixel value within a
10384 : * scanline.
10385 : *
10386 : * @param pnLineSpace Output parameter giving the byte offset from the start of
10387 : * one scanline in the buffer to the start of the next.
10388 : *
10389 : * @param papszOptions NULL terminated list of options.
10390 : * If a specialized implementation exists, defining
10391 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10392 : * used. On the contrary, defining
10393 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10394 : * being used (thus only allowing efficient implementations to be used). When
10395 : * requiring or falling back to the default implementation, the following
10396 : * options are available : CACHE_SIZE (in bytes, defaults to
10397 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10398 : * to FALSE)
10399 : *
10400 : * @return a virtual memory object that must be unreferenced by
10401 : * CPLVirtualMemFree(), or NULL in case of failure.
10402 : *
10403 : */
10404 :
10405 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10406 : int *pnPixelSpace,
10407 : GIntBig *pnLineSpace,
10408 : CSLConstList papszOptions)
10409 : {
10410 9 : const char *pszImpl = CSLFetchNameValueDef(
10411 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10412 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10413 8 : EQUAL(pszImpl, "FALSE"))
10414 : {
10415 1 : return nullptr;
10416 : }
10417 :
10418 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10419 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10420 8 : if (pnPixelSpace)
10421 8 : *pnPixelSpace = nPixelSpace;
10422 8 : if (pnLineSpace)
10423 8 : *pnLineSpace = nLineSpace;
10424 : const size_t nCacheSize =
10425 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10426 : const size_t nPageSizeHint =
10427 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10428 8 : const bool bSingleThreadUsage = CPLTestBool(
10429 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10430 8 : return GDALRasterBandGetVirtualMem(
10431 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10432 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10433 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10434 8 : papszOptions);
10435 : }
10436 :
10437 : /************************************************************************/
10438 : /* GDALGetVirtualMemAuto() */
10439 : /************************************************************************/
10440 :
10441 : /**
10442 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10443 : *
10444 : * @see GDALRasterBand::GetVirtualMemAuto()
10445 : */
10446 :
10447 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10448 : int *pnPixelSpace, GIntBig *pnLineSpace,
10449 : CSLConstList papszOptions)
10450 : {
10451 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10452 :
10453 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10454 :
10455 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10456 31 : const_cast<char **>(papszOptions));
10457 : }
10458 :
10459 : /************************************************************************/
10460 : /* GDALGetDataCoverageStatus() */
10461 : /************************************************************************/
10462 :
10463 : /**
10464 : * \brief Get the coverage status of a sub-window of the raster.
10465 : *
10466 : * Returns whether a sub-window of the raster contains only data, only empty
10467 : * blocks or a mix of both. This function can be used to determine quickly
10468 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10469 : * be sparse.
10470 : *
10471 : * Empty blocks are blocks that are generally not physically present in the
10472 : * file, and when read through GDAL, contain only pixels whose value is the
10473 : * nodata value when it is set, or whose value is 0 when the nodata value is
10474 : * not set.
10475 : *
10476 : * The query is done in an efficient way without reading the actual pixel
10477 : * values. If not possible, or not implemented at all by the driver,
10478 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10479 : * be returned.
10480 : *
10481 : * The values that can be returned by the function are the following,
10482 : * potentially combined with the binary or operator :
10483 : * <ul>
10484 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10485 : * GetDataCoverageStatus(). This flag should be returned together with
10486 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10487 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10488 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10489 : * the queried window. This is typically identified by the concept of missing
10490 : * block in formats that supports it.
10491 : * </li>
10492 : * </ul>
10493 : *
10494 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10495 : * should be interpreted more as hint of potential presence of data. For example
10496 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10497 : * nodata value), instead of using the missing block mechanism,
10498 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10499 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10500 : *
10501 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10502 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10503 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10504 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10505 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10506 : * the function will exit, so that you can potentially refine the requested area
10507 : * to find which particular region(s) have missing blocks.
10508 : *
10509 : * @see GDALRasterBand::GetDataCoverageStatus()
10510 : *
10511 : * @param hBand raster band
10512 : *
10513 : * @param nXOff The pixel offset to the top left corner of the region
10514 : * of the band to be queried. This would be zero to start from the left side.
10515 : *
10516 : * @param nYOff The line offset to the top left corner of the region
10517 : * of the band to be queried. This would be zero to start from the top.
10518 : *
10519 : * @param nXSize The width of the region of the band to be queried in pixels.
10520 : *
10521 : * @param nYSize The height of the region of the band to be queried in lines.
10522 : *
10523 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10524 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10525 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10526 : * as the computation of the coverage matches the mask, the computation will be
10527 : * stopped. *pdfDataPct will not be valid in that case.
10528 : *
10529 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10530 : * to the (approximate) percentage in [0,100] of pixels in the queried
10531 : * sub-window that have valid values. The implementation might not always be
10532 : * able to compute it, in which case it will be set to a negative value.
10533 : *
10534 : * @return a binary-or'ed combination of possible values
10535 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10536 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10537 : */
10538 :
10539 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10540 : int nYOff, int nXSize, int nYSize,
10541 : int nMaskFlagStop, double *pdfDataPct)
10542 : {
10543 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10544 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10545 :
10546 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10547 :
10548 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10549 29 : nMaskFlagStop, pdfDataPct);
10550 : }
10551 :
10552 : /************************************************************************/
10553 : /* GetDataCoverageStatus() */
10554 : /************************************************************************/
10555 :
10556 : /**
10557 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10558 : * int nYOff,
10559 : * int nXSize,
10560 : * int nYSize,
10561 : * int nMaskFlagStop,
10562 : * double* pdfDataPct)
10563 : * \brief Get the coverage status of a sub-window of the raster.
10564 : *
10565 : * Returns whether a sub-window of the raster contains only data, only empty
10566 : * blocks or a mix of both. This function can be used to determine quickly
10567 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10568 : * be sparse.
10569 : *
10570 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10571 : * value when it is set, or whose value is 0 when the nodata value is not set.
10572 : *
10573 : * The query is done in an efficient way without reading the actual pixel
10574 : * values. If not possible, or not implemented at all by the driver,
10575 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10576 : * be returned.
10577 : *
10578 : * The values that can be returned by the function are the following,
10579 : * potentially combined with the binary or operator :
10580 : * <ul>
10581 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10582 : * GetDataCoverageStatus(). This flag should be returned together with
10583 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10584 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10585 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10586 : * the queried window. This is typically identified by the concept of missing
10587 : * block in formats that supports it.
10588 : * </li>
10589 : * </ul>
10590 : *
10591 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10592 : * should be interpreted more as hint of potential presence of data. For example
10593 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10594 : * nodata value), instead of using the missing block mechanism,
10595 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10596 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10597 : *
10598 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10599 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10600 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10601 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10602 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10603 : * the function will exit, so that you can potentially refine the requested area
10604 : * to find which particular region(s) have missing blocks.
10605 : *
10606 : * @see GDALGetDataCoverageStatus()
10607 : *
10608 : * @param nXOff The pixel offset to the top left corner of the region
10609 : * of the band to be queried. This would be zero to start from the left side.
10610 : *
10611 : * @param nYOff The line offset to the top left corner of the region
10612 : * of the band to be queried. This would be zero to start from the top.
10613 : *
10614 : * @param nXSize The width of the region of the band to be queried in pixels.
10615 : *
10616 : * @param nYSize The height of the region of the band to be queried in lines.
10617 : *
10618 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10619 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10620 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10621 : * as the computation of the coverage matches the mask, the computation will be
10622 : * stopped. *pdfDataPct will not be valid in that case.
10623 : *
10624 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10625 : * to the (approximate) percentage in [0,100] of pixels in the queried
10626 : * sub-window that have valid values. The implementation might not always be
10627 : * able to compute it, in which case it will be set to a negative value.
10628 : *
10629 : * @return a binary-or'ed combination of possible values
10630 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10631 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10632 : */
10633 :
10634 : /**
10635 : * \brief Get the coverage status of a sub-window of the raster.
10636 : *
10637 : * Returns whether a sub-window of the raster contains only data, only empty
10638 : * blocks or a mix of both. This function can be used to determine quickly
10639 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10640 : * be sparse.
10641 : *
10642 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10643 : * value when it is set, or whose value is 0 when the nodata value is not set.
10644 : *
10645 : * The query is done in an efficient way without reading the actual pixel
10646 : * values. If not possible, or not implemented at all by the driver,
10647 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10648 : * be returned.
10649 : *
10650 : * The values that can be returned by the function are the following,
10651 : * potentially combined with the binary or operator :
10652 : * <ul>
10653 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10654 : * GetDataCoverageStatus(). This flag should be returned together with
10655 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10656 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10657 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10658 : * the queried window. This is typically identified by the concept of missing
10659 : * block in formats that supports it.
10660 : * </li>
10661 : * </ul>
10662 : *
10663 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10664 : * should be interpreted more as hint of potential presence of data. For example
10665 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10666 : * nodata value), instead of using the missing block mechanism,
10667 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10668 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10669 : *
10670 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10671 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10672 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10673 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10674 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10675 : * the function will exit, so that you can potentially refine the requested area
10676 : * to find which particular region(s) have missing blocks.
10677 : *
10678 : * @see GDALGetDataCoverageStatus()
10679 : *
10680 : * @param nXOff The pixel offset to the top left corner of the region
10681 : * of the band to be queried. This would be zero to start from the left side.
10682 : *
10683 : * @param nYOff The line offset to the top left corner of the region
10684 : * of the band to be queried. This would be zero to start from the top.
10685 : *
10686 : * @param nXSize The width of the region of the band to be queried in pixels.
10687 : *
10688 : * @param nYSize The height of the region of the band to be queried in lines.
10689 : *
10690 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10691 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10692 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10693 : * as the computation of the coverage matches the mask, the computation will be
10694 : * stopped. *pdfDataPct will not be valid in that case.
10695 : *
10696 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10697 : * to the (approximate) percentage in [0,100] of pixels in the queried
10698 : * sub-window that have valid values. The implementation might not always be
10699 : * able to compute it, in which case it will be set to a negative value.
10700 : *
10701 : * @return a binary-or'ed combination of possible values
10702 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10703 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10704 : */
10705 :
10706 4792 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10707 : int nYSize, int nMaskFlagStop,
10708 : double *pdfDataPct)
10709 : {
10710 4792 : if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10711 4792 : nYSize > nRasterYSize - nYOff)
10712 : {
10713 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10714 0 : if (pdfDataPct)
10715 0 : *pdfDataPct = 0.0;
10716 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10717 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10718 : }
10719 4792 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10720 4792 : pdfDataPct);
10721 : }
10722 :
10723 : /************************************************************************/
10724 : /* IGetDataCoverageStatus() */
10725 : /************************************************************************/
10726 :
10727 698 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10728 : int /*nXSize*/, int /*nYSize*/,
10729 : int /*nMaskFlagStop*/,
10730 : double *pdfDataPct)
10731 : {
10732 698 : if (pdfDataPct != nullptr)
10733 0 : *pdfDataPct = 100.0;
10734 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10735 698 : GDAL_DATA_COVERAGE_STATUS_DATA;
10736 : }
10737 :
10738 : //! @cond Doxygen_Suppress
10739 : /************************************************************************/
10740 : /* EnterReadWrite() */
10741 : /************************************************************************/
10742 :
10743 8095360 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10744 : {
10745 8095360 : if (poDS != nullptr)
10746 7325110 : return poDS->EnterReadWrite(eRWFlag);
10747 770245 : return FALSE;
10748 : }
10749 :
10750 : /************************************************************************/
10751 : /* LeaveReadWrite() */
10752 : /************************************************************************/
10753 :
10754 1150100 : void GDALRasterBand::LeaveReadWrite()
10755 : {
10756 1150100 : if (poDS != nullptr)
10757 1150100 : poDS->LeaveReadWrite();
10758 1150100 : }
10759 :
10760 : /************************************************************************/
10761 : /* InitRWLock() */
10762 : /************************************************************************/
10763 :
10764 4001460 : void GDALRasterBand::InitRWLock()
10765 : {
10766 4001460 : if (poDS != nullptr)
10767 4001050 : poDS->InitRWLock();
10768 4001460 : }
10769 :
10770 : //! @endcond
10771 :
10772 : // clang-format off
10773 :
10774 : /**
10775 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10776 : * \brief Set metadata.
10777 : *
10778 : * CAUTION: depending on the format, older values of the updated information
10779 : * might still be found in the file in a "ghost" state, even if no longer
10780 : * accessible through the GDAL API. This is for example the case of the GTiff
10781 : * format (this is not a exhaustive list)
10782 : *
10783 : * The C function GDALSetMetadata() does the same thing as this method.
10784 : *
10785 : * @param papszMetadata the metadata in name=value string list format to
10786 : * apply.
10787 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10788 : * domain.
10789 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10790 : * metadata has been accepted, but is likely not maintained persistently
10791 : * by the underlying object between sessions.
10792 : */
10793 :
10794 : /**
10795 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10796 : * \brief Set single metadata item.
10797 : *
10798 : * CAUTION: depending on the format, older values of the updated information
10799 : * might still be found in the file in a "ghost" state, even if no longer
10800 : * accessible through the GDAL API. This is for example the case of the GTiff
10801 : * format (this is not a exhaustive list)
10802 : *
10803 : * The C function GDALSetMetadataItem() does the same thing as this method.
10804 : *
10805 : * @param pszName the key for the metadata item to fetch.
10806 : * @param pszValue the value to assign to the key.
10807 : * @param pszDomain the domain to set within, use NULL for the default domain.
10808 : *
10809 : * @return CE_None on success, or an error code on failure.
10810 : */
10811 :
10812 : // clang-format on
10813 :
10814 : //! @cond Doxygen_Suppress
10815 : /************************************************************************/
10816 : /* EnablePixelTypeSignedByteWarning() */
10817 : /************************************************************************/
10818 :
10819 158055 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10820 : {
10821 158055 : m_bEnablePixelTypeSignedByteWarning = b;
10822 158055 : }
10823 :
10824 4882 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10825 : {
10826 4882 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10827 4882 : }
10828 :
10829 : //! @endcond
10830 :
10831 : /************************************************************************/
10832 : /* GetMetadataItem() */
10833 : /************************************************************************/
10834 :
10835 639919 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10836 : const char *pszDomain)
10837 : {
10838 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10839 639919 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10840 480750 : pszDomain != nullptr && EQUAL(pszDomain, GDAL_MDD_IMAGE_STRUCTURE) &&
10841 339884 : EQUAL(pszName, "PIXELTYPE"))
10842 : {
10843 2 : CPLError(CE_Warning, CPLE_AppDefined,
10844 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10845 : "used to signal signed 8-bit raster. Change your code to "
10846 : "test for the new GDT_Int8 data type instead.");
10847 : }
10848 639919 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10849 : }
10850 :
10851 : /************************************************************************/
10852 : /* GDALRasterBandAsMDArray() */
10853 : /************************************************************************/
10854 :
10855 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10856 : *
10857 : * The band must be linked to a GDALDataset. If this dataset is not already
10858 : * marked as shared, it will be, so that the returned array holds a reference
10859 : * to it.
10860 : *
10861 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10862 : * returned array will have an associated indexing variable.
10863 : *
10864 : * The returned pointer must be released with GDALMDArrayRelease().
10865 : *
10866 : * This is the same as the C++ method GDALRasterBand::AsMDArray().
10867 : *
10868 : * @return a new array, or NULL.
10869 : *
10870 : * @since GDAL 3.1
10871 : */
10872 25 : GDALMDArrayH GDALRasterBandAsMDArray(GDALRasterBandH hBand)
10873 : {
10874 25 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10875 50 : auto poArray(GDALRasterBand::FromHandle(hBand)->AsMDArray());
10876 25 : if (!poArray)
10877 0 : return nullptr;
10878 25 : return new GDALMDArrayHS(poArray);
10879 : }
10880 :
10881 : /************************************************************************/
10882 : /* WindowIterator */
10883 : /************************************************************************/
10884 :
10885 : //! @cond Doxygen_Suppress
10886 :
10887 718 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10888 : int nRasterYSize,
10889 : int nBlockXSize, int nBlockYSize,
10890 718 : int nRow, int nCol)
10891 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10892 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10893 718 : m_col(nCol)
10894 : {
10895 718 : }
10896 :
10897 784 : bool GDALRasterBand::WindowIterator::operator==(
10898 : const WindowIterator &other) const
10899 : {
10900 331 : return m_row == other.m_row && m_col == other.m_col &&
10901 331 : m_nRasterXSize == other.m_nRasterXSize &&
10902 331 : m_nRasterYSize == other.m_nRasterYSize &&
10903 1446 : m_nBlockXSize == other.m_nBlockXSize &&
10904 1115 : m_nBlockYSize == other.m_nBlockYSize;
10905 : }
10906 :
10907 743 : bool GDALRasterBand::WindowIterator::operator!=(
10908 : const WindowIterator &other) const
10909 : {
10910 743 : return !(*this == other);
10911 : }
10912 :
10913 : GDALRasterBand::WindowIterator::value_type
10914 452 : GDALRasterBand::WindowIterator::operator*() const
10915 : {
10916 : GDALRasterWindow ret;
10917 452 : ret.nXOff = m_col * m_nBlockXSize;
10918 452 : ret.nYOff = m_row * m_nBlockYSize;
10919 452 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10920 452 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10921 :
10922 452 : return ret;
10923 : }
10924 :
10925 443 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10926 : {
10927 443 : m_col++;
10928 443 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10929 : {
10930 345 : m_col = 0;
10931 345 : m_row++;
10932 : }
10933 443 : return *this;
10934 : }
10935 :
10936 173 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10937 173 : const GDALRasterBand &band, size_t maxSize)
10938 173 : : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10939 173 : band.nBlockYSize, maxSize)
10940 : {
10941 173 : }
10942 :
10943 203 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10944 203 : const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10945 203 : : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10946 203 : std::min(band1.GetYSize(), band2.GetYSize()),
10947 203 : std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10948 203 : std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10949 609 : maxSize)
10950 : {
10951 406 : if (band1.GetXSize() != band2.GetXSize() ||
10952 203 : band1.GetYSize() != band2.GetYSize())
10953 : {
10954 0 : CPLError(CE_Warning, CPLE_AppDefined,
10955 : "WindowIteratorWrapper called on bands of different "
10956 : "dimensions. Selecting smallest one");
10957 : }
10958 203 : }
10959 :
10960 376 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10961 : int nRasterYSize,
10962 : int nBlockXSize,
10963 : int nBlockYSize,
10964 376 : size_t maxSize)
10965 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10966 376 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10967 : {
10968 : #ifdef CSA_BUILD
10969 : assert(this);
10970 : #endif
10971 376 : int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10972 376 : int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10973 :
10974 376 : if (nXSize < 1 || nYSize < 1)
10975 : {
10976 : // If invalid block size is reported, assume scanlines
10977 8 : nXSize = m_nRasterXSize;
10978 8 : nYSize = 1;
10979 : }
10980 :
10981 376 : if (maxSize == 0)
10982 : {
10983 73 : m_nBlockXSize = nXSize;
10984 73 : m_nBlockYSize = nYSize;
10985 73 : return;
10986 : }
10987 :
10988 303 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10989 303 : const double dfBlocksPerChunk =
10990 303 : static_cast<double>(maxSize) /
10991 303 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10992 :
10993 303 : if (dfBlocksPerChunk < dfBlocksPerRow)
10994 : {
10995 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10996 14 : m_nRasterXSize,
10997 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10998 14 : m_nBlockYSize = nYSize;
10999 : }
11000 : else
11001 : {
11002 289 : m_nBlockXSize = m_nRasterXSize;
11003 289 : m_nBlockYSize = static_cast<int>(std::min<double>(
11004 289 : m_nRasterYSize,
11005 289 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
11006 : }
11007 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
11008 : {
11009 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
11010 : {
11011 : m_nBlockXSize = m_nRasterXSize;
11012 : m_nBlockYSize = 1;
11013 : }
11014 : }
11015 : }
11016 :
11017 : GDALRasterBand::WindowIterator
11018 343 : GDALRasterBand::WindowIteratorWrapper::begin() const
11019 : {
11020 343 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
11021 343 : m_nBlockYSize, 0, 0);
11022 : }
11023 :
11024 : GDALRasterBand::WindowIterator
11025 343 : GDALRasterBand::WindowIteratorWrapper::end() const
11026 : {
11027 343 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
11028 343 : m_nBlockYSize,
11029 343 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
11030 : }
11031 :
11032 69 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
11033 : {
11034 69 : return static_cast<uint64_t>(
11035 69 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
11036 69 : static_cast<uint64_t>(
11037 69 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
11038 : }
11039 :
11040 : //! @endcond
11041 :
11042 : /** Return an object whose begin() and end() methods can be used to iterate
11043 : * over GDALRasterWindow objects that are aligned with blocks in this raster
11044 : * band. The iteration order is from left to right, then from top to bottom.
11045 : *
11046 : \code{.cpp}
11047 : std::vector<double> pixelValues;
11048 : for (const auto& window : poBand->IterateWindows()) {
11049 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
11050 : window.nXSize, window.nYSize);
11051 : // check eErr
11052 : }
11053 : \endcode
11054 : *
11055 : *
11056 : * @param maxSize The maximum number of pixels in each window. If set to
11057 : * zero (the default), or a number smaller than the block size,
11058 : * the window size will be the same as the block size.
11059 : * @since GDAL 3.12
11060 : */
11061 : GDALRasterBand::WindowIteratorWrapper
11062 173 : GDALRasterBand::IterateWindows(size_t maxSize) const
11063 : {
11064 173 : return WindowIteratorWrapper(*this, maxSize);
11065 : }
11066 :
11067 : /************************************************************************/
11068 : /* MayMultiBlockReadingBeMultiThreaded() */
11069 : /************************************************************************/
11070 :
11071 : /** Return whether a RasterIO(GF_Read) request spanning over multiple
11072 : * blocks may be accelerated internally using multi-threading.
11073 : *
11074 : * This can be used to determine the best chunk size to read a raster band.
11075 : *
11076 : * Note that such optimizations may require that the window is perfectly aligned
11077 : * on block boundaries and does not involve resampling or data type translation
11078 : * occurs, etc.
11079 : *
11080 : * @since GDAL 3.13
11081 : */
11082 0 : bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
11083 : {
11084 0 : return false;
11085 : }
11086 :
11087 : /************************************************************************/
11088 : /* GDALMDArrayFromRasterBand */
11089 : /************************************************************************/
11090 :
11091 : class GDALMDArrayFromRasterBand final : public GDALMDArray
11092 : {
11093 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
11094 :
11095 : GDALDataset *m_poDS;
11096 : GDALRasterBand *m_poBand;
11097 : GDALExtendedDataType m_dt;
11098 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11099 : std::string m_osUnit;
11100 : std::vector<GByte> m_pabyNoData{};
11101 : std::shared_ptr<GDALMDArray> m_varX{};
11102 : std::shared_ptr<GDALMDArray> m_varY{};
11103 : std::string m_osFilename{};
11104 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11105 :
11106 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11107 : const size_t *count, const GInt64 *arrayStep,
11108 : const GPtrDiff_t *bufferStride,
11109 : const GDALExtendedDataType &bufferDataType,
11110 : void *pBuffer) const;
11111 :
11112 : protected:
11113 36 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
11114 72 : : GDALAbstractMDArray(std::string(),
11115 72 : std::string(poDS->GetDescription()) +
11116 : CPLSPrintf(" band %d", poBand->GetBand())),
11117 72 : GDALMDArray(std::string(),
11118 72 : std::string(poDS->GetDescription()) +
11119 : CPLSPrintf(" band %d", poBand->GetBand())),
11120 : m_poDS(poDS), m_poBand(poBand),
11121 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
11122 180 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
11123 : {
11124 36 : m_poDS->Reference();
11125 :
11126 36 : int bHasNoData = false;
11127 36 : if (m_poBand->GetRasterDataType() == GDT_Int64)
11128 : {
11129 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
11130 0 : if (bHasNoData)
11131 : {
11132 0 : m_pabyNoData.resize(m_dt.GetSize());
11133 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
11134 : m_dt.GetNumericDataType(), 0, 1);
11135 : }
11136 : }
11137 36 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
11138 : {
11139 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
11140 0 : if (bHasNoData)
11141 : {
11142 0 : m_pabyNoData.resize(m_dt.GetSize());
11143 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
11144 : m_dt.GetNumericDataType(), 0, 1);
11145 : }
11146 : }
11147 : else
11148 : {
11149 36 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
11150 36 : if (bHasNoData)
11151 : {
11152 1 : m_pabyNoData.resize(m_dt.GetSize());
11153 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
11154 : m_dt.GetNumericDataType(), 0, 1);
11155 : }
11156 : }
11157 :
11158 36 : const int nXSize = poBand->GetXSize();
11159 36 : const int nYSize = poBand->GetYSize();
11160 :
11161 36 : auto poSRS = m_poDS->GetSpatialRef();
11162 72 : std::string osTypeY;
11163 72 : std::string osTypeX;
11164 72 : std::string osDirectionY;
11165 72 : std::string osDirectionX;
11166 36 : if (poSRS && poSRS->GetAxesCount() == 2)
11167 : {
11168 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11169 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
11170 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11171 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
11172 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11173 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11174 : {
11175 8 : if (mapping == std::vector<int>{1, 2})
11176 : {
11177 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11178 8 : osDirectionY = "NORTH";
11179 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11180 8 : osDirectionX = "EAST";
11181 : }
11182 : }
11183 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11184 : {
11185 16 : if (mapping == std::vector<int>{2, 1})
11186 : {
11187 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11188 16 : osDirectionY = "NORTH";
11189 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11190 16 : osDirectionX = "EAST";
11191 : }
11192 : }
11193 : }
11194 :
11195 180 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11196 : "/", "Y", osTypeY, osDirectionY, nYSize),
11197 72 : std::make_shared<GDALDimensionWeakIndexingVar>(
11198 108 : "/", "X", osTypeX, osDirectionX, nXSize)};
11199 :
11200 36 : GDALGeoTransform gt;
11201 36 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
11202 : {
11203 50 : m_varX = GDALMDArrayRegularlySpaced::Create(
11204 50 : "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
11205 25 : m_dims[1]->SetIndexingVariable(m_varX);
11206 :
11207 50 : m_varY = GDALMDArrayRegularlySpaced::Create(
11208 50 : "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
11209 25 : m_dims[0]->SetIndexingVariable(m_varY);
11210 : }
11211 36 : }
11212 :
11213 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11214 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11215 : const GDALExtendedDataType &bufferDataType,
11216 : void *pDstBuffer) const override;
11217 :
11218 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11219 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11220 : const GDALExtendedDataType &bufferDataType,
11221 : const void *pSrcBuffer) override
11222 : {
11223 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11224 : bufferStride, bufferDataType,
11225 1 : const_cast<void *>(pSrcBuffer));
11226 : }
11227 :
11228 : public:
11229 72 : ~GDALMDArrayFromRasterBand() override
11230 36 : {
11231 36 : m_poDS->ReleaseRef();
11232 72 : }
11233 :
11234 36 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11235 : GDALRasterBand *poBand)
11236 : {
11237 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11238 72 : new GDALMDArrayFromRasterBand(poDS, poBand)));
11239 36 : array->SetSelf(array);
11240 72 : return array;
11241 : }
11242 :
11243 5 : bool IsWritable() const override
11244 : {
11245 5 : return m_poDS->GetAccess() == GA_Update;
11246 : }
11247 :
11248 112 : const std::string &GetFilename() const override
11249 : {
11250 112 : return m_osFilename;
11251 : }
11252 :
11253 : const std::vector<std::shared_ptr<GDALDimension>> &
11254 350 : GetDimensions() const override
11255 : {
11256 350 : return m_dims;
11257 : }
11258 :
11259 158 : const GDALExtendedDataType &GetDataType() const override
11260 : {
11261 158 : return m_dt;
11262 : }
11263 :
11264 5 : const std::string &GetUnit() const override
11265 : {
11266 5 : return m_osUnit;
11267 : }
11268 :
11269 32 : const void *GetRawNoDataValue() const override
11270 : {
11271 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11272 : }
11273 :
11274 4 : double GetOffset(bool *pbHasOffset,
11275 : GDALDataType *peStorageType) const override
11276 : {
11277 4 : int bHasOffset = false;
11278 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
11279 4 : if (pbHasOffset)
11280 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11281 4 : if (peStorageType)
11282 1 : *peStorageType = GDT_Unknown;
11283 4 : return dfRes;
11284 : }
11285 :
11286 4 : double GetScale(bool *pbHasScale,
11287 : GDALDataType *peStorageType) const override
11288 : {
11289 4 : int bHasScale = false;
11290 4 : double dfRes = m_poBand->GetScale(&bHasScale);
11291 4 : if (pbHasScale)
11292 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
11293 4 : if (peStorageType)
11294 1 : *peStorageType = GDT_Unknown;
11295 4 : return dfRes;
11296 : }
11297 :
11298 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11299 : {
11300 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
11301 88 : if (!poSrcSRS)
11302 2 : return nullptr;
11303 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11304 :
11305 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11306 86 : constexpr int iYDim = 0;
11307 86 : constexpr int iXDim = 1;
11308 258 : for (auto &m : axisMapping)
11309 : {
11310 172 : if (m == 1)
11311 86 : m = iXDim + 1;
11312 86 : else if (m == 2)
11313 86 : m = iYDim + 1;
11314 : else
11315 0 : m = 0;
11316 : }
11317 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11318 86 : return poSRS;
11319 : }
11320 :
11321 32 : std::vector<GUInt64> GetBlockSize() const override
11322 : {
11323 32 : int nBlockXSize = 0;
11324 32 : int nBlockYSize = 0;
11325 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11326 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11327 32 : static_cast<GUInt64>(nBlockXSize)};
11328 : }
11329 :
11330 : std::vector<std::shared_ptr<GDALAttribute>>
11331 23 : GetAttributes(CSLConstList) const override
11332 : {
11333 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
11334 23 : auto papszMD = m_poBand->GetMetadata();
11335 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
11336 : {
11337 2 : char *pszKey = nullptr;
11338 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11339 2 : if (pszKey && pszValue)
11340 : {
11341 : res.emplace_back(
11342 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11343 : }
11344 2 : CPLFree(pszKey);
11345 : }
11346 23 : return res;
11347 : }
11348 :
11349 6 : int GetOverviewCount() const override
11350 : {
11351 6 : return m_poBand->GetOverviewCount();
11352 : }
11353 :
11354 4 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11355 : {
11356 4 : const int nOverviews = GetOverviewCount();
11357 4 : if (idx < 0 || idx >= nOverviews)
11358 2 : return nullptr;
11359 2 : m_apoOverviews.resize(nOverviews);
11360 2 : if (!m_apoOverviews[idx])
11361 : {
11362 1 : if (auto poOvrBand = m_poBand->GetOverview(idx))
11363 : {
11364 1 : if (auto poOvrDS = poOvrBand->GetDataset())
11365 : {
11366 1 : m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11367 : }
11368 : }
11369 : }
11370 2 : return m_apoOverviews[idx];
11371 : }
11372 : };
11373 :
11374 39 : bool GDALMDArrayFromRasterBand::IRead(
11375 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11376 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11377 : void *pDstBuffer) const
11378 : {
11379 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11380 39 : bufferDataType, pDstBuffer);
11381 : }
11382 :
11383 : /************************************************************************/
11384 : /* ReadWrite() */
11385 : /************************************************************************/
11386 :
11387 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
11388 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11389 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11390 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11391 : {
11392 40 : constexpr size_t iDimX = 1;
11393 40 : constexpr size_t iDimY = 0;
11394 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11395 : arrayStartIdx, count, arrayStep, bufferStride,
11396 40 : bufferDataType, pBuffer);
11397 : }
11398 :
11399 : /************************************************************************/
11400 : /* GDALMDRasterIOFromBand() */
11401 : /************************************************************************/
11402 :
11403 76 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11404 : size_t iDimX, size_t iDimY,
11405 : const GUInt64 *arrayStartIdx, const size_t *count,
11406 : const GInt64 *arrayStep,
11407 : const GPtrDiff_t *bufferStride,
11408 : const GDALExtendedDataType &bufferDataType,
11409 : void *pBuffer)
11410 : {
11411 76 : const auto eDT(bufferDataType.GetNumericDataType());
11412 76 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11413 76 : const int nX =
11414 76 : arrayStep[iDimX] > 0
11415 76 : ? static_cast<int>(arrayStartIdx[iDimX])
11416 2 : : static_cast<int>(arrayStartIdx[iDimX] -
11417 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
11418 76 : const int nY =
11419 76 : arrayStep[iDimY] > 0
11420 76 : ? static_cast<int>(arrayStartIdx[iDimY])
11421 6 : : static_cast<int>(arrayStartIdx[iDimY] -
11422 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
11423 : const int nSizeX =
11424 76 : static_cast<int>(count[iDimX] * std::abs(arrayStep[iDimX]));
11425 : const int nSizeY =
11426 76 : static_cast<int>(count[iDimY] * std::abs(arrayStep[iDimY]));
11427 76 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11428 76 : int nStrideXSign = 1;
11429 76 : if (arrayStep[iDimX] < 0)
11430 : {
11431 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11432 2 : nStrideXSign = -1;
11433 : }
11434 76 : int nStrideYSign = 1;
11435 76 : if (arrayStep[iDimY] < 0)
11436 : {
11437 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11438 6 : nStrideYSign = -1;
11439 : }
11440 :
11441 152 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11442 76 : static_cast<int>(count[iDimX]),
11443 76 : static_cast<int>(count[iDimY]), eDT,
11444 : static_cast<GSpacing>(
11445 76 : nStrideXSign * bufferStride[iDimX] * nDTSize),
11446 : static_cast<GSpacing>(
11447 76 : nStrideYSign * bufferStride[iDimY] * nDTSize),
11448 76 : nullptr) == CE_None;
11449 : }
11450 :
11451 : /************************************************************************/
11452 : /* AsMDArray() */
11453 : /************************************************************************/
11454 :
11455 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11456 : *
11457 : * The band must be linked to a GDALDataset. If this dataset is not already
11458 : * marked as shared, it will be, so that the returned array holds a reference
11459 : * to it.
11460 : *
11461 : * If the dataset has a geotransform attached, the X and Y dimensions of the
11462 : * returned array will have an associated indexing variable.
11463 : *
11464 : * This is the same as the C function GDALRasterBandAsMDArray().
11465 : *
11466 : * The "reverse" method is GDALMDArray::AsClassicDataset().
11467 : *
11468 : * @return a new array, or nullptr.
11469 : *
11470 : * @since GDAL 3.1
11471 : */
11472 35 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11473 : {
11474 35 : if (!poDS)
11475 : {
11476 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11477 0 : return nullptr;
11478 : }
11479 35 : if (!poDS->GetShared())
11480 : {
11481 33 : poDS->MarkAsShared();
11482 : }
11483 : return GDALMDArrayFromRasterBand::Create(
11484 35 : poDS, const_cast<GDALRasterBand *>(this));
11485 : }
11486 :
11487 : /************************************************************************/
11488 : /* InterpolateAtPoint() */
11489 : /************************************************************************/
11490 :
11491 : /**
11492 : * \brief Interpolates the value between pixels using a resampling algorithm,
11493 : * taking pixel/line coordinates as input.
11494 : *
11495 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11496 : * @param dfLine line coordinate as a double, where interpolation should be done.
11497 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11498 : * @param pdfRealValue pointer to real part of interpolated value
11499 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11500 : *
11501 : * @return CE_None on success, or an error code on failure.
11502 : * @since GDAL 3.10
11503 : */
11504 :
11505 185 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11506 : GDALRIOResampleAlg eInterpolation,
11507 : double *pdfRealValue,
11508 : double *pdfImagValue) const
11509 : {
11510 185 : if (eInterpolation != GRIORA_NearestNeighbour &&
11511 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11512 : eInterpolation != GRIORA_CubicSpline)
11513 : {
11514 2 : CPLError(CE_Failure, CPLE_AppDefined,
11515 : "Only nearest, bilinear, cubic and cubicspline interpolation "
11516 : "methods "
11517 : "allowed");
11518 :
11519 2 : return CE_Failure;
11520 : }
11521 :
11522 183 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11523 183 : if (!m_poPointsCache)
11524 103 : m_poPointsCache = new GDALDoublePointsCache();
11525 :
11526 : const bool res =
11527 183 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11528 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
11529 :
11530 183 : return res ? CE_None : CE_Failure;
11531 : }
11532 :
11533 : /************************************************************************/
11534 : /* GDALRasterInterpolateAtPoint() */
11535 : /************************************************************************/
11536 :
11537 : /**
11538 : * \brief Interpolates the value between pixels using
11539 : * a resampling algorithm
11540 : *
11541 : * @see GDALRasterBand::InterpolateAtPoint()
11542 : * @since GDAL 3.10
11543 : */
11544 :
11545 162 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11546 : double dfLine,
11547 : GDALRIOResampleAlg eInterpolation,
11548 : double *pdfRealValue, double *pdfImagValue)
11549 : {
11550 162 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11551 :
11552 162 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11553 162 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11554 162 : pdfRealValue, pdfImagValue);
11555 : }
11556 :
11557 : /************************************************************************/
11558 : /* InterpolateAtGeolocation() */
11559 : /************************************************************************/
11560 :
11561 : /**
11562 : * \brief Interpolates the value between pixels using a resampling algorithm,
11563 : * taking georeferenced coordinates as input.
11564 : *
11565 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11566 : * must be in the "natural" SRS of the dataset, that is the one returned by
11567 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11568 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11569 : * array (generally WGS 84) if there is a geolocation array.
11570 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11571 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11572 : * be a easting, and dfGeolocY a northing.
11573 : *
11574 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11575 : * expressed in that CRS, and that tuple must be conformant with the
11576 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11577 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11578 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11579 : * before calling this method, and in that case, dfGeolocX must be a longitude
11580 : * or an easting value, and dfGeolocX a latitude or a northing value.
11581 : *
11582 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11583 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11584 : * it for details on how that transformation is done.
11585 : *
11586 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11587 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11588 : * where interpolation should be done.
11589 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11590 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11591 : * where interpolation should be done.
11592 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11593 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11594 : * @param pdfRealValue pointer to real part of interpolated value
11595 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11596 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11597 : *
11598 : * @return CE_None on success, or an error code on failure.
11599 : * @since GDAL 3.11
11600 : */
11601 :
11602 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11603 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11604 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11605 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11606 : {
11607 : double dfPixel;
11608 : double dfLine;
11609 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11610 : &dfLine,
11611 15 : papszTransformerOptions) != CE_None)
11612 : {
11613 1 : return CE_Failure;
11614 : }
11615 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11616 14 : pdfImagValue);
11617 : }
11618 :
11619 : /************************************************************************/
11620 : /* GDALRasterInterpolateAtGeolocation() */
11621 : /************************************************************************/
11622 :
11623 : /**
11624 : * \brief Interpolates the value between pixels using a resampling algorithm,
11625 : * taking georeferenced coordinates as input.
11626 : *
11627 : * @see GDALRasterBand::InterpolateAtGeolocation()
11628 : * @since GDAL 3.11
11629 : */
11630 :
11631 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11632 : double dfGeolocX, double dfGeolocY,
11633 : OGRSpatialReferenceH hSRS,
11634 : GDALRIOResampleAlg eInterpolation,
11635 : double *pdfRealValue,
11636 : double *pdfImagValue,
11637 : CSLConstList papszTransformerOptions)
11638 : {
11639 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11640 :
11641 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11642 15 : return poBand->InterpolateAtGeolocation(
11643 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11644 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11645 : }
11646 :
11647 : /************************************************************************/
11648 : /* GDALRasterBand::SplitRasterIO() */
11649 : /************************************************************************/
11650 :
11651 : //! @cond Doxygen_Suppress
11652 :
11653 : /** Implements IRasterIO() by dividing the request in 2.
11654 : *
11655 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11656 : *
11657 : * Return CE_Warning if the split could not be done, CE_None in case of
11658 : * success and CE_Failure in case of error.
11659 : *
11660 : * @since 3.12
11661 : */
11662 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11663 : [[maybe_unused]] int nXSize,
11664 : [[maybe_unused]] int nYSize, void *pData,
11665 : int nBufXSize, int nBufYSize,
11666 : GDALDataType eBufType,
11667 : GSpacing nPixelSpace, GSpacing nLineSpace,
11668 : GDALRasterIOExtraArg *psExtraArg)
11669 : {
11670 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11671 :
11672 999 : GByte *pabyData = static_cast<GByte *>(pData);
11673 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11674 : {
11675 : GDALRasterIOExtraArg sArg;
11676 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11677 499 : const int nHalfHeight = nBufYSize / 2;
11678 :
11679 499 : sArg.pfnProgress = GDALScaledProgress;
11680 499 : sArg.pProgressData = GDALCreateScaledProgress(
11681 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11682 499 : if (sArg.pProgressData == nullptr)
11683 499 : sArg.pfnProgress = nullptr;
11684 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11685 : pabyData, nBufXSize, nHalfHeight, eBufType,
11686 499 : nPixelSpace, nLineSpace, &sArg);
11687 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11688 :
11689 499 : if (eErr == CE_None)
11690 : {
11691 499 : sArg.pfnProgress = GDALScaledProgress;
11692 499 : sArg.pProgressData = GDALCreateScaledProgress(
11693 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11694 499 : if (sArg.pProgressData == nullptr)
11695 499 : sArg.pfnProgress = nullptr;
11696 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11697 : nBufYSize - nHalfHeight,
11698 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11699 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11700 499 : nLineSpace, &sArg);
11701 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11702 : }
11703 499 : return eErr;
11704 : }
11705 500 : else if (nBufXSize >= 2)
11706 : {
11707 : GDALRasterIOExtraArg sArg;
11708 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11709 500 : const int nHalfWidth = nBufXSize / 2;
11710 :
11711 500 : sArg.pfnProgress = GDALScaledProgress;
11712 500 : sArg.pProgressData = GDALCreateScaledProgress(
11713 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11714 500 : if (sArg.pProgressData == nullptr)
11715 500 : sArg.pfnProgress = nullptr;
11716 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11717 : pabyData, nHalfWidth, nBufYSize, eBufType,
11718 500 : nPixelSpace, nLineSpace, &sArg);
11719 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11720 :
11721 500 : if (eErr == CE_None)
11722 : {
11723 500 : sArg.pfnProgress = GDALScaledProgress;
11724 500 : sArg.pProgressData = GDALCreateScaledProgress(
11725 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11726 500 : if (sArg.pProgressData == nullptr)
11727 500 : sArg.pfnProgress = nullptr;
11728 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11729 : nBufXSize - nHalfWidth, nBufYSize,
11730 500 : pabyData + nHalfWidth * nPixelSpace,
11731 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11732 500 : nPixelSpace, nLineSpace, &sArg);
11733 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11734 : }
11735 500 : return eErr;
11736 : }
11737 :
11738 0 : return CE_Warning;
11739 : }
11740 :
11741 : //! @endcond
11742 :
11743 : /************************************************************************/
11744 : /* ThrowIfNotSameDimensions() */
11745 : /************************************************************************/
11746 :
11747 : //! @cond Doxygen_Suppress
11748 : /* static */
11749 187 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11750 : const GDALRasterBand &second)
11751 : {
11752 356 : if (first.GetXSize() != second.GetXSize() ||
11753 169 : first.GetYSize() != second.GetYSize())
11754 : {
11755 36 : throw std::runtime_error("Bands do not have the same dimensions");
11756 : }
11757 151 : }
11758 :
11759 : //! @endcond
11760 :
11761 : /************************************************************************/
11762 : /* GDALRasterBandUnaryOp() */
11763 : /************************************************************************/
11764 :
11765 : /** Apply a unary operation on this band.
11766 : *
11767 : * The resulting band is lazy evaluated. A reference is taken on the input
11768 : * dataset.
11769 : *
11770 : * @since 3.12
11771 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11772 : */
11773 : GDALComputedRasterBandH
11774 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11775 : GDALRasterAlgebraUnaryOperation eOp)
11776 : {
11777 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11778 6 : GDALComputedRasterBand::Operation cppOp{};
11779 6 : switch (eOp)
11780 : {
11781 2 : case GRAUO_LOGICAL_NOT:
11782 : return new GDALComputedRasterBand(
11783 : GDALComputedRasterBand::Operation::OP_NE,
11784 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11785 1 : case GRAUO_ABS:
11786 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11787 1 : break;
11788 1 : case GRAUO_SQRT:
11789 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11790 1 : break;
11791 1 : case GRAUO_LOG:
11792 : #ifndef HAVE_MUPARSER
11793 : CPLError(
11794 : CE_Failure, CPLE_NotSupported,
11795 : "log(band) not available on a GDAL build without muparser");
11796 : return nullptr;
11797 : #else
11798 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11799 1 : break;
11800 : #endif
11801 1 : case GRAUO_LOG10:
11802 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11803 1 : break;
11804 : }
11805 : return new GDALComputedRasterBand(cppOp,
11806 4 : *(GDALRasterBand::FromHandle(hBand)));
11807 : }
11808 :
11809 : /************************************************************************/
11810 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11811 : /************************************************************************/
11812 :
11813 : static GDALComputedRasterBand::Operation
11814 128 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11815 : GDALRasterAlgebraBinaryOperation eOp)
11816 : {
11817 128 : switch (eOp)
11818 : {
11819 34 : case GRABO_ADD:
11820 34 : return GDALComputedRasterBand::Operation::OP_ADD;
11821 2 : case GRABO_SUB:
11822 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11823 24 : case GRABO_MUL:
11824 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11825 3 : case GRABO_DIV:
11826 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11827 6 : case GRABO_GT:
11828 6 : return GDALComputedRasterBand::Operation::OP_GT;
11829 8 : case GRABO_GE:
11830 8 : return GDALComputedRasterBand::Operation::OP_GE;
11831 6 : case GRABO_LT:
11832 6 : return GDALComputedRasterBand::Operation::OP_LT;
11833 6 : case GRABO_LE:
11834 6 : return GDALComputedRasterBand::Operation::OP_LE;
11835 6 : case GRABO_EQ:
11836 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11837 6 : case GRABO_NE:
11838 6 : break;
11839 12 : case GRABO_LOGICAL_AND:
11840 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11841 12 : case GRABO_LOGICAL_OR:
11842 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11843 3 : case GRABO_POW:
11844 3 : return GDALComputedRasterBand::Operation::OP_POW;
11845 : }
11846 6 : return GDALComputedRasterBand::Operation::OP_NE;
11847 : }
11848 :
11849 : /************************************************************************/
11850 : /* GDALRasterBandBinaryOpBand() */
11851 : /************************************************************************/
11852 :
11853 : /** Apply a binary operation on this band with another one.
11854 : *
11855 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11856 : * "hBand1 - hBand2".
11857 : *
11858 : * The resulting band is lazy evaluated. A reference is taken on both input
11859 : * datasets.
11860 : *
11861 : * @since 3.12
11862 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11863 : */
11864 : GDALComputedRasterBandH
11865 65 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11866 : GDALRasterAlgebraBinaryOperation eOp,
11867 : GDALRasterBandH hOtherBand)
11868 : {
11869 65 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11870 65 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11871 : #ifndef HAVE_MUPARSER
11872 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11873 : {
11874 : CPLError(
11875 : CE_Failure, CPLE_NotSupported,
11876 : "Band comparison operators not available on a GDAL build without "
11877 : "muparser");
11878 : return nullptr;
11879 : }
11880 : else if (eOp == GRABO_POW)
11881 : {
11882 : CPLError(
11883 : CE_Failure, CPLE_NotSupported,
11884 : "pow(band, band) not available on a GDAL build without muparser");
11885 : return nullptr;
11886 : }
11887 : #endif
11888 65 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11889 65 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11890 : try
11891 : {
11892 65 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11893 : }
11894 13 : catch (const std::exception &e)
11895 : {
11896 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11897 13 : return nullptr;
11898 : }
11899 : return new GDALComputedRasterBand(
11900 52 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11901 52 : secondBand);
11902 : }
11903 :
11904 : /************************************************************************/
11905 : /* GDALRasterBandBinaryOpDouble() */
11906 : /************************************************************************/
11907 :
11908 : /** Apply a binary operation on this band with a constant
11909 : *
11910 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11911 : * "hBand - constant".
11912 : *
11913 : * The resulting band is lazy evaluated. A reference is taken on the input
11914 : * dataset.
11915 : *
11916 : * @since 3.12
11917 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11918 : */
11919 : GDALComputedRasterBandH
11920 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11921 : GDALRasterAlgebraBinaryOperation eOp,
11922 : double constant)
11923 : {
11924 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11925 : #ifndef HAVE_MUPARSER
11926 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11927 : {
11928 : CPLError(
11929 : CE_Failure, CPLE_NotSupported,
11930 : "Band comparison operators not available on a GDAL build without "
11931 : "muparser");
11932 : return nullptr;
11933 : }
11934 : #endif
11935 : return new GDALComputedRasterBand(
11936 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11937 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11938 : }
11939 :
11940 : /************************************************************************/
11941 : /* GDALRasterBandBinaryOpDoubleToBand() */
11942 : /************************************************************************/
11943 :
11944 : /** Apply a binary operation on the constant with this band
11945 : *
11946 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11947 : * "constant - hBand".
11948 : *
11949 : * The resulting band is lazy evaluated. A reference is taken on the input
11950 : * dataset.
11951 : *
11952 : * @since 3.12
11953 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11954 : */
11955 : GDALComputedRasterBandH
11956 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11957 : GDALRasterAlgebraBinaryOperation eOp,
11958 : GDALRasterBandH hBand)
11959 : {
11960 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11961 : #ifndef HAVE_MUPARSER
11962 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11963 : {
11964 : CPLError(
11965 : CE_Failure, CPLE_NotSupported,
11966 : "Band comparison operators not available on a GDAL build without "
11967 : "muparser");
11968 : return nullptr;
11969 : }
11970 : #endif
11971 18 : switch (eOp)
11972 : {
11973 15 : case GRABO_ADD:
11974 : case GRABO_MUL:
11975 : {
11976 : return new GDALComputedRasterBand(
11977 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11978 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11979 : }
11980 :
11981 2 : case GRABO_DIV:
11982 : case GRABO_GT:
11983 : case GRABO_GE:
11984 : case GRABO_LT:
11985 : case GRABO_LE:
11986 : case GRABO_EQ:
11987 : case GRABO_NE:
11988 : case GRABO_LOGICAL_AND:
11989 : case GRABO_LOGICAL_OR:
11990 : case GRABO_POW:
11991 : {
11992 : return new GDALComputedRasterBand(
11993 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11994 2 : *(GDALRasterBand::FromHandle(hBand)));
11995 : }
11996 :
11997 1 : case GRABO_SUB:
11998 : {
11999 1 : break;
12000 : }
12001 : }
12002 :
12003 : return new GDALComputedRasterBand(
12004 : GDALComputedRasterBand::Operation::OP_ADD,
12005 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
12006 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
12007 1 : constant);
12008 : }
12009 :
12010 : /************************************************************************/
12011 : /* operator+() */
12012 : /************************************************************************/
12013 :
12014 : /** Add this band with another one.
12015 : *
12016 : * The resulting band is lazy evaluated. A reference is taken on both input
12017 : * datasets.
12018 : *
12019 : * @since 3.12
12020 : * @throw std::runtime_error if both bands do not have the same dimensions.
12021 : */
12022 : GDALComputedRasterBand
12023 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
12024 : {
12025 8 : ThrowIfNotSameDimensions(*this, other);
12026 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
12027 7 : *this, other);
12028 : }
12029 :
12030 : /************************************************************************/
12031 : /* operator+() */
12032 : /************************************************************************/
12033 :
12034 : /** Add this band with a constant.
12035 : *
12036 : * The resulting band is lazy evaluated. A reference is taken on the input
12037 : * dataset.
12038 : *
12039 : * @since 3.12
12040 : */
12041 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
12042 : {
12043 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
12044 13 : *this, constant);
12045 : }
12046 :
12047 : /************************************************************************/
12048 : /* operator+() */
12049 : /************************************************************************/
12050 :
12051 : /** Add a band with a constant.
12052 : *
12053 : * The resulting band is lazy evaluated. A reference is taken on the input
12054 : * dataset.
12055 : *
12056 : * @since 3.12
12057 : */
12058 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
12059 : {
12060 1 : return other + constant;
12061 : }
12062 :
12063 : /************************************************************************/
12064 : /* operator-() */
12065 : /************************************************************************/
12066 :
12067 : /** Return a band whose value is the opposite value of the band for each
12068 : * pixel.
12069 : *
12070 : * The resulting band is lazy evaluated. A reference is taken on the input
12071 : * dataset.
12072 : *
12073 : * @since 3.12
12074 : */
12075 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
12076 : {
12077 2 : return 0 - *this;
12078 : }
12079 :
12080 : /************************************************************************/
12081 : /* operator-() */
12082 : /************************************************************************/
12083 :
12084 : /** Subtract this band with another one.
12085 : *
12086 : * The resulting band is lazy evaluated. A reference is taken on both input
12087 : * datasets.
12088 : *
12089 : * @since 3.12
12090 : * @throw std::runtime_error if both bands do not have the same dimensions.
12091 : */
12092 : GDALComputedRasterBand
12093 7 : GDALRasterBand::operator-(const GDALRasterBand &other) const
12094 : {
12095 7 : ThrowIfNotSameDimensions(*this, other);
12096 : return GDALComputedRasterBand(
12097 7 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
12098 : }
12099 :
12100 : /************************************************************************/
12101 : /* operator-() */
12102 : /************************************************************************/
12103 :
12104 : /** Subtract this band with a constant.
12105 : *
12106 : * The resulting band is lazy evaluated. A reference is taken on the input
12107 : * dataset.
12108 : *
12109 : * @since 3.12
12110 : */
12111 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
12112 : {
12113 : return GDALComputedRasterBand(
12114 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
12115 : }
12116 :
12117 : /************************************************************************/
12118 : /* operator-() */
12119 : /************************************************************************/
12120 :
12121 : /** Subtract a constant with a band.
12122 : *
12123 : * The resulting band is lazy evaluated. A reference is taken on the input
12124 : * dataset.
12125 : *
12126 : * @since 3.12
12127 : */
12128 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
12129 : {
12130 6 : return other * (-1.0) + constant;
12131 : }
12132 :
12133 : /************************************************************************/
12134 : /* operator*() */
12135 : /************************************************************************/
12136 :
12137 : /** Multiply this band with another one.
12138 : *
12139 : * The resulting band is lazy evaluated. A reference is taken on both input
12140 : * datasets.
12141 : *
12142 : * @since 3.12
12143 : * @throw std::runtime_error if both bands do not have the same dimensions.
12144 : */
12145 : GDALComputedRasterBand
12146 7 : GDALRasterBand::operator*(const GDALRasterBand &other) const
12147 : {
12148 7 : ThrowIfNotSameDimensions(*this, other);
12149 : return GDALComputedRasterBand(
12150 7 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
12151 : }
12152 :
12153 : /************************************************************************/
12154 : /* operator*() */
12155 : /************************************************************************/
12156 :
12157 : /** Multiply this band by a constant.
12158 : *
12159 : * The resulting band is lazy evaluated. A reference is taken on the input
12160 : * dataset.
12161 : *
12162 : * @since 3.12
12163 : */
12164 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
12165 : {
12166 : return GDALComputedRasterBand(
12167 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
12168 : }
12169 :
12170 : /************************************************************************/
12171 : /* operator*() */
12172 : /************************************************************************/
12173 :
12174 : /** Multiply a band with a constant.
12175 : *
12176 : * The resulting band is lazy evaluated. A reference is taken on the input
12177 : * dataset.
12178 : *
12179 : * @since 3.12
12180 : */
12181 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12182 : {
12183 2 : return other * constant;
12184 : }
12185 :
12186 : /************************************************************************/
12187 : /* operator/() */
12188 : /************************************************************************/
12189 :
12190 : /** Divide this band with another one.
12191 : *
12192 : * The resulting band is lazy evaluated. A reference is taken on both input
12193 : * datasets.
12194 : *
12195 : * @since 3.12
12196 : * @throw std::runtime_error if both bands do not have the same dimensions.
12197 : */
12198 : GDALComputedRasterBand
12199 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
12200 : {
12201 2 : ThrowIfNotSameDimensions(*this, other);
12202 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12203 2 : *this, other);
12204 : }
12205 :
12206 : /************************************************************************/
12207 : /* operator/() */
12208 : /************************************************************************/
12209 :
12210 : /** Divide this band by a constant.
12211 : *
12212 : * The resulting band is lazy evaluated. A reference is taken on the input
12213 : * dataset.
12214 : *
12215 : * @since 3.12
12216 : */
12217 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12218 : {
12219 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12220 0 : *this, constant);
12221 : }
12222 :
12223 : /************************************************************************/
12224 : /* operator/() */
12225 : /************************************************************************/
12226 :
12227 : /** Divide a constant by a band.
12228 : *
12229 : * The resulting band is lazy evaluated. A reference is taken on the input
12230 : * dataset.
12231 : *
12232 : * @since 3.12
12233 : */
12234 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12235 : {
12236 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12237 1 : constant, other);
12238 : }
12239 :
12240 : /************************************************************************/
12241 : /* ThrowIfNotMuparser() */
12242 : /************************************************************************/
12243 :
12244 : #ifndef HAVE_MUPARSER
12245 : static GDALComputedRasterBand ThrowIfNotMuparser()
12246 : {
12247 : throw std::runtime_error("Operator not available on a "
12248 : "GDAL build without muparser");
12249 : }
12250 : #endif
12251 :
12252 : /************************************************************************/
12253 : /* CreateComputedBand() */
12254 : /************************************************************************/
12255 :
12256 : static GDALComputedRasterBand
12257 27 : CreateComputedBand(GDALComputedRasterBand::Operation op,
12258 : const GDALRasterBand &bandA, const GDALRasterBand &bandB)
12259 : {
12260 : #ifndef HAVE_MUPARSER
12261 : (void)op;
12262 : (void)bandA;
12263 : (void)bandB;
12264 : return ThrowIfNotMuparser();
12265 : #else
12266 27 : GDALRasterBand::ThrowIfNotSameDimensions(bandA, bandB);
12267 19 : return GDALComputedRasterBand(op, bandA, bandB);
12268 : #endif
12269 : }
12270 :
12271 : static GDALComputedRasterBand
12272 32 : CreateComputedBand(GDALComputedRasterBand::Operation op,
12273 : const GDALRasterBand &band, double constant)
12274 : {
12275 : #ifndef HAVE_MUPARSER
12276 : (void)op;
12277 : (void)band;
12278 : (void)constant;
12279 : return ThrowIfNotMuparser();
12280 : #else
12281 32 : return GDALComputedRasterBand(op, band, constant);
12282 : #endif
12283 : }
12284 :
12285 : static GDALComputedRasterBand
12286 18 : CreateComputedBand(GDALComputedRasterBand::Operation op, double constant,
12287 : const GDALRasterBand &band)
12288 : {
12289 : #ifndef HAVE_MUPARSER
12290 : (void)op;
12291 : (void)constant;
12292 : (void)band;
12293 : return ThrowIfNotMuparser();
12294 : #else
12295 18 : return GDALComputedRasterBand(op, constant, band);
12296 : #endif
12297 : }
12298 :
12299 : /************************************************************************/
12300 : /* operator>() */
12301 : /************************************************************************/
12302 :
12303 : /** Return a band whose value is 1 if the pixel value of the left operand
12304 : * is greater than the pixel value of the right operand.
12305 : *
12306 : * The resulting band is lazy evaluated. A reference is taken on the input
12307 : * dataset.
12308 : *
12309 : * @since 3.12
12310 : */
12311 : GDALComputedRasterBand
12312 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
12313 : {
12314 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GT, *this,
12315 3 : other);
12316 : }
12317 :
12318 : /************************************************************************/
12319 : /* operator>() */
12320 : /************************************************************************/
12321 :
12322 : /** Return a band whose value is 1 if the pixel value of the left operand
12323 : * is greater than the constant.
12324 : *
12325 : * The resulting band is lazy evaluated. A reference is taken on the input
12326 : * dataset.
12327 : *
12328 : * @since 3.12
12329 : */
12330 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12331 : {
12332 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GT, *this,
12333 3 : constant);
12334 : }
12335 :
12336 : /************************************************************************/
12337 : /* operator>() */
12338 : /************************************************************************/
12339 :
12340 : /** Return a band whose value is 1 if the constant is greater than the pixel
12341 : * value of the right operand.
12342 : *
12343 : * The resulting band is lazy evaluated. A reference is taken on the input
12344 : * dataset.
12345 : *
12346 : * @since 3.12
12347 : */
12348 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12349 : {
12350 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GT,
12351 2 : constant, other);
12352 : }
12353 :
12354 : /************************************************************************/
12355 : /* operator>=() */
12356 : /************************************************************************/
12357 :
12358 : /** Return a band whose value is 1 if the pixel value of the left operand
12359 : * is greater or equal to the pixel value of the right operand.
12360 : *
12361 : * The resulting band is lazy evaluated. A reference is taken on the input
12362 : * dataset.
12363 : *
12364 : * @since 3.12
12365 : */
12366 : GDALComputedRasterBand
12367 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
12368 : {
12369 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GE, *this,
12370 4 : other);
12371 : }
12372 :
12373 : /************************************************************************/
12374 : /* operator>=() */
12375 : /************************************************************************/
12376 :
12377 : /** Return a band whose value is 1 if the pixel value of the left operand
12378 : * is greater or equal to the constant.
12379 : *
12380 : * The resulting band is lazy evaluated. A reference is taken on the input
12381 : * dataset.
12382 : *
12383 : * @since 3.12
12384 : */
12385 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12386 : {
12387 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GE, *this,
12388 3 : constant);
12389 : }
12390 :
12391 : /************************************************************************/
12392 : /* operator>=() */
12393 : /************************************************************************/
12394 :
12395 : /** Return a band whose value is 1 if the constant is greater or equal to
12396 : * the pixel value of the right operand.
12397 : *
12398 : * The resulting band is lazy evaluated. A reference is taken on the input
12399 : * dataset.
12400 : *
12401 : * @since 3.12
12402 : */
12403 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12404 : {
12405 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_GE,
12406 2 : constant, other);
12407 : }
12408 :
12409 : /************************************************************************/
12410 : /* operator<() */
12411 : /************************************************************************/
12412 :
12413 : /** Return a band whose value is 1 if the pixel value of the left operand
12414 : * is lesser than the pixel value of the right operand.
12415 : *
12416 : * The resulting band is lazy evaluated. A reference is taken on the input
12417 : * dataset.
12418 : *
12419 : * @since 3.12
12420 : */
12421 : GDALComputedRasterBand
12422 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
12423 : {
12424 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LT, *this,
12425 3 : other);
12426 : }
12427 :
12428 : /************************************************************************/
12429 : /* operator<() */
12430 : /************************************************************************/
12431 :
12432 : /** Return a band whose value is 1 if the pixel value of the left operand
12433 : * is lesser than the constant.
12434 : *
12435 : * The resulting band is lazy evaluated. A reference is taken on the input
12436 : * dataset.
12437 : *
12438 : * @since 3.12
12439 : */
12440 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12441 : {
12442 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LT, *this,
12443 3 : constant);
12444 : }
12445 :
12446 : /************************************************************************/
12447 : /* operator<() */
12448 : /************************************************************************/
12449 :
12450 : /** Return a band whose value is 1 if the constant is lesser than the pixel
12451 : * value of the right operand.
12452 : *
12453 : * The resulting band is lazy evaluated. A reference is taken on the input
12454 : * dataset.
12455 : *
12456 : * @since 3.12
12457 : */
12458 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12459 : {
12460 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LT,
12461 2 : constant, other);
12462 : }
12463 :
12464 : /************************************************************************/
12465 : /* operator<=() */
12466 : /************************************************************************/
12467 :
12468 : /** Return a band whose value is 1 if the pixel value of the left operand
12469 : * is lesser or equal to the pixel value of the right operand.
12470 : *
12471 : * The resulting band is lazy evaluated. A reference is taken on the input
12472 : * dataset.
12473 : *
12474 : * @since 3.12
12475 : */
12476 : GDALComputedRasterBand
12477 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
12478 : {
12479 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LE, *this,
12480 4 : other);
12481 : }
12482 :
12483 : /************************************************************************/
12484 : /* operator<=() */
12485 : /************************************************************************/
12486 :
12487 : /** Return a band whose value is 1 if the pixel value of the left operand
12488 : * is lesser or equal to the constant.
12489 : *
12490 : * The resulting band is lazy evaluated. A reference is taken on the input
12491 : * dataset.
12492 : *
12493 : * @since 3.12
12494 : */
12495 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12496 : {
12497 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LE, *this,
12498 3 : constant);
12499 : }
12500 :
12501 : /************************************************************************/
12502 : /* operator<=() */
12503 : /************************************************************************/
12504 :
12505 : /** Return a band whose value is 1 if the constant is lesser or equal to
12506 : * the pixel value of the right operand.
12507 : *
12508 : * The resulting band is lazy evaluated. A reference is taken on the input
12509 : * dataset.
12510 : *
12511 : * @since 3.12
12512 : */
12513 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12514 : {
12515 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LE,
12516 2 : constant, other);
12517 : }
12518 :
12519 : /************************************************************************/
12520 : /* operator==() */
12521 : /************************************************************************/
12522 :
12523 : /** Return a band whose value is 1 if the pixel value of the left operand
12524 : * is equal to the pixel value of the right operand.
12525 : *
12526 : * The resulting band is lazy evaluated. A reference is taken on the input
12527 : * dataset.
12528 : *
12529 : * @since 3.12
12530 : */
12531 : GDALComputedRasterBand
12532 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
12533 : {
12534 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_EQ, *this,
12535 3 : other);
12536 : }
12537 :
12538 : /************************************************************************/
12539 : /* operator==() */
12540 : /************************************************************************/
12541 :
12542 : /** Return a band whose value is 1 if the pixel value of the left operand
12543 : * is equal to the constant.
12544 : *
12545 : * The resulting band is lazy evaluated. A reference is taken on the input
12546 : * dataset.
12547 : *
12548 : * @since 3.12
12549 : */
12550 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12551 : {
12552 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_EQ, *this,
12553 8 : constant);
12554 : }
12555 :
12556 : /************************************************************************/
12557 : /* operator==() */
12558 : /************************************************************************/
12559 :
12560 : /** Return a band whose value is 1 if the constant is equal to
12561 : * the pixel value of the right operand.
12562 : *
12563 : * The resulting band is lazy evaluated. A reference is taken on the input
12564 : * dataset.
12565 : *
12566 : * @since 3.12
12567 : */
12568 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12569 : {
12570 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_EQ,
12571 2 : constant, other);
12572 : }
12573 :
12574 : /************************************************************************/
12575 : /* operator!=() */
12576 : /************************************************************************/
12577 :
12578 : /** Return a band whose value is 1 if the pixel value of the left operand
12579 : * is different from the pixel value of the right operand.
12580 : *
12581 : * The resulting band is lazy evaluated. A reference is taken on the input
12582 : * dataset.
12583 : *
12584 : * @since 3.12
12585 : */
12586 : GDALComputedRasterBand
12587 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12588 : {
12589 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_NE, *this,
12590 3 : other);
12591 : }
12592 :
12593 : /************************************************************************/
12594 : /* operator!=() */
12595 : /************************************************************************/
12596 :
12597 : /** Return a band whose value is 1 if the pixel value of the left operand
12598 : * is different from the constant.
12599 : *
12600 : * The resulting band is lazy evaluated. A reference is taken on the input
12601 : * dataset.
12602 : *
12603 : * @since 3.12
12604 : */
12605 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12606 : {
12607 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_NE, *this,
12608 6 : constant);
12609 : }
12610 :
12611 : /************************************************************************/
12612 : /* operator!=() */
12613 : /************************************************************************/
12614 :
12615 : /** Return a band whose value is 1 if the constant is different from
12616 : * the pixel value of the right operand.
12617 : *
12618 : * The resulting band is lazy evaluated. A reference is taken on the input
12619 : * dataset.
12620 : *
12621 : * @since 3.12
12622 : */
12623 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12624 : {
12625 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_NE,
12626 2 : constant, other);
12627 : }
12628 :
12629 : #if defined(__GNUC__)
12630 : #pragma GCC diagnostic push
12631 : #pragma GCC diagnostic ignored "-Weffc++"
12632 : #endif
12633 :
12634 : /************************************************************************/
12635 : /* operator&&() */
12636 : /************************************************************************/
12637 :
12638 : /** Return a band whose value is 1 if the pixel value of the left and right
12639 : * operands is true.
12640 : *
12641 : * The resulting band is lazy evaluated. A reference is taken on the input
12642 : * dataset.
12643 : *
12644 : * @since 3.12
12645 : */
12646 : GDALComputedRasterBand
12647 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12648 : {
12649 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_AND,
12650 3 : *this, other);
12651 : }
12652 :
12653 : /************************************************************************/
12654 : /* operator&&() */
12655 : /************************************************************************/
12656 :
12657 : /** Return a band whose value is 1 if the pixel value of the left operand
12658 : * is true, as well as the constant
12659 : *
12660 : * The resulting band is lazy evaluated. A reference is taken on the input
12661 : * dataset.
12662 : *
12663 : * @since 3.12
12664 : */
12665 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12666 : {
12667 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_AND,
12668 2 : *this, constant);
12669 : }
12670 :
12671 : /************************************************************************/
12672 : /* operator&&() */
12673 : /************************************************************************/
12674 :
12675 : /** Return a band whose value is 1 if the constant is true, as well as
12676 : * the pixel value of the right operand.
12677 : *
12678 : * The resulting band is lazy evaluated. A reference is taken on the input
12679 : * dataset.
12680 : *
12681 : * @since 3.12
12682 : */
12683 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12684 : {
12685 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_AND,
12686 2 : constant, other);
12687 : }
12688 :
12689 : /************************************************************************/
12690 : /* operator||() */
12691 : /************************************************************************/
12692 :
12693 : /** Return a band whose value is 1 if the pixel value of the left or right
12694 : * operands is true.
12695 : *
12696 : * The resulting band is lazy evaluated. A reference is taken on the input
12697 : * dataset.
12698 : *
12699 : * @since 3.12
12700 : */
12701 : GDALComputedRasterBand
12702 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12703 : {
12704 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_OR,
12705 4 : *this, other);
12706 : }
12707 :
12708 : /************************************************************************/
12709 : /* operator||() */
12710 : /************************************************************************/
12711 :
12712 : /** Return a band whose value is 1 if the pixel value of the left operand
12713 : * is true, or if the constant is true
12714 : *
12715 : * The resulting band is lazy evaluated. A reference is taken on the input
12716 : * dataset.
12717 : *
12718 : * @since 3.12
12719 : */
12720 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12721 : {
12722 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_OR,
12723 4 : *this, constant);
12724 : }
12725 :
12726 : /************************************************************************/
12727 : /* operator||() */
12728 : /************************************************************************/
12729 :
12730 : /** Return a band whose value is 1 if the constant is true, or
12731 : * the pixel value of the right operand is true
12732 : *
12733 : * The resulting band is lazy evaluated. A reference is taken on the input
12734 : * dataset.
12735 : *
12736 : * @since 3.12
12737 : */
12738 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12739 : {
12740 : return CreateComputedBand(GDALComputedRasterBand::Operation::OP_LOGICAL_OR,
12741 4 : constant, other);
12742 : }
12743 :
12744 : #if defined(__GNUC__)
12745 : #pragma GCC diagnostic pop
12746 : #endif
12747 :
12748 : /************************************************************************/
12749 : /* operator!() */
12750 : /************************************************************************/
12751 :
12752 : /** Return a band whose value is the logical negation of the pixel value
12753 : *
12754 : * The resulting band is lazy evaluated. A reference is taken on the input
12755 : * dataset.
12756 : *
12757 : * @since 3.12
12758 : */
12759 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12760 : {
12761 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12762 2 : *this, true);
12763 : }
12764 :
12765 : namespace gdal
12766 : {
12767 :
12768 : /************************************************************************/
12769 : /* IfThenElse() */
12770 : /************************************************************************/
12771 :
12772 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12773 : * is not zero, or the one from elseBand otherwise.
12774 : *
12775 : * Variants of this method exits where thenBand and/or elseBand can be double
12776 : * values.
12777 : *
12778 : * The resulting band is lazy evaluated. A reference is taken on the input
12779 : * datasets.
12780 : *
12781 : * This method is the same as the C function GDALRasterBandIfThenElse()
12782 : *
12783 : * @since 3.12
12784 : */
12785 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12786 : const GDALRasterBand &thenBand,
12787 : const GDALRasterBand &elseBand)
12788 : {
12789 : #ifndef HAVE_MUPARSER
12790 : (void)condBand;
12791 : (void)thenBand;
12792 : (void)elseBand;
12793 : return ThrowIfNotMuparser();
12794 : #else
12795 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12796 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12797 : return GDALComputedRasterBand(
12798 : GDALComputedRasterBand::Operation::OP_TERNARY,
12799 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12800 : #endif
12801 : }
12802 :
12803 : //! @cond Doxygen_Suppress
12804 :
12805 : /************************************************************************/
12806 : /* IfThenElse() */
12807 : /************************************************************************/
12808 :
12809 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12810 : * is not zero, or the one from elseBand otherwise.
12811 : *
12812 : * The resulting band is lazy evaluated. A reference is taken on the input
12813 : * datasets.
12814 : *
12815 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12816 : * with thenBand = (condBand * 0) + thenValue
12817 : *
12818 : * @since 3.12
12819 : */
12820 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12821 : double thenValue,
12822 : const GDALRasterBand &elseBand)
12823 : {
12824 : #ifndef HAVE_MUPARSER
12825 : (void)condBand;
12826 : (void)thenValue;
12827 : (void)elseBand;
12828 : return ThrowIfNotMuparser();
12829 : #else
12830 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12831 : auto thenBand =
12832 1 : (condBand * 0)
12833 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12834 1 : thenValue;
12835 : return GDALComputedRasterBand(
12836 : GDALComputedRasterBand::Operation::OP_TERNARY,
12837 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12838 : #endif
12839 : }
12840 :
12841 : /************************************************************************/
12842 : /* IfThenElse() */
12843 : /************************************************************************/
12844 :
12845 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12846 : * is not zero, or the one from elseValue otherwise.
12847 : *
12848 : * The resulting band is lazy evaluated. A reference is taken on the input
12849 : * datasets.
12850 : *
12851 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12852 : * with elseBand = (condBand * 0) + elseValue
12853 :
12854 : * @since 3.12
12855 : */
12856 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12857 : const GDALRasterBand &thenBand,
12858 : double elseValue)
12859 : {
12860 : #ifndef HAVE_MUPARSER
12861 : (void)condBand;
12862 : (void)thenBand;
12863 : (void)elseValue;
12864 : return ThrowIfNotMuparser();
12865 : #else
12866 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12867 : auto elseBand =
12868 1 : (condBand * 0)
12869 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12870 1 : elseValue;
12871 : return GDALComputedRasterBand(
12872 : GDALComputedRasterBand::Operation::OP_TERNARY,
12873 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12874 : #endif
12875 : }
12876 :
12877 : /************************************************************************/
12878 : /* IfThenElse() */
12879 : /************************************************************************/
12880 :
12881 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12882 : * is not zero, or the one from elseValue otherwise.
12883 : *
12884 : * The resulting band is lazy evaluated. A reference is taken on the input
12885 : * datasets.
12886 : *
12887 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12888 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12889 : *
12890 : * @since 3.12
12891 : */
12892 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12893 : double thenValue, double elseValue)
12894 : {
12895 : #ifndef HAVE_MUPARSER
12896 : (void)condBand;
12897 : (void)thenValue;
12898 : (void)elseValue;
12899 : return ThrowIfNotMuparser();
12900 : #else
12901 : auto thenBand =
12902 3 : (condBand * 0)
12903 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12904 6 : thenValue;
12905 : auto elseBand =
12906 3 : (condBand * 0)
12907 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12908 3 : elseValue;
12909 : return GDALComputedRasterBand(
12910 : GDALComputedRasterBand::Operation::OP_TERNARY,
12911 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12912 : #endif
12913 : }
12914 :
12915 : //! @endcond
12916 :
12917 : } // namespace gdal
12918 :
12919 : /************************************************************************/
12920 : /* GDALRasterBandIfThenElse() */
12921 : /************************************************************************/
12922 :
12923 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12924 : * is not zero, or the one from hElseBand otherwise.
12925 : *
12926 : * The resulting band is lazy evaluated. A reference is taken on the input
12927 : * datasets.
12928 : *
12929 : * This function is the same as the C++ method gdal::IfThenElse()
12930 : *
12931 : * @since 3.12
12932 : */
12933 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12934 : GDALRasterBandH hThenBand,
12935 : GDALRasterBandH hElseBand)
12936 : {
12937 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12938 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12939 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12940 : #ifndef HAVE_MUPARSER
12941 : CPLError(CE_Failure, CPLE_NotSupported,
12942 : "Band comparison operators not available on a GDAL build without "
12943 : "muparser");
12944 : return nullptr;
12945 : #else
12946 :
12947 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12948 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12949 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12950 : try
12951 : {
12952 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12953 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12954 : }
12955 2 : catch (const std::exception &e)
12956 : {
12957 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12958 2 : return nullptr;
12959 : }
12960 : return new GDALComputedRasterBand(
12961 : GDALComputedRasterBand::Operation::OP_TERNARY,
12962 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12963 : #endif
12964 : }
12965 :
12966 : /************************************************************************/
12967 : /* GDALRasterBand::AsType() */
12968 : /************************************************************************/
12969 :
12970 : /** Cast this band to another type.
12971 : *
12972 : * The resulting band is lazy evaluated. A reference is taken on the input
12973 : * dataset.
12974 : *
12975 : * This method is the same as the C function GDALRasterBandAsDataType()
12976 : *
12977 : * @since 3.12
12978 : */
12979 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12980 : {
12981 10 : if (dt == GDT_Unknown)
12982 : {
12983 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12984 : }
12985 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12986 9 : *this, dt);
12987 : }
12988 :
12989 : /************************************************************************/
12990 : /* GDALRasterBandAsDataType() */
12991 : /************************************************************************/
12992 :
12993 : /** Cast this band to another type.
12994 : *
12995 : * The resulting band is lazy evaluated. A reference is taken on the input
12996 : * dataset.
12997 : *
12998 : * This function is the same as the C++ method GDALRasterBand::AsType()
12999 : *
13000 : * @since 3.12
13001 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13002 : */
13003 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
13004 : GDALDataType eDT)
13005 : {
13006 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
13007 16 : if (eDT == GDT_Unknown)
13008 : {
13009 1 : CPLError(CE_Failure, CPLE_NotSupported,
13010 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
13011 1 : return nullptr;
13012 : }
13013 : return new GDALComputedRasterBand(
13014 : GDALComputedRasterBand::Operation::OP_CAST,
13015 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
13016 : }
13017 :
13018 : /************************************************************************/
13019 : /* GetBandVector() */
13020 : /************************************************************************/
13021 :
13022 : static std::vector<const GDALRasterBand *>
13023 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
13024 : {
13025 10 : std::vector<const GDALRasterBand *> bands;
13026 27 : for (size_t i = 0; i < nBandCount; ++i)
13027 : {
13028 20 : if (i > 0)
13029 : {
13030 10 : GDALRasterBand::ThrowIfNotSameDimensions(
13031 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
13032 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
13033 : }
13034 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
13035 : }
13036 7 : return bands;
13037 : }
13038 :
13039 : /************************************************************************/
13040 : /* GDALOperationOnNBands() */
13041 : /************************************************************************/
13042 :
13043 : static GDALComputedRasterBandH
13044 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
13045 : GDALRasterBandH *pahBands)
13046 : {
13047 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
13048 11 : if (nBandCount == 0)
13049 : {
13050 1 : CPLError(CE_Failure, CPLE_AppDefined,
13051 : "At least one band should be passed");
13052 1 : return nullptr;
13053 : }
13054 :
13055 20 : std::vector<const GDALRasterBand *> bands;
13056 : try
13057 : {
13058 10 : bands = GetBandVector(nBandCount, pahBands);
13059 : }
13060 3 : catch (const std::exception &e)
13061 : {
13062 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
13063 3 : return nullptr;
13064 : }
13065 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
13066 : }
13067 :
13068 : /************************************************************************/
13069 : /* GDALMaximumOfNBands() */
13070 : /************************************************************************/
13071 :
13072 : /** Return a band whose each pixel value is the maximum of the corresponding
13073 : * pixel values in the input bands.
13074 : *
13075 : * The resulting band is lazy evaluated. A reference is taken on input
13076 : * datasets.
13077 : *
13078 : * This function is the same as the C ++ method gdal::max()
13079 : *
13080 : * @since 3.12
13081 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13082 : */
13083 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
13084 : GDALRasterBandH *pahBands)
13085 : {
13086 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
13087 4 : nBandCount, pahBands);
13088 : }
13089 :
13090 : /************************************************************************/
13091 : /* gdal::max() */
13092 : /************************************************************************/
13093 :
13094 : namespace gdal
13095 : {
13096 : /** Return a band whose each pixel value is the maximum of the corresponding
13097 : * pixel values in the inputs (bands or constants)
13098 : *
13099 : * The resulting band is lazy evaluated. A reference is taken on input
13100 : * datasets.
13101 : *
13102 : * Two or more bands can be passed.
13103 : *
13104 : * This method is the same as the C function GDALMaximumOfNBands()
13105 : *
13106 : * @since 3.12
13107 : * @throw std::runtime_error if bands do not have the same dimensions.
13108 : */
13109 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
13110 : const GDALRasterBand &second)
13111 : {
13112 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13113 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13114 1 : first, second);
13115 : }
13116 : } // namespace gdal
13117 :
13118 : /************************************************************************/
13119 : /* GDALRasterBandMaxConstant() */
13120 : /************************************************************************/
13121 :
13122 : /** Return a band whose each pixel value is the maximum of the corresponding
13123 : * pixel values in the input band and the constant.
13124 : *
13125 : * The resulting band is lazy evaluated. A reference is taken on the input
13126 : * dataset.
13127 : *
13128 : * This function is the same as the C ++ method gdal::max()
13129 : *
13130 : * @since 3.12
13131 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13132 : */
13133 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13134 : double dfConstant)
13135 : {
13136 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13137 : GDALComputedRasterBand::Operation::OP_MAX,
13138 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13139 6 : dfConstant));
13140 : }
13141 :
13142 : /************************************************************************/
13143 : /* GDALMinimumOfNBands() */
13144 : /************************************************************************/
13145 :
13146 : /** Return a band whose each pixel value is the minimum of the corresponding
13147 : * pixel values in the input bands.
13148 : *
13149 : * The resulting band is lazy evaluated. A reference is taken on input
13150 : * datasets.
13151 : *
13152 : * This function is the same as the C ++ method gdal::min()
13153 : *
13154 : * @since 3.12
13155 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13156 : */
13157 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13158 : GDALRasterBandH *pahBands)
13159 : {
13160 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13161 4 : nBandCount, pahBands);
13162 : }
13163 :
13164 : /************************************************************************/
13165 : /* gdal::min() */
13166 : /************************************************************************/
13167 :
13168 : namespace gdal
13169 : {
13170 : /** Return a band whose each pixel value is the minimum of the corresponding
13171 : * pixel values in the inputs (bands or constants)
13172 : *
13173 : * The resulting band is lazy evaluated. A reference is taken on input
13174 : * datasets.
13175 : *
13176 : * Two or more bands can be passed.
13177 : *
13178 : * This method is the same as the C function GDALMinimumOfNBands()
13179 : *
13180 : * @since 3.12
13181 : * @throw std::runtime_error if bands do not have the same dimensions.
13182 : */
13183 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
13184 : const GDALRasterBand &second)
13185 : {
13186 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13187 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13188 0 : first, second);
13189 : }
13190 : } // namespace gdal
13191 :
13192 : /************************************************************************/
13193 : /* GDALRasterBandMinConstant() */
13194 : /************************************************************************/
13195 :
13196 : /** Return a band whose each pixel value is the minimum of the corresponding
13197 : * pixel values in the input band and the constant.
13198 : *
13199 : * The resulting band is lazy evaluated. A reference is taken on the input
13200 : * dataset.
13201 : *
13202 : * This function is the same as the C ++ method gdal::min()
13203 : *
13204 : * @since 3.12
13205 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13206 : */
13207 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13208 : double dfConstant)
13209 : {
13210 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13211 : GDALComputedRasterBand::Operation::OP_MIN,
13212 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13213 6 : dfConstant));
13214 : }
13215 :
13216 : /************************************************************************/
13217 : /* GDALMeanOfNBands() */
13218 : /************************************************************************/
13219 :
13220 : /** Return a band whose each pixel value is the arithmetic mean of the
13221 : * corresponding pixel values in the input bands.
13222 : *
13223 : * The resulting band is lazy evaluated. A reference is taken on input
13224 : * datasets.
13225 : *
13226 : * This function is the same as the C ++ method gdal::mean()
13227 : *
13228 : * @since 3.12
13229 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13230 : */
13231 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13232 : GDALRasterBandH *pahBands)
13233 : {
13234 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13235 3 : nBandCount, pahBands);
13236 : }
13237 :
13238 : /************************************************************************/
13239 : /* gdal::mean() */
13240 : /************************************************************************/
13241 :
13242 : namespace gdal
13243 : {
13244 :
13245 : /** Return a band whose each pixel value is the arithmetic mean of the
13246 : * corresponding pixel values in the input bands.
13247 : *
13248 : * The resulting band is lazy evaluated. A reference is taken on input
13249 : * datasets.
13250 : *
13251 : * Two or more bands can be passed.
13252 : *
13253 : * This method is the same as the C function GDALMeanOfNBands()
13254 : *
13255 : * @since 3.12
13256 : * @throw std::runtime_error if bands do not have the same dimensions.
13257 : */
13258 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
13259 : const GDALRasterBand &second)
13260 : {
13261 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13262 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13263 0 : first, second);
13264 : }
13265 : } // namespace gdal
13266 :
13267 : /************************************************************************/
13268 : /* gdal::abs() */
13269 : /************************************************************************/
13270 :
13271 : namespace gdal
13272 : {
13273 :
13274 : /** Return a band whose each pixel value is the absolute value (or module
13275 : * for complex data type) of the corresponding pixel value in the input band.
13276 : *
13277 : * The resulting band is lazy evaluated. A reference is taken on input
13278 : * datasets.
13279 : *
13280 : * @since 3.12
13281 : */
13282 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
13283 : {
13284 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13285 1 : band);
13286 : }
13287 : } // namespace gdal
13288 :
13289 : /************************************************************************/
13290 : /* gdal::fabs() */
13291 : /************************************************************************/
13292 :
13293 : namespace gdal
13294 : {
13295 :
13296 : /** Return a band whose each pixel value is the absolute value (or module
13297 : * for complex data type) of the corresponding pixel value in the input band.
13298 : *
13299 : * The resulting band is lazy evaluated. A reference is taken on input
13300 : * datasets.
13301 : *
13302 : * @since 3.12
13303 : */
13304 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
13305 : {
13306 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13307 1 : band);
13308 : }
13309 : } // namespace gdal
13310 :
13311 : /************************************************************************/
13312 : /* gdal::sqrt() */
13313 : /************************************************************************/
13314 :
13315 : namespace gdal
13316 : {
13317 :
13318 : /** Return a band whose each pixel value is the square root of the
13319 : * corresponding pixel value in the input band.
13320 : *
13321 : * The resulting band is lazy evaluated. A reference is taken on input
13322 : * datasets.
13323 : *
13324 : * @since 3.12
13325 : */
13326 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13327 : {
13328 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13329 1 : band);
13330 : }
13331 : } // namespace gdal
13332 :
13333 : /************************************************************************/
13334 : /* gdal::log() */
13335 : /************************************************************************/
13336 :
13337 : namespace gdal
13338 : {
13339 :
13340 : /** Return a band whose each pixel value is the natural logarithm of the
13341 : * corresponding pixel value in the input band.
13342 : *
13343 : * The resulting band is lazy evaluated. A reference is taken on input
13344 : * datasets.
13345 : *
13346 : * @since 3.12
13347 : */
13348 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
13349 : {
13350 : #ifndef HAVE_MUPARSER
13351 : (void)band;
13352 : return ThrowIfNotMuparser();
13353 : #else
13354 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13355 1 : band);
13356 : #endif
13357 : }
13358 : } // namespace gdal
13359 :
13360 : /************************************************************************/
13361 : /* gdal::log10() */
13362 : /************************************************************************/
13363 :
13364 : namespace gdal
13365 : {
13366 :
13367 : /** Return a band whose each pixel value is the logarithm base 10 of the
13368 : * corresponding pixel value in the input band.
13369 : *
13370 : * The resulting band is lazy evaluated. A reference is taken on input
13371 : * datasets.
13372 : *
13373 : * @since 3.12
13374 : */
13375 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
13376 : {
13377 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13378 1 : band);
13379 : }
13380 : } // namespace gdal
13381 :
13382 : /************************************************************************/
13383 : /* gdal::pow() */
13384 : /************************************************************************/
13385 :
13386 : namespace gdal
13387 : {
13388 :
13389 : #ifndef DOXYGEN_SKIP
13390 : /** Return a band whose each pixel value is the constant raised to the power of
13391 : * the corresponding pixel value in the input band.
13392 : *
13393 : * The resulting band is lazy evaluated. A reference is taken on input
13394 : * datasets.
13395 : *
13396 : * @since 3.12
13397 : */
13398 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13399 : {
13400 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13401 1 : constant, band);
13402 : }
13403 : #endif
13404 :
13405 : } // namespace gdal
13406 :
13407 : /************************************************************************/
13408 : /* gdal::pow() */
13409 : /************************************************************************/
13410 :
13411 : namespace gdal
13412 : {
13413 :
13414 : /** Return a band whose each pixel value is the the corresponding pixel value
13415 : * in the input band raised to the power of the constant.
13416 : *
13417 : * The resulting band is lazy evaluated. A reference is taken on input
13418 : * datasets.
13419 : *
13420 : * @since 3.12
13421 : */
13422 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13423 : {
13424 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13425 1 : band, constant);
13426 : }
13427 : } // namespace gdal
13428 :
13429 : /************************************************************************/
13430 : /* gdal::pow() */
13431 : /************************************************************************/
13432 :
13433 : namespace gdal
13434 : {
13435 :
13436 : #ifndef DOXYGEN_SKIP
13437 : /** Return a band whose each pixel value is the the corresponding pixel value
13438 : * in the input band1 raised to the power of the corresponding pixel value
13439 : * in the input band2
13440 : *
13441 : * The resulting band is lazy evaluated. A reference is taken on input
13442 : * datasets.
13443 : *
13444 : * @since 3.12
13445 : * @throw std::runtime_error if bands do not have the same dimensions.
13446 : */
13447 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
13448 : const GDALRasterBand &band2)
13449 : {
13450 : #ifndef HAVE_MUPARSER
13451 : (void)band1;
13452 : (void)band2;
13453 : return ThrowIfNotMuparser();
13454 : #else
13455 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13456 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13457 1 : band1, band2);
13458 : #endif
13459 : }
13460 : #endif
13461 : } // namespace gdal
|