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 <cassert>
19 : #include <climits>
20 : #include <cmath>
21 : #include <cstdarg>
22 : #include <cstddef>
23 : #include <cstdio>
24 : #include <cstdlib>
25 : #include <cstring>
26 : #include <algorithm>
27 : #include <limits>
28 : #include <memory>
29 : #include <new>
30 : #include <numeric> // std::lcm
31 : #include <type_traits>
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_float.h"
36 : #include "cpl_multiproc.h"
37 : #include "cpl_progress.h"
38 : #include "cpl_string.h"
39 : #include "cpl_virtualmem.h"
40 : #include "cpl_vsi.h"
41 : #include "cpl_worker_thread_pool.h"
42 : #include "gdal.h"
43 : #include "gdal_abstractbandblockcache.h"
44 : #include "gdalantirecursion.h"
45 : #include "gdal_rat.h"
46 : #include "gdal_rasterband.h"
47 : #include "gdal_priv_templates.hpp"
48 : #include "gdal_interpolateatpoint.h"
49 : #include "gdal_minmax_element.hpp"
50 : #include "gdalmultidim_priv.h"
51 : #include "gdal_thread_pool.h"
52 :
53 : #ifdef USE_NEON_OPTIMIZATIONS
54 : #include "include_sse2neon.h"
55 : #endif
56 :
57 : #if defined(__AVX2__) || defined(__FMA__)
58 : #include <immintrin.h>
59 : #endif
60 :
61 : /************************************************************************/
62 : /* GDALRasterBand() */
63 : /************************************************************************/
64 :
65 : /*! Constructor. Applications should never create GDALRasterBands directly. */
66 :
67 1578410 : GDALRasterBand::GDALRasterBand()
68 : : GDALRasterBand(
69 1578410 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
70 : {
71 1578410 : }
72 :
73 : /** Constructor. Applications should never create GDALRasterBands directly.
74 : * @param bForceCachedIOIn Whether cached IO should be forced.
75 : */
76 1860100 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
77 1860100 : : bForceCachedIO(bForceCachedIOIn)
78 :
79 : {
80 1860100 : }
81 :
82 : /************************************************************************/
83 : /* ~GDALRasterBand() */
84 : /************************************************************************/
85 :
86 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
87 : instead destroy the GDALDataset. */
88 :
89 1860100 : GDALRasterBand::~GDALRasterBand()
90 :
91 : {
92 1860100 : if (poDS && poDS->IsMarkedSuppressOnClose())
93 : {
94 592 : if (poBandBlockCache)
95 529 : poBandBlockCache->DisableDirtyBlockWriting();
96 : }
97 1860100 : GDALRasterBand::FlushCache(true);
98 :
99 1860100 : delete poBandBlockCache;
100 :
101 1860100 : if (static_cast<GIntBig>(nBlockReads) >
102 1860100 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
103 228 : nBand == 1 && poDS != nullptr)
104 : {
105 336 : CPLDebug(
106 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
107 168 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
108 168 : poDS->GetDescription());
109 : }
110 :
111 1860100 : InvalidateMaskBand();
112 1860100 : nBand = -nBand;
113 :
114 1860100 : delete m_poPointsCache;
115 1860100 : }
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 4667110 : 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 4667110 : if (psExtraArg == nullptr)
348 : {
349 4061000 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
350 4061000 : psExtraArg = &sExtraArg;
351 : }
352 606108 : 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 4667110 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
361 : nBufYSize);
362 :
363 4667110 : 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 4667110 : 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 4667110 : if (eRWFlag == GF_Write)
387 : {
388 402816 : 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 402816 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
398 : {
399 7 : 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 4667100 : if (nPixelSpace == 0)
408 : {
409 4260340 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
410 : }
411 :
412 4667100 : if (nLineSpace == 0)
413 : {
414 4247940 : nLineSpace = nPixelSpace * nBufXSize;
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Do some validation of parameters. */
419 : /* -------------------------------------------------------------------- */
420 4667100 : 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 4667080 : 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 4667080 : 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 4667080 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
446 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
447 4667080 : nLineSpace, psExtraArg);
448 : }
449 :
450 : /************************************************************************/
451 : /* RasterIOInternal() */
452 : /************************************************************************/
453 :
454 4667180 : 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 4667180 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
464 :
465 : CPLErr eErr;
466 4667180 : 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 4667160 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
473 4667160 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
474 :
475 4667180 : if (bCallLeaveReadWrite)
476 612398 : LeaveReadWrite();
477 :
478 4667180 : 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 3589600 : 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 3589600 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
502 :
503 3589600 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
504 :
505 3589600 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
506 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
507 3589600 : 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 42371 : 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 42371 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
529 :
530 42371 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
531 :
532 42371 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
533 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
534 42371 : 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 : sExtraArg.nVersion = 1;
703 18 : sExtraArg.eResampleAlg = eResampleAlg;
704 18 : sExtraArg.pfnProgress = pfnProgress;
705 18 : sExtraArg.pProgressData = pProgressData;
706 18 : sExtraArg.bFloatingPointWindowValidity = true;
707 18 : sExtraArg.dfXOff = dfXOff;
708 18 : sExtraArg.dfYOff = dfYOff;
709 18 : sExtraArg.dfXSize = dfXSize;
710 18 : sExtraArg.dfYSize = dfYSize;
711 18 : const int nXOff = static_cast<int>(dfXOff);
712 18 : const int nYOff = static_cast<int>(dfYOff);
713 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
714 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
715 18 : if (nBufXSize == 0 && nBufYSize == 0)
716 : {
717 17 : if (static_cast<int>(dfXSize) == dfXSize &&
718 17 : static_cast<int>(dfYSize) == dfYSize)
719 : {
720 17 : nBufXSize = static_cast<int>(dfXSize);
721 17 : nBufYSize = static_cast<int>(dfYSize);
722 : }
723 : else
724 : {
725 0 : CPLError(CE_Failure, CPLE_AppDefined,
726 : "nBufXSize and nBufYSize must be provided if dfXSize or "
727 : "dfYSize is not an integer value");
728 0 : return CE_Failure;
729 : }
730 : }
731 18 : if (nBufXSize == 0 || nBufYSize == 0)
732 : {
733 0 : CPLDebug("GDAL",
734 : "RasterIO() skipped for odd window or buffer size.\n"
735 : " Window = (%d,%d)x%dx%d\n"
736 : " Buffer = %dx%d\n",
737 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
738 : static_cast<int>(nBufYSize));
739 :
740 0 : return CE_None;
741 : }
742 :
743 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
744 : {
745 1 : CPLError(CE_Failure, CPLE_AppDefined,
746 : "Provided array is not large enough");
747 1 : return CE_Failure;
748 : }
749 :
750 17 : constexpr GSpacing nPixelSpace = sizeof(T);
751 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
752 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
753 :
754 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
755 :
756 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
757 : static_cast<int>(nBufXSize),
758 : static_cast<int>(nBufYSize), eBufType,
759 17 : nPixelSpace, nLineSpace, &sExtraArg);
760 : }
761 :
762 : //! @cond Doxygen_Suppress
763 :
764 : #define INSTANTIATE_READ_RASTER(T) \
765 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
766 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
767 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
768 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
769 : void *pProgressData) const;
770 :
771 : INSTANTIATE_READ_RASTER(uint8_t)
772 : INSTANTIATE_READ_RASTER(int8_t)
773 : INSTANTIATE_READ_RASTER(uint16_t)
774 : INSTANTIATE_READ_RASTER(int16_t)
775 : INSTANTIATE_READ_RASTER(uint32_t)
776 : INSTANTIATE_READ_RASTER(int32_t)
777 : INSTANTIATE_READ_RASTER(uint64_t)
778 : INSTANTIATE_READ_RASTER(int64_t)
779 : INSTANTIATE_READ_RASTER(GFloat16)
780 : INSTANTIATE_READ_RASTER(float)
781 : INSTANTIATE_READ_RASTER(double)
782 : // Not allowed by C++ standard
783 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
784 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
785 : INSTANTIATE_READ_RASTER(std::complex<float>)
786 : INSTANTIATE_READ_RASTER(std::complex<double>)
787 :
788 : //! @endcond
789 :
790 : /************************************************************************/
791 : /* ReadRaster() */
792 : /************************************************************************/
793 :
794 : /** Read a region of image data for this band.
795 : *
796 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
797 : * for common use cases, like reading a whole band.
798 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
799 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
800 : * float, double, std::complex<float|double>.
801 : *
802 : * To read a whole band (assuming it fits into memory), as a vector of double:
803 : *
804 : \code
805 : std::vector<double> myArray;
806 : if (poBand->ReadRaster(myArray) == CE_None)
807 : {
808 : // do something
809 : }
810 : \endcode
811 : *
812 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
813 : *
814 : \code{.cpp}
815 : std::vector<double> myArray;
816 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
817 : {
818 : // do something
819 : }
820 : \endcode
821 : *
822 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
823 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
824 : * instance of this dataset) concurrently from several threads.
825 : *
826 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
827 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
828 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
829 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
830 : * Or use nLineSpace and a possibly shifted pData value.
831 : *
832 : * @param[out] vData The vector into which the data should be written.
833 : * The vector will be resized, if needed, to contain at least nBufXSize *
834 : * nBufYSize values. The values in the vector are organized in left to right,
835 : * top to bottom pixel order, and fully packed.
836 : * The type of the vector does not need to be the one of GetDataType(). The
837 : * method will perform data type translation (with potential rounding, clamping)
838 : * if needed.
839 : *
840 : * @param dfXOff The pixel offset to the top left corner of the region
841 : * of the band to be accessed. This would be zero to start from the left side.
842 : * Defaults to 0.
843 : *
844 : * @param dfYOff The line offset to the top left corner of the region
845 : * of the band to be accessed. This would be zero to start from the top.
846 : * Defaults to 0.
847 : *
848 : * @param dfXSize The width of the region of the band to be accessed in pixels.
849 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
850 : * dfXSize is set to the band width.
851 : *
852 : * @param dfYSize The height of the region of the band to be accessed in lines.
853 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
854 : * dfYSize is set to the band height.
855 : *
856 : * @param nBufXSize the width of the buffer image into which the desired region
857 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
858 : * then nBufXSize is initialized with dfXSize.
859 : *
860 : * @param nBufYSize the height of the buffer image into which the desired region
861 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
862 : * then nBufYSize is initialized with dfYSize.
863 : *
864 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
865 : *
866 : * @param pfnProgress Progress function. May be nullptr.
867 : *
868 : * @param pProgressData User data of pfnProgress. May be nullptr.
869 : *
870 : * @return CE_Failure if the access fails, otherwise CE_None.
871 : *
872 : * @see GDALRasterBand::RasterIO()
873 : * @since GDAL 3.10
874 : */
875 : template <class T>
876 90 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
877 : double dfYOff, double dfXSize, double dfYSize,
878 : size_t nBufXSize, size_t nBufYSize,
879 : GDALRIOResampleAlg eResampleAlg,
880 : GDALProgressFunc pfnProgress,
881 : void *pProgressData) const
882 : {
883 90 : if (((nBufXSize | nBufYSize) >> 31) != 0)
884 : {
885 2 : return CE_Failure;
886 : }
887 :
888 88 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
889 : {
890 81 : dfXSize = nRasterXSize;
891 81 : dfYSize = nRasterYSize;
892 : }
893 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
894 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
895 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
896 7 : dfYOff + dfYSize > INT_MAX)
897 : {
898 0 : return CE_Failure;
899 : }
900 :
901 : GDALRasterIOExtraArg sExtraArg;
902 88 : sExtraArg.nVersion = 1;
903 88 : sExtraArg.eResampleAlg = eResampleAlg;
904 88 : sExtraArg.pfnProgress = pfnProgress;
905 88 : sExtraArg.pProgressData = pProgressData;
906 88 : sExtraArg.bFloatingPointWindowValidity = true;
907 88 : sExtraArg.dfXOff = dfXOff;
908 88 : sExtraArg.dfYOff = dfYOff;
909 88 : sExtraArg.dfXSize = dfXSize;
910 88 : sExtraArg.dfYSize = dfYSize;
911 88 : const int nXOff = static_cast<int>(dfXOff);
912 88 : const int nYOff = static_cast<int>(dfYOff);
913 88 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
914 88 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
915 88 : if (nBufXSize == 0 && nBufYSize == 0)
916 : {
917 84 : if (static_cast<int>(dfXSize) == dfXSize &&
918 83 : static_cast<int>(dfYSize) == dfYSize)
919 : {
920 83 : nBufXSize = static_cast<int>(dfXSize);
921 83 : nBufYSize = static_cast<int>(dfYSize);
922 : }
923 : else
924 : {
925 1 : CPLError(CE_Failure, CPLE_AppDefined,
926 : "nBufXSize and nBufYSize must be provided if "
927 : "dfXSize or dfYSize is not an integer value");
928 1 : return CE_Failure;
929 : }
930 : }
931 87 : if (nBufXSize == 0 || nBufYSize == 0)
932 : {
933 0 : CPLDebug("GDAL",
934 : "RasterIO() skipped for odd window or buffer size.\n"
935 : " Window = (%d,%d)x%dx%d\n"
936 : " Buffer = %dx%d\n",
937 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
938 : static_cast<int>(nBufYSize));
939 :
940 0 : return CE_None;
941 : }
942 :
943 : if constexpr (SIZEOF_VOIDP < 8)
944 : {
945 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
946 : {
947 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
948 : return CE_Failure;
949 : }
950 : }
951 :
952 87 : if (vData.size() < nBufXSize * nBufYSize)
953 : {
954 : try
955 : {
956 85 : vData.resize(nBufXSize * nBufYSize);
957 : }
958 1 : catch (const std::exception &)
959 : {
960 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
961 1 : return CE_Failure;
962 : }
963 : }
964 :
965 86 : constexpr GSpacing nPixelSpace = sizeof(T);
966 86 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
967 86 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
968 :
969 86 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
970 :
971 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
972 : vData.data(), static_cast<int>(nBufXSize),
973 : static_cast<int>(nBufYSize), eBufType,
974 86 : nPixelSpace, nLineSpace, &sExtraArg);
975 : }
976 :
977 : //! @cond Doxygen_Suppress
978 :
979 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
980 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
981 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
982 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
983 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
984 : void *pProgressData) const;
985 :
986 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
988 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
989 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
990 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
991 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
992 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
993 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
994 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
995 : INSTANTIATE_READ_RASTER_VECTOR(float)
996 : INSTANTIATE_READ_RASTER_VECTOR(double)
997 : // Not allowed by C++ standard
998 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
999 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1000 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1001 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1002 :
1003 : //! @endcond
1004 :
1005 : /************************************************************************/
1006 : /* ReadBlock() */
1007 : /************************************************************************/
1008 :
1009 : /**
1010 : * \brief Read a block of image data efficiently.
1011 : *
1012 : * This method accesses a "natural" block from the raster band without
1013 : * resampling, or data type conversion. For a more generalized, but
1014 : * potentially less efficient access use RasterIO().
1015 : *
1016 : * This method is the same as the C GDALReadBlock() function.
1017 : *
1018 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1019 : * block oriented data without an extra copy into an application buffer.
1020 : *
1021 : * The following code would efficiently compute a histogram of eight bit
1022 : * raster data. Note that the final block may be partial ... data beyond
1023 : * the edge of the underlying raster band in these edge blocks is of an
1024 : * undetermined value.
1025 : *
1026 : \code{.cpp}
1027 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1028 :
1029 : {
1030 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1031 :
1032 : CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1033 :
1034 : int nXBlockSize, nYBlockSize;
1035 :
1036 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1037 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1038 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1039 :
1040 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1041 :
1042 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1043 : {
1044 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1045 : {
1046 : int nXValid, nYValid;
1047 :
1048 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1049 :
1050 : // Compute the portion of the block that is valid
1051 : // for partial edge blocks.
1052 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1053 :
1054 : // Collect the histogram counts.
1055 : for( int iY = 0; iY < nYValid; iY++ )
1056 : {
1057 : for( int iX = 0; iX < nXValid; iX++ )
1058 : {
1059 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1060 : }
1061 : }
1062 : }
1063 : }
1064 : }
1065 : \endcode
1066 : *
1067 : * @param nXBlockOff the horizontal block offset, with zero indicating
1068 : * the left most block, 1 the next block and so forth.
1069 : *
1070 : * @param nYBlockOff the vertical block offset, with zero indicating
1071 : * the top most block, 1 the next block and so forth.
1072 : *
1073 : * @param pImage the buffer into which the data will be read. The buffer
1074 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1075 : * of type GetRasterDataType().
1076 : *
1077 : * @return CE_None on success or CE_Failure on an error.
1078 : */
1079 :
1080 1040 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1081 :
1082 : {
1083 : /* -------------------------------------------------------------------- */
1084 : /* Validate arguments. */
1085 : /* -------------------------------------------------------------------- */
1086 1040 : CPLAssert(pImage != nullptr);
1087 :
1088 1040 : if (!InitBlockInfo())
1089 0 : return CE_Failure;
1090 :
1091 1040 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1092 : {
1093 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1094 : "Illegal nXBlockOff value (%d) in "
1095 : "GDALRasterBand::ReadBlock()\n",
1096 : nXBlockOff);
1097 :
1098 0 : return (CE_Failure);
1099 : }
1100 :
1101 1040 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1102 : {
1103 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1104 : "Illegal nYBlockOff value (%d) in "
1105 : "GDALRasterBand::ReadBlock()\n",
1106 : nYBlockOff);
1107 :
1108 0 : return (CE_Failure);
1109 : }
1110 :
1111 : /* -------------------------------------------------------------------- */
1112 : /* Invoke underlying implementation method. */
1113 : /* -------------------------------------------------------------------- */
1114 :
1115 1040 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1116 1040 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1117 1040 : if (bCallLeaveReadWrite)
1118 4 : LeaveReadWrite();
1119 1040 : return eErr;
1120 : }
1121 :
1122 : /************************************************************************/
1123 : /* GDALReadBlock() */
1124 : /************************************************************************/
1125 :
1126 : /**
1127 : * \brief Read a block of image data efficiently.
1128 : *
1129 : * @see GDALRasterBand::ReadBlock()
1130 : */
1131 :
1132 79 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1133 : void *pData)
1134 :
1135 : {
1136 79 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1137 :
1138 79 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1139 79 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1140 : }
1141 :
1142 : /************************************************************************/
1143 : /* IReadBlock() */
1144 : /************************************************************************/
1145 :
1146 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1147 : * ) \brief Read a block of data.
1148 : *
1149 : * Default internal implementation ... to be overridden by
1150 : * subclasses that support reading.
1151 : * @param nBlockXOff Block X Offset
1152 : * @param nBlockYOff Block Y Offset
1153 : * @param pData Pixel buffer into which to place read data.
1154 : * @return CE_None on success or CE_Failure on an error.
1155 : */
1156 :
1157 : /************************************************************************/
1158 : /* IWriteBlock() */
1159 : /************************************************************************/
1160 :
1161 : /**
1162 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1163 : * Write a block of data.
1164 : *
1165 : * Default internal implementation ... to be overridden by
1166 : * subclasses that support writing.
1167 : * @param nBlockXOff Block X Offset
1168 : * @param nBlockYOff Block Y Offset
1169 : * @param pData Pixel buffer to write
1170 : * @return CE_None on success or CE_Failure on an error.
1171 : */
1172 :
1173 : /**/
1174 : /**/
1175 :
1176 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1177 : void * /*pData*/)
1178 :
1179 : {
1180 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1181 0 : ReportError(CE_Failure, CPLE_NotSupported,
1182 : "WriteBlock() not supported for this dataset.");
1183 :
1184 0 : return (CE_Failure);
1185 : }
1186 :
1187 : /************************************************************************/
1188 : /* WriteBlock() */
1189 : /************************************************************************/
1190 :
1191 : /**
1192 : * \brief Write a block of image data efficiently.
1193 : *
1194 : * This method accesses a "natural" block from the raster band without
1195 : * resampling, or data type conversion. For a more generalized, but
1196 : * potentially less efficient access use RasterIO().
1197 : *
1198 : * This method is the same as the C GDALWriteBlock() function.
1199 : *
1200 : * See ReadBlock() for an example of block oriented data access.
1201 : *
1202 : * @param nXBlockOff the horizontal block offset, with zero indicating
1203 : * the left most block, 1 the next block and so forth.
1204 : *
1205 : * @param nYBlockOff the vertical block offset, with zero indicating
1206 : * the left most block, 1 the next block and so forth.
1207 : *
1208 : * @param pImage the buffer from which the data will be written. The buffer
1209 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1210 : * of type GetRasterDataType(). Note that the content of the buffer might be
1211 : * temporarily modified during the execution of this method (and eventually
1212 : * restored back to its original content), so it is not safe to use a buffer
1213 : * stored in a read-only section of the calling program.
1214 : *
1215 : * @return CE_None on success or CE_Failure on an error.
1216 : */
1217 :
1218 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1219 :
1220 : {
1221 : /* -------------------------------------------------------------------- */
1222 : /* Validate arguments. */
1223 : /* -------------------------------------------------------------------- */
1224 4883 : CPLAssert(pImage != nullptr);
1225 :
1226 4883 : if (!InitBlockInfo())
1227 0 : return CE_Failure;
1228 :
1229 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1230 : {
1231 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1232 : "Illegal nXBlockOff value (%d) in "
1233 : "GDALRasterBand::WriteBlock()\n",
1234 : nXBlockOff);
1235 :
1236 0 : return (CE_Failure);
1237 : }
1238 :
1239 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1240 : {
1241 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1242 : "Illegal nYBlockOff value (%d) in "
1243 : "GDALRasterBand::WriteBlock()\n",
1244 : nYBlockOff);
1245 :
1246 0 : return (CE_Failure);
1247 : }
1248 :
1249 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1250 : {
1251 0 : return CE_Failure;
1252 : }
1253 :
1254 4883 : if (eFlushBlockErr != CE_None)
1255 : {
1256 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1257 : "An error occurred while writing a dirty block "
1258 : "from GDALRasterBand::WriteBlock");
1259 0 : CPLErr eErr = eFlushBlockErr;
1260 0 : eFlushBlockErr = CE_None;
1261 0 : return eErr;
1262 : }
1263 :
1264 : /* -------------------------------------------------------------------- */
1265 : /* Invoke underlying implementation method. */
1266 : /* -------------------------------------------------------------------- */
1267 :
1268 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1269 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1270 4883 : if (bCallLeaveReadWrite)
1271 4883 : LeaveReadWrite();
1272 :
1273 4883 : return eErr;
1274 : }
1275 :
1276 : /************************************************************************/
1277 : /* GDALWriteBlock() */
1278 : /************************************************************************/
1279 :
1280 : /**
1281 : * \brief Write a block of image data efficiently.
1282 : *
1283 : * @see GDALRasterBand::WriteBlock()
1284 : */
1285 :
1286 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1287 : void *pData)
1288 :
1289 : {
1290 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1291 :
1292 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1293 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1294 : }
1295 :
1296 : /************************************************************************/
1297 : /* EmitErrorMessageIfWriteNotSupported() */
1298 : /************************************************************************/
1299 :
1300 : /**
1301 : * Emit an error message if a write operation to this band is not supported.
1302 : *
1303 : * The base implementation will emit an error message if the access mode is
1304 : * read-only. Derived classes may implement it to provide a custom message.
1305 : *
1306 : * @param pszCaller Calling function.
1307 : * @return true if an error message has been emitted.
1308 : */
1309 676669 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1310 : const char *pszCaller) const
1311 : {
1312 676669 : if (eAccess == GA_ReadOnly)
1313 : {
1314 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1315 : "%s: attempt to write to dataset opened in read-only mode.",
1316 : pszCaller);
1317 :
1318 4 : return true;
1319 : }
1320 676665 : return false;
1321 : }
1322 :
1323 : /************************************************************************/
1324 : /* GetActualBlockSize() */
1325 : /************************************************************************/
1326 : /**
1327 : * \brief Fetch the actual block size for a given block offset.
1328 : *
1329 : * Handles partial blocks at the edges of the raster and returns the true
1330 : * number of pixels
1331 : *
1332 : * @param nXBlockOff the horizontal block offset for which to calculate the
1333 : * number of valid pixels, with zero indicating the left most block, 1 the next
1334 : * block and so forth.
1335 : *
1336 : * @param nYBlockOff the vertical block offset, with zero indicating
1337 : * the top most block, 1 the next block and so forth.
1338 : *
1339 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1340 : * the x direction will be stored
1341 : *
1342 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1343 : * the y direction will be stored
1344 : *
1345 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1346 : *
1347 : */
1348 33957 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1349 : int *pnXValid, int *pnYValid) const
1350 : {
1351 67913 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1352 67910 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1353 67906 : nYBlockOff < 0 || nBlockYSize == 0 ||
1354 33953 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1355 : {
1356 6 : return CE_Failure;
1357 : }
1358 :
1359 33951 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1360 33951 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1361 :
1362 33951 : *pnXValid = nBlockXSize;
1363 33951 : *pnYValid = nBlockYSize;
1364 :
1365 33951 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1366 : {
1367 32614 : *pnXValid = nRasterXSize - nXPixelOff;
1368 : }
1369 :
1370 33951 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1371 : {
1372 3297 : *pnYValid = nRasterYSize - nYPixelOff;
1373 : }
1374 :
1375 33951 : return CE_None;
1376 : }
1377 :
1378 : /************************************************************************/
1379 : /* GDALGetActualBlockSize() */
1380 : /************************************************************************/
1381 :
1382 : /**
1383 : * \brief Retrieve the actual block size for a given block offset.
1384 : *
1385 : * @see GDALRasterBand::GetActualBlockSize()
1386 : */
1387 :
1388 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1389 : int nYBlockOff, int *pnXValid,
1390 : int *pnYValid)
1391 :
1392 : {
1393 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1394 :
1395 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1396 : return (
1397 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1398 : }
1399 :
1400 : /************************************************************************/
1401 : /* GetSuggestedBlockAccessPattern() */
1402 : /************************************************************************/
1403 :
1404 : /**
1405 : * \brief Return the suggested/most efficient access pattern to blocks
1406 : * (for read operations).
1407 : *
1408 : * While all GDAL drivers have to expose a block size, not all can guarantee
1409 : * efficient random access (GSBAP_RANDOM) to any block.
1410 : * Some drivers for example decompress sequentially a compressed stream from
1411 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1412 : * case best performance will be achieved while reading blocks in that order.
1413 : * (accessing blocks in random access in such rasters typically causes the
1414 : * decoding to be re-initialized from the start if accessing blocks in
1415 : * a non-sequential order)
1416 : *
1417 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1418 : * returned by drivers that expose a somewhat artificial block size, because
1419 : * they can extract any part of a raster, but in a rather inefficient way.
1420 : *
1421 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1422 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1423 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1424 : * most efficient strategy is to read as many pixels as possible in the less
1425 : * RasterIO() operations.
1426 : *
1427 : * The return of this method is for example used to determine the swath size
1428 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1429 : *
1430 : * @since GDAL 3.6
1431 : */
1432 :
1433 : GDALSuggestedBlockAccessPattern
1434 2487 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1435 : {
1436 2487 : return GSBAP_UNKNOWN;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* GetRasterDataType() */
1441 : /************************************************************************/
1442 :
1443 : /**
1444 : * \brief Fetch the pixel data type for this band.
1445 : *
1446 : * This method is the same as the C function GDALGetRasterDataType().
1447 : *
1448 : * @return the data type of pixels for this band.
1449 : */
1450 :
1451 9040420 : GDALDataType GDALRasterBand::GetRasterDataType() const
1452 :
1453 : {
1454 9040420 : return eDataType;
1455 : }
1456 :
1457 : /************************************************************************/
1458 : /* GDALGetRasterDataType() */
1459 : /************************************************************************/
1460 :
1461 : /**
1462 : * \brief Fetch the pixel data type for this band.
1463 : *
1464 : * @see GDALRasterBand::GetRasterDataType()
1465 : */
1466 :
1467 911468 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1468 :
1469 : {
1470 911468 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1471 :
1472 911468 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1473 911468 : return poBand->GetRasterDataType();
1474 : }
1475 :
1476 : /************************************************************************/
1477 : /* GetBlockSize() */
1478 : /************************************************************************/
1479 :
1480 : /**
1481 : * \brief Fetch the "natural" block size of this band.
1482 : *
1483 : * GDAL contains a concept of the natural block size of rasters so that
1484 : * applications can organized data access efficiently for some file formats.
1485 : * The natural block size is the block size that is most efficient for
1486 : * accessing the format. For many formats this is simple a whole scanline
1487 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1488 : *
1489 : * However, for tiled images this will typically be the tile size.
1490 : *
1491 : * Note that the X and Y block sizes don't have to divide the image size
1492 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1493 : * See ReadBlock() for an example of code dealing with these issues.
1494 : *
1495 : * This method is the same as the C function GDALGetBlockSize().
1496 : *
1497 : * @param pnXSize integer to put the X block size into or NULL.
1498 : *
1499 : * @param pnYSize integer to put the Y block size into or NULL.
1500 : */
1501 :
1502 5574230 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1503 :
1504 : {
1505 5574230 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1506 : {
1507 0 : ReportError(CE_Failure, CPLE_AppDefined,
1508 0 : "Invalid block dimension : %d * %d", nBlockXSize,
1509 0 : nBlockYSize);
1510 0 : if (pnXSize != nullptr)
1511 0 : *pnXSize = 0;
1512 0 : if (pnYSize != nullptr)
1513 0 : *pnYSize = 0;
1514 : }
1515 : else
1516 : {
1517 5574230 : if (pnXSize != nullptr)
1518 5574230 : *pnXSize = nBlockXSize;
1519 5574230 : if (pnYSize != nullptr)
1520 5574230 : *pnYSize = nBlockYSize;
1521 : }
1522 5574230 : }
1523 :
1524 : /************************************************************************/
1525 : /* GDALGetBlockSize() */
1526 : /************************************************************************/
1527 :
1528 : /**
1529 : * \brief Fetch the "natural" block size of this band.
1530 : *
1531 : * @see GDALRasterBand::GetBlockSize()
1532 : */
1533 :
1534 41307 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1535 : int *pnYSize)
1536 :
1537 : {
1538 41307 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1539 :
1540 41307 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1541 41307 : poBand->GetBlockSize(pnXSize, pnYSize);
1542 : }
1543 :
1544 : /************************************************************************/
1545 : /* InitBlockInfo() */
1546 : /************************************************************************/
1547 :
1548 : //! @cond Doxygen_Suppress
1549 3669050 : int GDALRasterBand::InitBlockInfo()
1550 :
1551 : {
1552 3669050 : if (poBandBlockCache != nullptr)
1553 3428410 : return poBandBlockCache->IsInitOK();
1554 :
1555 : /* Do some validation of raster and block dimensions in case the driver */
1556 : /* would have neglected to do it itself */
1557 240637 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1558 : {
1559 0 : ReportError(CE_Failure, CPLE_AppDefined,
1560 : "Invalid block dimension : %d * %d", nBlockXSize,
1561 : nBlockYSize);
1562 0 : return FALSE;
1563 : }
1564 :
1565 240637 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1566 : {
1567 0 : ReportError(CE_Failure, CPLE_AppDefined,
1568 : "Invalid raster dimension : %d * %d", nRasterXSize,
1569 : nRasterYSize);
1570 0 : return FALSE;
1571 : }
1572 :
1573 240637 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1574 240637 : if (nDataTypeSize == 0)
1575 : {
1576 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1577 0 : return FALSE;
1578 : }
1579 :
1580 : #if SIZEOF_VOIDP == 4
1581 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1582 : {
1583 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1584 : * multiplication in other cases */
1585 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1586 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1587 : {
1588 : ReportError(CE_Failure, CPLE_NotSupported,
1589 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1590 : nBlockYSize);
1591 : return FALSE;
1592 : }
1593 : }
1594 : #endif
1595 :
1596 240637 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1597 240637 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1598 :
1599 : const char *pszBlockStrategy =
1600 240637 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1601 240637 : bool bUseArray = true;
1602 240637 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1603 : {
1604 240597 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1605 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1606 : {
1607 240578 : GUIntBig nBlockCount =
1608 240578 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1609 240578 : if (poDS != nullptr)
1610 240374 : nBlockCount *= poDS->GetRasterCount();
1611 240578 : bUseArray = (nBlockCount < 1024 * 1024);
1612 : }
1613 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1614 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1615 : {
1616 0 : bUseArray = false;
1617 240597 : }
1618 : }
1619 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1620 40 : bUseArray = false;
1621 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1622 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1623 : pszBlockStrategy);
1624 :
1625 240637 : if (bUseArray)
1626 240566 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1627 : else
1628 : {
1629 71 : if (nBand == 1)
1630 26 : CPLDebug("GDAL", "Use hashset band block cache");
1631 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1632 : }
1633 240637 : if (poBandBlockCache == nullptr)
1634 0 : return FALSE;
1635 240637 : return poBandBlockCache->Init();
1636 : }
1637 :
1638 : //! @endcond
1639 :
1640 : /************************************************************************/
1641 : /* FlushCache() */
1642 : /************************************************************************/
1643 :
1644 : /**
1645 : * \brief Flush raster data cache.
1646 : *
1647 : * This call will recover memory used to cache data blocks for this raster
1648 : * band, and ensure that new requests are referred to the underlying driver.
1649 : *
1650 : * This method is the same as the C function GDALFlushRasterCache().
1651 : *
1652 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1653 : * @return CE_None on success.
1654 : */
1655 :
1656 5894920 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1657 :
1658 : {
1659 6014990 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1660 120064 : poBandBlockCache)
1661 4328 : poBandBlockCache->DisableDirtyBlockWriting();
1662 :
1663 5894920 : CPLErr eGlobalErr = eFlushBlockErr;
1664 :
1665 5894920 : if (eFlushBlockErr != CE_None)
1666 : {
1667 0 : ReportError(
1668 : eFlushBlockErr, CPLE_AppDefined,
1669 : "An error occurred while writing a dirty block from FlushCache");
1670 0 : eFlushBlockErr = CE_None;
1671 : }
1672 :
1673 5894920 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1674 5123970 : return eGlobalErr;
1675 :
1676 770959 : return poBandBlockCache->FlushCache();
1677 : }
1678 :
1679 : /************************************************************************/
1680 : /* GDALFlushRasterCache() */
1681 : /************************************************************************/
1682 :
1683 : /**
1684 : * \brief Flush raster data cache.
1685 : *
1686 : * @see GDALRasterBand::FlushCache()
1687 : */
1688 :
1689 625 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1690 :
1691 : {
1692 625 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1693 :
1694 625 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1695 : }
1696 :
1697 : /************************************************************************/
1698 : /* DropCache() */
1699 : /************************************************************************/
1700 :
1701 : /**
1702 : * \brief Drop raster data cache : data in cache will be lost.
1703 : *
1704 : * This call will recover memory used to cache data blocks for this raster
1705 : * band, and ensure that new requests are referred to the underlying driver.
1706 : *
1707 : * This method is the same as the C function GDALDropRasterCache().
1708 : *
1709 : * @return CE_None on success.
1710 : * @since 3.9
1711 : */
1712 :
1713 1 : CPLErr GDALRasterBand::DropCache()
1714 :
1715 : {
1716 1 : CPLErr result = CE_None;
1717 :
1718 1 : if (poBandBlockCache)
1719 1 : poBandBlockCache->DisableDirtyBlockWriting();
1720 :
1721 1 : CPLErr eGlobalErr = eFlushBlockErr;
1722 :
1723 1 : if (eFlushBlockErr != CE_None)
1724 : {
1725 0 : ReportError(
1726 : eFlushBlockErr, CPLE_AppDefined,
1727 : "An error occurred while writing a dirty block from DropCache");
1728 0 : eFlushBlockErr = CE_None;
1729 : }
1730 :
1731 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1732 0 : result = eGlobalErr;
1733 : else
1734 1 : result = poBandBlockCache->FlushCache();
1735 :
1736 1 : if (poBandBlockCache)
1737 1 : poBandBlockCache->EnableDirtyBlockWriting();
1738 :
1739 1 : return result;
1740 : }
1741 :
1742 : /************************************************************************/
1743 : /* GDALDropRasterCache() */
1744 : /************************************************************************/
1745 :
1746 : /**
1747 : * \brief Drop raster data cache.
1748 : *
1749 : * @see GDALRasterBand::DropCache()
1750 : * @since 3.9
1751 : */
1752 :
1753 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1754 :
1755 : {
1756 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1757 :
1758 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1759 : }
1760 :
1761 : /************************************************************************/
1762 : /* UnreferenceBlock() */
1763 : /* */
1764 : /* Unreference the block from our array of blocks */
1765 : /* This method should only be called by */
1766 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1767 : /* the block cache mutex) */
1768 : /************************************************************************/
1769 :
1770 29688 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1771 : {
1772 : #ifdef notdef
1773 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1774 : {
1775 : if (poBandBlockCache == nullptr)
1776 : printf("poBandBlockCache == NULL\n"); /*ok*/
1777 : else
1778 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1779 : printf("caller = %s\n", pszCaller); /*ok*/
1780 : printf("GDALRasterBand: %p\n", this); /*ok*/
1781 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1782 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1783 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1784 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1785 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1786 : poBlock->DumpBlock();
1787 : if (GetDataset() != nullptr)
1788 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1789 : GDALRasterBlock::Verify();
1790 : abort();
1791 : }
1792 : #endif
1793 29688 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1794 29688 : return poBandBlockCache->UnreferenceBlock(poBlock);
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* AddBlockToFreeList() */
1799 : /* */
1800 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1801 : /* finished with a block about to be free'd, they pass it to that */
1802 : /* method. */
1803 : /************************************************************************/
1804 :
1805 : //! @cond Doxygen_Suppress
1806 29688 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1807 : {
1808 29688 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1809 29688 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1810 : }
1811 :
1812 : //! @endcond
1813 :
1814 : /************************************************************************/
1815 : /* HasDirtyBlocks() */
1816 : /************************************************************************/
1817 :
1818 : //! @cond Doxygen_Suppress
1819 17 : bool GDALRasterBand::HasDirtyBlocks() const
1820 : {
1821 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1822 : }
1823 :
1824 : //! @endcond
1825 :
1826 : /************************************************************************/
1827 : /* FlushBlock() */
1828 : /************************************************************************/
1829 :
1830 : /** Flush a block out of the block cache.
1831 : * @param nXBlockOff block x offset
1832 : * @param nYBlockOff blocky offset
1833 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1834 : * @return CE_None in case of success, an error code otherwise.
1835 : */
1836 2315 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1837 : int bWriteDirtyBlock)
1838 :
1839 : {
1840 2315 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1841 0 : return (CE_Failure);
1842 :
1843 : /* -------------------------------------------------------------------- */
1844 : /* Validate the request */
1845 : /* -------------------------------------------------------------------- */
1846 2315 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1847 : {
1848 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1849 : "Illegal nBlockXOff value (%d) in "
1850 : "GDALRasterBand::FlushBlock()\n",
1851 : nXBlockOff);
1852 :
1853 0 : return (CE_Failure);
1854 : }
1855 :
1856 2315 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1857 : {
1858 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1859 : "Illegal nBlockYOff value (%d) in "
1860 : "GDALRasterBand::FlushBlock()\n",
1861 : nYBlockOff);
1862 :
1863 0 : return (CE_Failure);
1864 : }
1865 :
1866 2315 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1867 2315 : bWriteDirtyBlock);
1868 : }
1869 :
1870 : /************************************************************************/
1871 : /* TryGetLockedBlockRef() */
1872 : /************************************************************************/
1873 :
1874 : /**
1875 : * \brief Try fetching block ref.
1876 : *
1877 : * This method will returned the requested block (locked) if it is already
1878 : * in the block cache for the layer. If not, nullptr is returned.
1879 : *
1880 : * If a non-NULL value is returned, then a lock for the block will have been
1881 : * acquired on behalf of the caller. It is absolutely imperative that the
1882 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1883 : * severe problems may result.
1884 : *
1885 : * @param nXBlockOff the horizontal block offset, with zero indicating
1886 : * the left most block, 1 the next block and so forth.
1887 : *
1888 : * @param nYBlockOff the vertical block offset, with zero indicating
1889 : * the top most block, 1 the next block and so forth.
1890 : *
1891 : * @return NULL if block not available, or locked block pointer.
1892 : */
1893 :
1894 10729000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1895 : int nYBlockOff)
1896 :
1897 : {
1898 10729000 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1899 173587 : return nullptr;
1900 :
1901 : /* -------------------------------------------------------------------- */
1902 : /* Validate the request */
1903 : /* -------------------------------------------------------------------- */
1904 10555400 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1905 : {
1906 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1907 : "Illegal nBlockXOff value (%d) in "
1908 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1909 : nXBlockOff);
1910 :
1911 0 : return (nullptr);
1912 : }
1913 :
1914 10555400 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1915 : {
1916 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1917 : "Illegal nBlockYOff value (%d) in "
1918 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1919 : nYBlockOff);
1920 :
1921 0 : return (nullptr);
1922 : }
1923 :
1924 10555400 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1925 : }
1926 :
1927 : /************************************************************************/
1928 : /* GetLockedBlockRef() */
1929 : /************************************************************************/
1930 :
1931 : /**
1932 : * \brief Fetch a pointer to an internally cached raster block.
1933 : *
1934 : * This method will returned the requested block (locked) if it is already
1935 : * in the block cache for the layer. If not, the block will be read from
1936 : * the driver, and placed in the layer block cached, then returned. If an
1937 : * error occurs reading the block from the driver, a NULL value will be
1938 : * returned.
1939 : *
1940 : * If a non-NULL value is returned, then a lock for the block will have been
1941 : * acquired on behalf of the caller. It is absolutely imperative that the
1942 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1943 : * severe problems may result.
1944 : *
1945 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1946 : * enable caching.
1947 : *
1948 : * @param nXBlockOff the horizontal block offset, with zero indicating
1949 : * the left most block, 1 the next block and so forth.
1950 : *
1951 : * @param nYBlockOff the vertical block offset, with zero indicating
1952 : * the top most block, 1 the next block and so forth.
1953 : *
1954 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1955 : * but not actually read from the source. This is useful when it will just
1956 : * be completely set and written back.
1957 : *
1958 : * @return pointer to the block object, or NULL on failure.
1959 : */
1960 :
1961 10418800 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1962 : int nYBlockOff,
1963 : int bJustInitialize)
1964 :
1965 : {
1966 : /* -------------------------------------------------------------------- */
1967 : /* Try and fetch from cache. */
1968 : /* -------------------------------------------------------------------- */
1969 10418800 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1970 :
1971 : /* -------------------------------------------------------------------- */
1972 : /* If we didn't find it in our memory cache, instantiate a */
1973 : /* block (potentially load from disk) and "adopt" it into the */
1974 : /* cache. */
1975 : /* -------------------------------------------------------------------- */
1976 10418800 : if (poBlock == nullptr)
1977 : {
1978 3390720 : if (!InitBlockInfo())
1979 0 : return (nullptr);
1980 :
1981 : /* --------------------------------------------------------------------
1982 : */
1983 : /* Validate the request */
1984 : /* --------------------------------------------------------------------
1985 : */
1986 3390720 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1987 : {
1988 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1989 : "Illegal nBlockXOff value (%d) in "
1990 : "GDALRasterBand::GetLockedBlockRef()\n",
1991 : nXBlockOff);
1992 :
1993 0 : return (nullptr);
1994 : }
1995 :
1996 3390720 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1997 : {
1998 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1999 : "Illegal nBlockYOff value (%d) in "
2000 : "GDALRasterBand::GetLockedBlockRef()\n",
2001 : nYBlockOff);
2002 :
2003 0 : return (nullptr);
2004 : }
2005 :
2006 3390720 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2007 3390720 : if (poBlock == nullptr)
2008 0 : return nullptr;
2009 :
2010 3390720 : poBlock->AddLock();
2011 :
2012 : /* We need to temporarily drop the read-write lock in the following */
2013 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2014 : */
2015 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2016 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2017 : */
2018 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2019 : */
2020 : /* called and attempt at taking the lock on T2 (already taken).
2021 : * Similarly */
2022 : /* for T2 with D1, hence a deadlock situation (#6163) */
2023 : /* But this may open the door to other problems... */
2024 3390720 : if (poDS)
2025 3389980 : poDS->TemporarilyDropReadWriteLock();
2026 : /* allocate data space */
2027 3390720 : CPLErr eErr = poBlock->Internalize();
2028 3390720 : if (poDS)
2029 3389980 : poDS->ReacquireReadWriteLock();
2030 3390720 : if (eErr != CE_None)
2031 : {
2032 0 : poBlock->DropLock();
2033 0 : delete poBlock;
2034 0 : return nullptr;
2035 : }
2036 :
2037 3390720 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2038 : {
2039 0 : poBlock->DropLock();
2040 0 : delete poBlock;
2041 0 : return nullptr;
2042 : }
2043 :
2044 3390720 : if (!bJustInitialize)
2045 : {
2046 2893210 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2047 2893210 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2048 2893210 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2049 2893210 : if (bCallLeaveReadWrite)
2050 133367 : LeaveReadWrite();
2051 2893210 : if (eErr != CE_None)
2052 : {
2053 1165 : poBlock->DropLock();
2054 1165 : FlushBlock(nXBlockOff, nYBlockOff);
2055 1165 : ReportError(CE_Failure, CPLE_AppDefined,
2056 : "IReadBlock failed at X offset %d, Y offset %d%s",
2057 : nXBlockOff, nYBlockOff,
2058 1165 : (nErrorCounter != CPLGetErrorCounter())
2059 1163 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2060 : : "");
2061 1165 : return nullptr;
2062 : }
2063 :
2064 2892050 : nBlockReads++;
2065 2892050 : if (static_cast<GIntBig>(nBlockReads) ==
2066 2892050 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2067 228 : 1 &&
2068 228 : nBand == 1 && poDS != nullptr)
2069 : {
2070 168 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2071 168 : poDS->GetDescription());
2072 : }
2073 : }
2074 : }
2075 :
2076 10417600 : return poBlock;
2077 : }
2078 :
2079 : /************************************************************************/
2080 : /* Fill() */
2081 : /************************************************************************/
2082 :
2083 : /**
2084 : * \brief Fill this band with a constant value.
2085 : *
2086 : * GDAL makes no guarantees
2087 : * about what values pixels in newly created files are set to, so this
2088 : * method can be used to clear a band to a specified "default" value.
2089 : * The fill value is passed in as a double but this will be converted
2090 : * to the underlying type before writing to the file. An optional
2091 : * second argument allows the imaginary component of a complex
2092 : * constant value to be specified.
2093 : *
2094 : * This method is the same as the C function GDALFillRaster().
2095 : *
2096 : * @param dfRealValue Real component of fill value
2097 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2098 : *
2099 : * @return CE_Failure if the write fails, otherwise CE_None
2100 : */
2101 269827 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2102 : {
2103 :
2104 : // General approach is to construct a source block of the file's
2105 : // native type containing the appropriate value and then copy this
2106 : // to each block in the image via the RasterBlock cache. Using
2107 : // the cache means we avoid file I/O if it is not necessary, at the
2108 : // expense of some extra memcpy's (since we write to the
2109 : // RasterBlock cache, which is then at some point written to the
2110 : // underlying file, rather than simply directly to the underlying
2111 : // file.)
2112 :
2113 : // Check we can write to the file.
2114 269827 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2115 : {
2116 6 : return CE_Failure;
2117 : }
2118 :
2119 : // Make sure block parameters are set.
2120 269821 : if (!InitBlockInfo())
2121 0 : return CE_Failure;
2122 :
2123 : // Allocate the source block.
2124 269821 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2125 269821 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2126 269821 : auto blockByteSize = blockSize * elementSize;
2127 : unsigned char *srcBlock =
2128 269821 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2129 269821 : if (srcBlock == nullptr)
2130 : {
2131 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2132 : "GDALRasterBand::Fill(): Out of memory "
2133 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2134 : static_cast<GUIntBig>(blockByteSize));
2135 0 : return CE_Failure;
2136 : }
2137 :
2138 : // Initialize the source block.
2139 269821 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2140 269821 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2141 : elementSize, blockSize);
2142 :
2143 269821 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2144 :
2145 : // Write block to block cache
2146 881425 : for (int j = 0; j < nBlocksPerColumn; ++j)
2147 : {
2148 1517580 : for (int i = 0; i < nBlocksPerRow; ++i)
2149 : {
2150 905978 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2151 905978 : if (destBlock == nullptr)
2152 : {
2153 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2154 : "GDALRasterBand::Fill(): Error "
2155 : "while retrieving cache block.");
2156 0 : VSIFree(srcBlock);
2157 0 : return CE_Failure;
2158 : }
2159 905978 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2160 905978 : destBlock->MarkDirty();
2161 905978 : destBlock->DropLock();
2162 : }
2163 : }
2164 :
2165 269821 : if (bCallLeaveReadWrite)
2166 267757 : LeaveReadWrite();
2167 :
2168 : // Free up the source block
2169 269821 : VSIFree(srcBlock);
2170 :
2171 269821 : return CE_None;
2172 : }
2173 :
2174 : /************************************************************************/
2175 : /* GDALFillRaster() */
2176 : /************************************************************************/
2177 :
2178 : /**
2179 : * \brief Fill this band with a constant value.
2180 : *
2181 : * @see GDALRasterBand::Fill()
2182 : */
2183 269597 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2184 : double dfImaginaryValue)
2185 : {
2186 269597 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2187 :
2188 269597 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2189 269597 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2190 : }
2191 :
2192 : /************************************************************************/
2193 : /* GetAccess() */
2194 : /************************************************************************/
2195 :
2196 : /**
2197 : * \brief Find out if we have update permission for this band.
2198 : *
2199 : * This method is the same as the C function GDALGetRasterAccess().
2200 : *
2201 : * @return Either GA_Update or GA_ReadOnly.
2202 : */
2203 :
2204 3298 : GDALAccess GDALRasterBand::GetAccess()
2205 :
2206 : {
2207 3298 : return eAccess;
2208 : }
2209 :
2210 : /************************************************************************/
2211 : /* GDALGetRasterAccess() */
2212 : /************************************************************************/
2213 :
2214 : /**
2215 : * \brief Find out if we have update permission for this band.
2216 : *
2217 : * @see GDALRasterBand::GetAccess()
2218 : */
2219 :
2220 2640 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2221 :
2222 : {
2223 2640 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2224 :
2225 2640 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2226 2640 : return poBand->GetAccess();
2227 : }
2228 :
2229 : /************************************************************************/
2230 : /* GetCategoryNames() */
2231 : /************************************************************************/
2232 :
2233 : /**
2234 : * \brief Fetch the list of category names for this raster.
2235 : *
2236 : * The return list is a "StringList" in the sense of the CPL functions.
2237 : * That is a NULL terminated array of strings. Raster values without
2238 : * associated names will have an empty string in the returned list. The
2239 : * first entry in the list is for raster values of zero, and so on.
2240 : *
2241 : * The returned stringlist should not be altered or freed by the application.
2242 : * It may change on the next GDAL call, so please copy it if it is needed
2243 : * for any period of time.
2244 : *
2245 : * This method is the same as the C function GDALGetRasterCategoryNames().
2246 : *
2247 : * @return list of names, or NULL if none.
2248 : */
2249 :
2250 262 : char **GDALRasterBand::GetCategoryNames()
2251 :
2252 : {
2253 262 : return nullptr;
2254 : }
2255 :
2256 : /************************************************************************/
2257 : /* GDALGetRasterCategoryNames() */
2258 : /************************************************************************/
2259 :
2260 : /**
2261 : * \brief Fetch the list of category names for this raster.
2262 : *
2263 : * @see GDALRasterBand::GetCategoryNames()
2264 : */
2265 :
2266 210 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2267 :
2268 : {
2269 210 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2270 :
2271 210 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2272 210 : return poBand->GetCategoryNames();
2273 : }
2274 :
2275 : /************************************************************************/
2276 : /* SetCategoryNames() */
2277 : /************************************************************************/
2278 :
2279 : /**
2280 : * \fn GDALRasterBand::SetCategoryNames(char**)
2281 : * \brief Set the category names for this band.
2282 : *
2283 : * See the GetCategoryNames() method for more on the interpretation of
2284 : * category names.
2285 : *
2286 : * This method is the same as the C function GDALSetRasterCategoryNames().
2287 : *
2288 : * @param papszNames the NULL terminated StringList of category names. May
2289 : * be NULL to just clear the existing list.
2290 : *
2291 : * @return CE_None on success of CE_Failure on failure. If unsupported
2292 : * by the driver CE_Failure is returned, but no error message is reported.
2293 : */
2294 :
2295 : /**/
2296 : /**/
2297 :
2298 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2299 : {
2300 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2301 0 : ReportError(CE_Failure, CPLE_NotSupported,
2302 : "SetCategoryNames() not supported for this dataset.");
2303 :
2304 0 : return CE_Failure;
2305 : }
2306 :
2307 : /************************************************************************/
2308 : /* GDALSetCategoryNames() */
2309 : /************************************************************************/
2310 :
2311 : /**
2312 : * \brief Set the category names for this band.
2313 : *
2314 : * @see GDALRasterBand::SetCategoryNames()
2315 : */
2316 :
2317 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2318 : CSLConstList papszNames)
2319 :
2320 : {
2321 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2322 :
2323 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2324 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2325 : }
2326 :
2327 : /************************************************************************/
2328 : /* GetNoDataValue() */
2329 : /************************************************************************/
2330 :
2331 : /**
2332 : * \brief Fetch the no data value for this band.
2333 : *
2334 : * If there is no out of data value, an out of range value will generally
2335 : * be returned. The no data value for a band is generally a special marker
2336 : * value used to mark pixels that are not valid data. Such pixels should
2337 : * generally not be displayed, nor contribute to analysis operations.
2338 : *
2339 : * The no data value returned is 'raw', meaning that it has no offset and
2340 : * scale applied.
2341 : *
2342 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2343 : * lossy if the nodata value cannot exactly been represented by a double.
2344 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2345 : *
2346 : * This method is the same as the C function GDALGetRasterNoDataValue().
2347 : *
2348 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2349 : * is actually associated with this layer. May be NULL (default).
2350 : *
2351 : * @return the nodata value for this band.
2352 : */
2353 :
2354 13170 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2355 :
2356 : {
2357 13170 : if (pbSuccess != nullptr)
2358 13170 : *pbSuccess = FALSE;
2359 :
2360 13170 : return -1e10;
2361 : }
2362 :
2363 : /************************************************************************/
2364 : /* GDALGetRasterNoDataValue() */
2365 : /************************************************************************/
2366 :
2367 : /**
2368 : * \brief Fetch the no data value for this band.
2369 : *
2370 : * @see GDALRasterBand::GetNoDataValue()
2371 : */
2372 :
2373 415292 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2374 : int *pbSuccess)
2375 :
2376 : {
2377 415292 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2378 :
2379 415292 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2380 415292 : return poBand->GetNoDataValue(pbSuccess);
2381 : }
2382 :
2383 : /************************************************************************/
2384 : /* GetNoDataValueAsInt64() */
2385 : /************************************************************************/
2386 :
2387 : /**
2388 : * \brief Fetch the no data value for this band.
2389 : *
2390 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2391 : *
2392 : * If there is no out of data value, an out of range value will generally
2393 : * be returned. The no data value for a band is generally a special marker
2394 : * value used to mark pixels that are not valid data. Such pixels should
2395 : * generally not be displayed, nor contribute to analysis operations.
2396 : *
2397 : * The no data value returned is 'raw', meaning that it has no offset and
2398 : * scale applied.
2399 : *
2400 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2401 : *
2402 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2403 : * is actually associated with this layer. May be NULL (default).
2404 : *
2405 : * @return the nodata value for this band.
2406 : *
2407 : * @since GDAL 3.5
2408 : */
2409 :
2410 5 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2411 :
2412 : {
2413 5 : if (pbSuccess != nullptr)
2414 5 : *pbSuccess = FALSE;
2415 :
2416 5 : return std::numeric_limits<int64_t>::min();
2417 : }
2418 :
2419 : /************************************************************************/
2420 : /* GDALGetRasterNoDataValueAsInt64() */
2421 : /************************************************************************/
2422 :
2423 : /**
2424 : * \brief Fetch the no data value for this band.
2425 : *
2426 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2427 : *
2428 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2429 : *
2430 : * @since GDAL 3.5
2431 : */
2432 :
2433 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2434 : int *pbSuccess)
2435 :
2436 : {
2437 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2438 : std::numeric_limits<int64_t>::min());
2439 :
2440 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2441 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2442 : }
2443 :
2444 : /************************************************************************/
2445 : /* GetNoDataValueAsUInt64() */
2446 : /************************************************************************/
2447 :
2448 : /**
2449 : * \brief Fetch the no data value for this band.
2450 : *
2451 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2452 : *
2453 : * If there is no out of data value, an out of range value will generally
2454 : * be returned. The no data value for a band is generally a special marker
2455 : * value used to mark pixels that are not valid data. Such pixels should
2456 : * generally not be displayed, nor contribute to analysis operations.
2457 : *
2458 : * The no data value returned is 'raw', meaning that it has no offset and
2459 : * scale applied.
2460 : *
2461 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2462 : *
2463 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2464 : * is actually associated with this layer. May be NULL (default).
2465 : *
2466 : * @return the nodata value for this band.
2467 : *
2468 : * @since GDAL 3.5
2469 : */
2470 :
2471 4 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2472 :
2473 : {
2474 4 : if (pbSuccess != nullptr)
2475 4 : *pbSuccess = FALSE;
2476 :
2477 4 : return std::numeric_limits<uint64_t>::max();
2478 : }
2479 :
2480 : /************************************************************************/
2481 : /* GDALGetRasterNoDataValueAsUInt64() */
2482 : /************************************************************************/
2483 :
2484 : /**
2485 : * \brief Fetch the no data value for this band.
2486 : *
2487 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2488 : *
2489 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2490 : *
2491 : * @since GDAL 3.5
2492 : */
2493 :
2494 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2495 : int *pbSuccess)
2496 :
2497 : {
2498 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2499 : std::numeric_limits<uint64_t>::max());
2500 :
2501 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2502 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2503 : }
2504 :
2505 : /************************************************************************/
2506 : /* SetNoDataValueAsString() */
2507 : /************************************************************************/
2508 :
2509 : /**
2510 : * \brief Set the no data value for this band.
2511 : *
2512 : * Depending on drivers, changing the no data value may or may not have an
2513 : * effect on the pixel values of a raster that has just been created. It is
2514 : * thus advised to explicitly called Fill() if the intent is to initialize
2515 : * the raster to the nodata value.
2516 : * In any case, changing an existing no data value, when one already exists and
2517 : * the dataset exists or has been initialized, has no effect on the pixel whose
2518 : * value matched the previous nodata value.
2519 : *
2520 : * To clear the nodata value, use DeleteNoDataValue().
2521 : *
2522 : * @param pszNoData the value to set.
2523 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2524 : * If the value cannot be exactly represented on the output data
2525 : * type, *pbCannotBeExactlyRepresented will be set to true.
2526 : *
2527 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2528 : * by the driver, CE_Failure is returned but no error message will have
2529 : * been emitted.
2530 : *
2531 : * @since 3.11
2532 : */
2533 :
2534 : CPLErr
2535 126 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2536 : bool *pbCannotBeExactlyRepresented)
2537 : {
2538 126 : if (pbCannotBeExactlyRepresented)
2539 126 : *pbCannotBeExactlyRepresented = false;
2540 126 : if (eDataType == GDT_Int64)
2541 : {
2542 8 : if (strchr(pszNoData, '.') ||
2543 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2544 : {
2545 2 : char *endptr = nullptr;
2546 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2547 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2548 2 : GDALIsValueExactAs<int64_t>(dfVal))
2549 : {
2550 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2551 : }
2552 : }
2553 : else
2554 : {
2555 : try
2556 : {
2557 7 : const auto val = std::stoll(pszNoData);
2558 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2559 : }
2560 2 : catch (const std::exception &)
2561 : {
2562 : }
2563 : }
2564 : }
2565 121 : else if (eDataType == GDT_UInt64)
2566 : {
2567 2 : if (strchr(pszNoData, '.') ||
2568 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2569 : {
2570 0 : char *endptr = nullptr;
2571 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2572 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2573 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2574 : {
2575 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2576 : }
2577 : }
2578 : else
2579 : {
2580 : try
2581 : {
2582 1 : const auto val = std::stoull(pszNoData);
2583 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2584 : }
2585 0 : catch (const std::exception &)
2586 : {
2587 : }
2588 : }
2589 : }
2590 120 : else if (eDataType == GDT_Float32)
2591 : {
2592 10 : char *endptr = nullptr;
2593 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2594 10 : if (endptr == pszNoData + strlen(pszNoData))
2595 : {
2596 10 : return SetNoDataValue(double(fVal));
2597 : }
2598 : }
2599 : else
2600 : {
2601 110 : char *endptr = nullptr;
2602 110 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2603 220 : if (endptr == pszNoData + strlen(pszNoData) &&
2604 110 : GDALIsValueExactAs(dfVal, eDataType))
2605 : {
2606 109 : return SetNoDataValue(dfVal);
2607 : }
2608 : }
2609 5 : if (pbCannotBeExactlyRepresented)
2610 5 : *pbCannotBeExactlyRepresented = true;
2611 5 : return CE_Failure;
2612 : }
2613 :
2614 : /************************************************************************/
2615 : /* SetNoDataValue() */
2616 : /************************************************************************/
2617 :
2618 : /**
2619 : * \fn GDALRasterBand::SetNoDataValue(double)
2620 : * \brief Set the no data value for this band.
2621 : *
2622 : * Depending on drivers, changing the no data value may or may not have an
2623 : * effect on the pixel values of a raster that has just been created. It is
2624 : * thus advised to explicitly called Fill() if the intent is to initialize
2625 : * the raster to the nodata value.
2626 : * In any case, changing an existing no data value, when one already exists and
2627 : * the dataset exists or has been initialized, has no effect on the pixel whose
2628 : * value matched the previous nodata value.
2629 : *
2630 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2631 : * be represented by a double, use SetNoDataValueAsInt64() or
2632 : * SetNoDataValueAsUInt64() instead.
2633 : *
2634 : * To clear the nodata value, use DeleteNoDataValue().
2635 : *
2636 : * This method is the same as the C function GDALSetRasterNoDataValue().
2637 : *
2638 : * @param dfNoData the value to set.
2639 : *
2640 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2641 : * by the driver, CE_Failure is returned but no error message will have
2642 : * been emitted.
2643 : */
2644 :
2645 : /**/
2646 : /**/
2647 :
2648 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2649 :
2650 : {
2651 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2652 0 : ReportError(CE_Failure, CPLE_NotSupported,
2653 : "SetNoDataValue() not supported for this dataset.");
2654 :
2655 0 : return CE_Failure;
2656 : }
2657 :
2658 : /************************************************************************/
2659 : /* GDALSetRasterNoDataValue() */
2660 : /************************************************************************/
2661 :
2662 : /**
2663 : * \brief Set the no data value for this band.
2664 : *
2665 : * Depending on drivers, changing the no data value may or may not have an
2666 : * effect on the pixel values of a raster that has just been created. It is
2667 : * thus advised to explicitly called Fill() if the intent is to initialize
2668 : * the raster to the nodata value.
2669 : * In any case, changing an existing no data value, when one already exists and
2670 : * the dataset exists or has been initialized, has no effect on the pixel whose
2671 : * value matched the previous nodata value.
2672 : *
2673 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2674 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2675 : * GDALSetRasterNoDataValueAsUInt64() instead.
2676 : *
2677 : * @see GDALRasterBand::SetNoDataValue()
2678 : */
2679 :
2680 1274 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2681 : double dfValue)
2682 :
2683 : {
2684 1274 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2685 :
2686 1274 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2687 1274 : return poBand->SetNoDataValue(dfValue);
2688 : }
2689 :
2690 : /************************************************************************/
2691 : /* SetNoDataValueAsInt64() */
2692 : /************************************************************************/
2693 :
2694 : /**
2695 : * \brief Set the no data value for this band.
2696 : *
2697 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2698 : *
2699 : * Depending on drivers, changing the no data value may or may not have an
2700 : * effect on the pixel values of a raster that has just been created. It is
2701 : * thus advised to explicitly called Fill() if the intent is to initialize
2702 : * the raster to the nodata value.
2703 : * In ay case, changing an existing no data value, when one already exists and
2704 : * the dataset exists or has been initialized, has no effect on the pixel whose
2705 : * value matched the previous nodata value.
2706 : *
2707 : * To clear the nodata value, use DeleteNoDataValue().
2708 : *
2709 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2710 : *
2711 : * @param nNoDataValue the value to set.
2712 : *
2713 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2714 : * by the driver, CE_Failure is returned but no error message will have
2715 : * been emitted.
2716 : *
2717 : * @since GDAL 3.5
2718 : */
2719 :
2720 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2721 :
2722 : {
2723 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2724 0 : ReportError(CE_Failure, CPLE_NotSupported,
2725 : "SetNoDataValueAsInt64() not supported for this dataset.");
2726 :
2727 0 : return CE_Failure;
2728 : }
2729 :
2730 : /************************************************************************/
2731 : /* GDALSetRasterNoDataValueAsInt64() */
2732 : /************************************************************************/
2733 :
2734 : /**
2735 : * \brief Set the no data value for this band.
2736 : *
2737 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2738 : *
2739 : * Depending on drivers, changing the no data value may or may not have an
2740 : * effect on the pixel values of a raster that has just been created. It is
2741 : * thus advised to explicitly called Fill() if the intent is to initialize
2742 : * the raster to the nodata value.
2743 : * In ay case, changing an existing no data value, when one already exists and
2744 : * the dataset exists or has been initialized, has no effect on the pixel whose
2745 : * value matched the previous nodata value.
2746 : *
2747 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2748 : *
2749 : * @since GDAL 3.5
2750 : */
2751 :
2752 24 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2753 : int64_t nValue)
2754 :
2755 : {
2756 24 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2757 :
2758 24 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2759 24 : return poBand->SetNoDataValueAsInt64(nValue);
2760 : }
2761 :
2762 : /************************************************************************/
2763 : /* SetNoDataValueAsUInt64() */
2764 : /************************************************************************/
2765 :
2766 : /**
2767 : * \brief Set the no data value for this band.
2768 : *
2769 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2770 : *
2771 : * Depending on drivers, changing the no data value may or may not have an
2772 : * effect on the pixel values of a raster that has just been created. It is
2773 : * thus advised to explicitly called Fill() if the intent is to initialize
2774 : * the raster to the nodata value.
2775 : * In ay case, changing an existing no data value, when one already exists and
2776 : * the dataset exists or has been initialized, has no effect on the pixel whose
2777 : * value matched the previous nodata value.
2778 : *
2779 : * To clear the nodata value, use DeleteNoDataValue().
2780 : *
2781 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2782 : *
2783 : * @param nNoDataValue the value to set.
2784 : *
2785 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2786 : * by the driver, CE_Failure is returned but no error message will have
2787 : * been emitted.
2788 : *
2789 : * @since GDAL 3.5
2790 : */
2791 :
2792 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2793 :
2794 : {
2795 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2796 0 : ReportError(CE_Failure, CPLE_NotSupported,
2797 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2798 :
2799 0 : return CE_Failure;
2800 : }
2801 :
2802 : /************************************************************************/
2803 : /* GDALSetRasterNoDataValueAsUInt64() */
2804 : /************************************************************************/
2805 :
2806 : /**
2807 : * \brief Set the no data value for this band.
2808 : *
2809 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2810 : *
2811 : * Depending on drivers, changing the no data value may or may not have an
2812 : * effect on the pixel values of a raster that has just been created. It is
2813 : * thus advised to explicitly called Fill() if the intent is to initialize
2814 : * the raster to the nodata value.
2815 : * In ay case, changing an existing no data value, when one already exists and
2816 : * the dataset exists or has been initialized, has no effect on the pixel whose
2817 : * value matched the previous nodata value.
2818 : *
2819 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2820 : *
2821 : * @since GDAL 3.5
2822 : */
2823 :
2824 23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2825 : uint64_t nValue)
2826 :
2827 : {
2828 23 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2829 :
2830 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2831 23 : return poBand->SetNoDataValueAsUInt64(nValue);
2832 : }
2833 :
2834 : /************************************************************************/
2835 : /* DeleteNoDataValue() */
2836 : /************************************************************************/
2837 :
2838 : /**
2839 : * \brief Remove the no data value for this band.
2840 : *
2841 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2842 : *
2843 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2844 : * by the driver, CE_Failure is returned but no error message will have
2845 : * been emitted.
2846 : *
2847 : */
2848 :
2849 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2850 :
2851 : {
2852 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2853 0 : ReportError(CE_Failure, CPLE_NotSupported,
2854 : "DeleteNoDataValue() not supported for this dataset.");
2855 :
2856 0 : return CE_Failure;
2857 : }
2858 :
2859 : /************************************************************************/
2860 : /* GDALDeleteRasterNoDataValue() */
2861 : /************************************************************************/
2862 :
2863 : /**
2864 : * \brief Remove the no data value for this band.
2865 : *
2866 : * @see GDALRasterBand::DeleteNoDataValue()
2867 : *
2868 : */
2869 :
2870 56 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2871 :
2872 : {
2873 56 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2874 :
2875 56 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2876 56 : return poBand->DeleteNoDataValue();
2877 : }
2878 :
2879 : /************************************************************************/
2880 : /* GetMaximum() */
2881 : /************************************************************************/
2882 :
2883 : /**
2884 : * \brief Fetch the maximum value for this band.
2885 : *
2886 : * For file formats that don't know this intrinsically, the maximum supported
2887 : * value for the data type will generally be returned.
2888 : *
2889 : * This method is the same as the C function GDALGetRasterMaximum().
2890 : *
2891 : * @param pbSuccess pointer to a boolean to use to indicate if the
2892 : * returned value is a tight maximum or not. May be NULL (default).
2893 : *
2894 : * @return the maximum raster value (excluding no data pixels)
2895 : */
2896 :
2897 548 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2898 :
2899 : {
2900 548 : const char *pszValue = nullptr;
2901 :
2902 548 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2903 : {
2904 47 : if (pbSuccess != nullptr)
2905 42 : *pbSuccess = TRUE;
2906 :
2907 47 : return CPLAtofM(pszValue);
2908 : }
2909 :
2910 501 : if (pbSuccess != nullptr)
2911 497 : *pbSuccess = FALSE;
2912 :
2913 501 : switch (eDataType)
2914 : {
2915 345 : case GDT_UInt8:
2916 : {
2917 345 : EnablePixelTypeSignedByteWarning(false);
2918 : const char *pszPixelType =
2919 345 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2920 345 : EnablePixelTypeSignedByteWarning(true);
2921 345 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2922 0 : return 127;
2923 :
2924 345 : return 255;
2925 : }
2926 :
2927 1 : case GDT_Int8:
2928 1 : return 127;
2929 :
2930 21 : case GDT_UInt16:
2931 21 : return 65535;
2932 :
2933 24 : case GDT_Int16:
2934 : case GDT_CInt16:
2935 24 : return 32767;
2936 :
2937 39 : case GDT_Int32:
2938 : case GDT_CInt32:
2939 39 : return 2147483647.0;
2940 :
2941 14 : case GDT_UInt32:
2942 14 : return 4294967295.0;
2943 :
2944 1 : case GDT_Int64:
2945 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2946 :
2947 1 : case GDT_UInt64:
2948 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2949 :
2950 0 : case GDT_Float16:
2951 : case GDT_CFloat16:
2952 0 : return 65504.0;
2953 :
2954 33 : case GDT_Float32:
2955 : case GDT_CFloat32:
2956 33 : return 4294967295.0; // Not actually accurate.
2957 :
2958 22 : case GDT_Float64:
2959 : case GDT_CFloat64:
2960 22 : return 4294967295.0; // Not actually accurate.
2961 :
2962 0 : case GDT_Unknown:
2963 : case GDT_TypeCount:
2964 0 : break;
2965 : }
2966 0 : return 4294967295.0; // Not actually accurate.
2967 : }
2968 :
2969 : /************************************************************************/
2970 : /* GDALGetRasterMaximum() */
2971 : /************************************************************************/
2972 :
2973 : /**
2974 : * \brief Fetch the maximum value for this band.
2975 : *
2976 : * @see GDALRasterBand::GetMaximum()
2977 : */
2978 :
2979 350 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2980 :
2981 : {
2982 350 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2983 :
2984 350 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2985 350 : return poBand->GetMaximum(pbSuccess);
2986 : }
2987 :
2988 : /************************************************************************/
2989 : /* GetMinimum() */
2990 : /************************************************************************/
2991 :
2992 : /**
2993 : * \brief Fetch the minimum value for this band.
2994 : *
2995 : * For file formats that don't know this intrinsically, the minimum supported
2996 : * value for the data type will generally be returned.
2997 : *
2998 : * This method is the same as the C function GDALGetRasterMinimum().
2999 : *
3000 : * @param pbSuccess pointer to a boolean to use to indicate if the
3001 : * returned value is a tight minimum or not. May be NULL (default).
3002 : *
3003 : * @return the minimum raster value (excluding no data pixels)
3004 : */
3005 :
3006 556 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3007 :
3008 : {
3009 556 : const char *pszValue = nullptr;
3010 :
3011 556 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3012 : {
3013 52 : if (pbSuccess != nullptr)
3014 47 : *pbSuccess = TRUE;
3015 :
3016 52 : return CPLAtofM(pszValue);
3017 : }
3018 :
3019 504 : if (pbSuccess != nullptr)
3020 500 : *pbSuccess = FALSE;
3021 :
3022 504 : switch (eDataType)
3023 : {
3024 348 : case GDT_UInt8:
3025 : {
3026 348 : EnablePixelTypeSignedByteWarning(false);
3027 : const char *pszPixelType =
3028 348 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3029 348 : EnablePixelTypeSignedByteWarning(true);
3030 348 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3031 0 : return -128;
3032 :
3033 348 : return 0;
3034 : }
3035 :
3036 1 : case GDT_Int8:
3037 1 : return -128;
3038 :
3039 21 : case GDT_UInt16:
3040 21 : return 0;
3041 :
3042 24 : case GDT_Int16:
3043 : case GDT_CInt16:
3044 24 : return -32768;
3045 :
3046 39 : case GDT_Int32:
3047 : case GDT_CInt32:
3048 39 : return -2147483648.0;
3049 :
3050 14 : case GDT_UInt32:
3051 14 : return 0;
3052 :
3053 1 : case GDT_Int64:
3054 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3055 :
3056 1 : case GDT_UInt64:
3057 1 : return 0;
3058 :
3059 0 : case GDT_Float16:
3060 : case GDT_CFloat16:
3061 0 : return -65504.0;
3062 :
3063 33 : case GDT_Float32:
3064 : case GDT_CFloat32:
3065 33 : return -4294967295.0; // Not actually accurate.
3066 :
3067 22 : case GDT_Float64:
3068 : case GDT_CFloat64:
3069 22 : return -4294967295.0; // Not actually accurate.
3070 :
3071 0 : case GDT_Unknown:
3072 : case GDT_TypeCount:
3073 0 : break;
3074 : }
3075 0 : return -4294967295.0; // Not actually accurate.
3076 : }
3077 :
3078 : /************************************************************************/
3079 : /* GDALGetRasterMinimum() */
3080 : /************************************************************************/
3081 :
3082 : /**
3083 : * \brief Fetch the minimum value for this band.
3084 : *
3085 : * @see GDALRasterBand::GetMinimum()
3086 : */
3087 :
3088 360 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3089 :
3090 : {
3091 360 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3092 :
3093 360 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3094 360 : return poBand->GetMinimum(pbSuccess);
3095 : }
3096 :
3097 : /************************************************************************/
3098 : /* GetColorInterpretation() */
3099 : /************************************************************************/
3100 :
3101 : /**
3102 : * \brief How should this band be interpreted as color?
3103 : *
3104 : * GCI_Undefined is returned when the format doesn't know anything
3105 : * about the color interpretation.
3106 : *
3107 : * This method is the same as the C function
3108 : * GDALGetRasterColorInterpretation().
3109 : *
3110 : * @return color interpretation value for band.
3111 : */
3112 :
3113 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3114 :
3115 : {
3116 163 : return GCI_Undefined;
3117 : }
3118 :
3119 : /************************************************************************/
3120 : /* GDALGetRasterColorInterpretation() */
3121 : /************************************************************************/
3122 :
3123 : /**
3124 : * \brief How should this band be interpreted as color?
3125 : *
3126 : * @see GDALRasterBand::GetColorInterpretation()
3127 : */
3128 :
3129 : GDALColorInterp CPL_STDCALL
3130 6399 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3131 :
3132 : {
3133 6399 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3134 :
3135 6399 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3136 6399 : return poBand->GetColorInterpretation();
3137 : }
3138 :
3139 : /************************************************************************/
3140 : /* SetColorInterpretation() */
3141 : /************************************************************************/
3142 :
3143 : /**
3144 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3145 : * \brief Set color interpretation of a band.
3146 : *
3147 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3148 : *
3149 : * @param eColorInterp the new color interpretation to apply to this band.
3150 : *
3151 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3152 : */
3153 :
3154 : /**/
3155 : /**/
3156 :
3157 1 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3158 :
3159 : {
3160 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3161 1 : ReportError(CE_Failure, CPLE_NotSupported,
3162 : "SetColorInterpretation() not supported for this dataset.");
3163 1 : return CE_Failure;
3164 : }
3165 :
3166 : /************************************************************************/
3167 : /* GDALSetRasterColorInterpretation() */
3168 : /************************************************************************/
3169 :
3170 : /**
3171 : * \brief Set color interpretation of a band.
3172 : *
3173 : * @see GDALRasterBand::SetColorInterpretation()
3174 : */
3175 :
3176 1995 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3177 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3178 :
3179 : {
3180 1995 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3181 :
3182 1995 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3183 1995 : return poBand->SetColorInterpretation(eColorInterp);
3184 : }
3185 :
3186 : /************************************************************************/
3187 : /* GetColorTable() */
3188 : /************************************************************************/
3189 :
3190 : /**
3191 : * \brief Fetch the color table associated with band.
3192 : *
3193 : * If there is no associated color table, the return result is NULL. The
3194 : * returned color table remains owned by the GDALRasterBand, and can't
3195 : * be depended on for long, nor should it ever be modified by the caller.
3196 : *
3197 : * This method is the same as the C function GDALGetRasterColorTable().
3198 : *
3199 : * @return internal color table, or NULL.
3200 : */
3201 :
3202 215 : GDALColorTable *GDALRasterBand::GetColorTable()
3203 :
3204 : {
3205 215 : return nullptr;
3206 : }
3207 :
3208 : /************************************************************************/
3209 : /* GDALGetRasterColorTable() */
3210 : /************************************************************************/
3211 :
3212 : /**
3213 : * \brief Fetch the color table associated with band.
3214 : *
3215 : * @see GDALRasterBand::GetColorTable()
3216 : */
3217 :
3218 2219 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3219 :
3220 : {
3221 2219 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3222 :
3223 2219 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3224 2219 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3225 : }
3226 :
3227 : /************************************************************************/
3228 : /* SetColorTable() */
3229 : /************************************************************************/
3230 :
3231 : /**
3232 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3233 : * \brief Set the raster color table.
3234 : *
3235 : * The driver will make a copy of all desired data in the colortable. It
3236 : * remains owned by the caller after the call.
3237 : *
3238 : * This method is the same as the C function GDALSetRasterColorTable().
3239 : *
3240 : * @param poCT the color table to apply. This may be NULL to clear the color
3241 : * table (where supported).
3242 : *
3243 : * @return CE_None on success, or CE_Failure on failure. If the action is
3244 : * unsupported by the driver, a value of CE_Failure is returned, but no
3245 : * error is issued.
3246 : */
3247 :
3248 : /**/
3249 : /**/
3250 :
3251 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3252 :
3253 : {
3254 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3255 0 : ReportError(CE_Failure, CPLE_NotSupported,
3256 : "SetColorTable() not supported for this dataset.");
3257 0 : return CE_Failure;
3258 : }
3259 :
3260 : /************************************************************************/
3261 : /* GDALSetRasterColorTable() */
3262 : /************************************************************************/
3263 :
3264 : /**
3265 : * \brief Set the raster color table.
3266 : *
3267 : * @see GDALRasterBand::SetColorTable()
3268 : */
3269 :
3270 105 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3271 : GDALColorTableH hCT)
3272 :
3273 : {
3274 105 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3275 :
3276 105 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3277 105 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3278 : }
3279 :
3280 : /************************************************************************/
3281 : /* HasArbitraryOverviews() */
3282 : /************************************************************************/
3283 :
3284 : /**
3285 : * \brief Check for arbitrary overviews.
3286 : *
3287 : * This returns TRUE if the underlying datastore can compute arbitrary
3288 : * overviews efficiently, such as is the case with OGDI over a network.
3289 : * Datastores with arbitrary overviews don't generally have any fixed
3290 : * overviews, but the RasterIO() method can be used in downsampling mode
3291 : * to get overview data efficiently.
3292 : *
3293 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3294 : *
3295 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3296 : * FALSE.
3297 : */
3298 :
3299 279 : int GDALRasterBand::HasArbitraryOverviews()
3300 :
3301 : {
3302 279 : return FALSE;
3303 : }
3304 :
3305 : /************************************************************************/
3306 : /* GDALHasArbitraryOverviews() */
3307 : /************************************************************************/
3308 :
3309 : /**
3310 : * \brief Check for arbitrary overviews.
3311 : *
3312 : * @see GDALRasterBand::HasArbitraryOverviews()
3313 : */
3314 :
3315 200 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3316 :
3317 : {
3318 200 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3319 :
3320 200 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3321 200 : return poBand->HasArbitraryOverviews();
3322 : }
3323 :
3324 : /************************************************************************/
3325 : /* GetOverviewCount() */
3326 : /************************************************************************/
3327 :
3328 : /**
3329 : * \brief Return the number of overview layers available.
3330 : *
3331 : * This method is the same as the C function GDALGetOverviewCount().
3332 : *
3333 : * @return overview count, zero if none.
3334 : */
3335 :
3336 1067010 : int GDALRasterBand::GetOverviewCount()
3337 :
3338 : {
3339 1724200 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3340 657194 : poDS->AreOverviewsEnabled())
3341 657194 : return poDS->oOvManager.GetOverviewCount(nBand);
3342 :
3343 409813 : return 0;
3344 : }
3345 :
3346 : /************************************************************************/
3347 : /* GDALGetOverviewCount() */
3348 : /************************************************************************/
3349 :
3350 : /**
3351 : * \brief Return the number of overview layers available.
3352 : *
3353 : * @see GDALRasterBand::GetOverviewCount()
3354 : */
3355 :
3356 3320 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3357 :
3358 : {
3359 3320 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3360 :
3361 3320 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3362 3320 : return poBand->GetOverviewCount();
3363 : }
3364 :
3365 : /************************************************************************/
3366 : /* GetOverview() */
3367 : /************************************************************************/
3368 :
3369 : /**
3370 : * \brief Fetch overview raster band object.
3371 : *
3372 : * This method is the same as the C function GDALGetOverview().
3373 : *
3374 : * @param i overview index between 0 and GetOverviewCount()-1.
3375 : *
3376 : * @return overview GDALRasterBand.
3377 : */
3378 :
3379 943 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3380 :
3381 : {
3382 1734 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3383 791 : poDS->AreOverviewsEnabled())
3384 791 : return poDS->oOvManager.GetOverview(nBand, i);
3385 :
3386 152 : return nullptr;
3387 : }
3388 :
3389 : /************************************************************************/
3390 : /* GDALGetOverview() */
3391 : /************************************************************************/
3392 :
3393 : /**
3394 : * \brief Fetch overview raster band object.
3395 : *
3396 : * @see GDALRasterBand::GetOverview()
3397 : */
3398 :
3399 5667 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3400 :
3401 : {
3402 5667 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3403 :
3404 5667 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3405 5667 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3406 : }
3407 :
3408 : /************************************************************************/
3409 : /* GetRasterSampleOverview() */
3410 : /************************************************************************/
3411 :
3412 : /**
3413 : * \brief Fetch best sampling overview.
3414 : *
3415 : * Returns the most reduced overview of the given band that still satisfies
3416 : * the desired number of samples. This function can be used with zero
3417 : * as the number of desired samples to fetch the most reduced overview.
3418 : * The same band as was passed in will be returned if it has not overviews,
3419 : * or if none of the overviews have enough samples.
3420 : *
3421 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3422 : * and GDALGetRasterSampleOverviewEx().
3423 : *
3424 : * @param nDesiredSamples the returned band will have at least this many
3425 : * pixels.
3426 : *
3427 : * @return optimal overview or the band itself.
3428 : */
3429 :
3430 : GDALRasterBand *
3431 2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3432 :
3433 : {
3434 2009 : GDALRasterBand *poBestBand = this;
3435 :
3436 2009 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3437 :
3438 4029 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3439 : {
3440 2020 : GDALRasterBand *poOBand = GetOverview(iOverview);
3441 :
3442 2020 : if (poOBand == nullptr)
3443 0 : continue;
3444 :
3445 : const double dfOSamples =
3446 2020 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3447 :
3448 2020 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3449 : {
3450 2017 : dfBestSamples = dfOSamples;
3451 2017 : poBestBand = poOBand;
3452 : }
3453 : }
3454 :
3455 2009 : return poBestBand;
3456 : }
3457 :
3458 : /************************************************************************/
3459 : /* GDALGetRasterSampleOverview() */
3460 : /************************************************************************/
3461 :
3462 : /**
3463 : * \brief Fetch best sampling overview.
3464 : *
3465 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3466 : * billion samples.
3467 : *
3468 : * @see GDALRasterBand::GetRasterSampleOverview()
3469 : * @see GDALGetRasterSampleOverviewEx()
3470 : */
3471 :
3472 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3473 : int nDesiredSamples)
3474 :
3475 : {
3476 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3477 :
3478 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3479 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3480 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3481 : }
3482 :
3483 : /************************************************************************/
3484 : /* GDALGetRasterSampleOverviewEx() */
3485 : /************************************************************************/
3486 :
3487 : /**
3488 : * \brief Fetch best sampling overview.
3489 : *
3490 : * @see GDALRasterBand::GetRasterSampleOverview()
3491 : */
3492 :
3493 : GDALRasterBandH CPL_STDCALL
3494 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3495 :
3496 : {
3497 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3498 :
3499 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3500 2000 : return GDALRasterBand::ToHandle(
3501 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3502 : }
3503 :
3504 : /************************************************************************/
3505 : /* BuildOverviews() */
3506 : /************************************************************************/
3507 :
3508 : /**
3509 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3510 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3511 : *
3512 : * If the operation is unsupported for the indicated dataset, then
3513 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3514 : * CPLE_NotSupported.
3515 : *
3516 : * WARNING: Most formats don't support per-band overview computation, but
3517 : * require that overviews are computed for all bands of a dataset, using
3518 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3519 : * is the HFA driver which supports this method.
3520 : *
3521 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3522 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3523 : * applied.
3524 : * @param nOverviews number of overviews to build.
3525 : * @param panOverviewList the list of overview decimation factors to build.
3526 : * @param pfnProgress a function to call to report progress, or NULL.
3527 : * @param pProgressData application data to pass to the progress function.
3528 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3529 : * key=value pairs, or NULL
3530 : *
3531 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3532 : */
3533 :
3534 : /**/
3535 : /**/
3536 :
3537 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3538 : int /*nOverviews*/,
3539 : const int * /*panOverviewList*/,
3540 : GDALProgressFunc /*pfnProgress*/,
3541 : void * /*pProgressData*/,
3542 : CSLConstList /* papszOptions */)
3543 :
3544 : {
3545 0 : ReportError(CE_Failure, CPLE_NotSupported,
3546 : "BuildOverviews() not supported for this dataset.");
3547 :
3548 0 : return (CE_Failure);
3549 : }
3550 :
3551 : /************************************************************************/
3552 : /* GetOffset() */
3553 : /************************************************************************/
3554 :
3555 : /**
3556 : * \brief Fetch the raster value offset.
3557 : *
3558 : * This value (in combination with the GetScale() value) can be used to
3559 : * transform raw pixel values into the units returned by GetUnitType().
3560 : * For example this might be used to store elevations in GUInt16 bands
3561 : * with a precision of 0.1, and starting from -100.
3562 : *
3563 : * Units value = (raw value * scale) + offset
3564 : *
3565 : * Note that applying scale and offset is of the responsibility of the user,
3566 : * and is not done by methods such as RasterIO() or ReadBlock().
3567 : *
3568 : * For file formats that don't know this intrinsically a value of zero
3569 : * is returned.
3570 : *
3571 : * This method is the same as the C function GDALGetRasterOffset().
3572 : *
3573 : * @param pbSuccess pointer to a boolean to use to indicate if the
3574 : * returned value is meaningful or not. May be NULL (default).
3575 : *
3576 : * @return the raster offset.
3577 : */
3578 :
3579 445 : double GDALRasterBand::GetOffset(int *pbSuccess)
3580 :
3581 : {
3582 445 : if (pbSuccess != nullptr)
3583 336 : *pbSuccess = FALSE;
3584 :
3585 445 : return 0.0;
3586 : }
3587 :
3588 : /************************************************************************/
3589 : /* GDALGetRasterOffset() */
3590 : /************************************************************************/
3591 :
3592 : /**
3593 : * \brief Fetch the raster value offset.
3594 : *
3595 : * @see GDALRasterBand::GetOffset()
3596 : */
3597 :
3598 420 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3599 :
3600 : {
3601 420 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3602 :
3603 420 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3604 420 : return poBand->GetOffset(pbSuccess);
3605 : }
3606 :
3607 : /************************************************************************/
3608 : /* SetOffset() */
3609 : /************************************************************************/
3610 :
3611 : /**
3612 : * \fn GDALRasterBand::SetOffset(double)
3613 : * \brief Set scaling offset.
3614 : *
3615 : * Very few formats implement this method. When not implemented it will
3616 : * issue a CPLE_NotSupported error and return CE_Failure.
3617 : *
3618 : * This method is the same as the C function GDALSetRasterOffset().
3619 : *
3620 : * @param dfNewOffset the new offset.
3621 : *
3622 : * @return CE_None or success or CE_Failure on failure.
3623 : */
3624 :
3625 : /**/
3626 : /**/
3627 :
3628 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3629 : {
3630 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3631 0 : ReportError(CE_Failure, CPLE_NotSupported,
3632 : "SetOffset() not supported on this raster band.");
3633 :
3634 0 : return CE_Failure;
3635 : }
3636 :
3637 : /************************************************************************/
3638 : /* GDALSetRasterOffset() */
3639 : /************************************************************************/
3640 :
3641 : /**
3642 : * \brief Set scaling offset.
3643 : *
3644 : * @see GDALRasterBand::SetOffset()
3645 : */
3646 :
3647 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3648 : double dfNewOffset)
3649 :
3650 : {
3651 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3652 :
3653 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3654 86 : return poBand->SetOffset(dfNewOffset);
3655 : }
3656 :
3657 : /************************************************************************/
3658 : /* GetScale() */
3659 : /************************************************************************/
3660 :
3661 : /**
3662 : * \brief Fetch the raster value scale.
3663 : *
3664 : * This value (in combination with the GetOffset() value) can be used to
3665 : * transform raw pixel values into the units returned by GetUnitType().
3666 : * For example this might be used to store elevations in GUInt16 bands
3667 : * with a precision of 0.1, and starting from -100.
3668 : *
3669 : * Units value = (raw value * scale) + offset
3670 : *
3671 : * Note that applying scale and offset is of the responsibility of the user,
3672 : * and is not done by methods such as RasterIO() or ReadBlock().
3673 : *
3674 : * For file formats that don't know this intrinsically a value of one
3675 : * is returned.
3676 : *
3677 : * This method is the same as the C function GDALGetRasterScale().
3678 : *
3679 : * @param pbSuccess pointer to a boolean to use to indicate if the
3680 : * returned value is meaningful or not. May be NULL (default).
3681 : *
3682 : * @return the raster scale.
3683 : */
3684 :
3685 445 : double GDALRasterBand::GetScale(int *pbSuccess)
3686 :
3687 : {
3688 445 : if (pbSuccess != nullptr)
3689 336 : *pbSuccess = FALSE;
3690 :
3691 445 : return 1.0;
3692 : }
3693 :
3694 : /************************************************************************/
3695 : /* GDALGetRasterScale() */
3696 : /************************************************************************/
3697 :
3698 : /**
3699 : * \brief Fetch the raster value scale.
3700 : *
3701 : * @see GDALRasterBand::GetScale()
3702 : */
3703 :
3704 418 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3705 :
3706 : {
3707 418 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3708 :
3709 418 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3710 418 : return poBand->GetScale(pbSuccess);
3711 : }
3712 :
3713 : /************************************************************************/
3714 : /* SetScale() */
3715 : /************************************************************************/
3716 :
3717 : /**
3718 : * \fn GDALRasterBand::SetScale(double)
3719 : * \brief Set scaling ratio.
3720 : *
3721 : * Very few formats implement this method. When not implemented it will
3722 : * issue a CPLE_NotSupported error and return CE_Failure.
3723 : *
3724 : * This method is the same as the C function GDALSetRasterScale().
3725 : *
3726 : * @param dfNewScale the new scale.
3727 : *
3728 : * @return CE_None or success or CE_Failure on failure.
3729 : */
3730 :
3731 : /**/
3732 : /**/
3733 :
3734 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3735 :
3736 : {
3737 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3738 0 : ReportError(CE_Failure, CPLE_NotSupported,
3739 : "SetScale() not supported on this raster band.");
3740 :
3741 0 : return CE_Failure;
3742 : }
3743 :
3744 : /************************************************************************/
3745 : /* GDALSetRasterScale() */
3746 : /************************************************************************/
3747 :
3748 : /**
3749 : * \brief Set scaling ratio.
3750 : *
3751 : * @see GDALRasterBand::SetScale()
3752 : */
3753 :
3754 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3755 :
3756 : {
3757 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3758 :
3759 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3760 87 : return poBand->SetScale(dfNewOffset);
3761 : }
3762 :
3763 : /************************************************************************/
3764 : /* GetUnitType() */
3765 : /************************************************************************/
3766 :
3767 : /**
3768 : * \brief Return raster unit type.
3769 : *
3770 : * Return a name for the units of this raster's values. For instance, it
3771 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3772 : * units are available, a value of "" will be returned. The returned string
3773 : * should not be modified, nor freed by the calling application.
3774 : *
3775 : * This method is the same as the C function GDALGetRasterUnitType().
3776 : *
3777 : * @return unit name string.
3778 : */
3779 :
3780 169 : const char *GDALRasterBand::GetUnitType()
3781 :
3782 : {
3783 169 : return "";
3784 : }
3785 :
3786 : /************************************************************************/
3787 : /* GDALGetRasterUnitType() */
3788 : /************************************************************************/
3789 :
3790 : /**
3791 : * \brief Return raster unit type.
3792 : *
3793 : * @see GDALRasterBand::GetUnitType()
3794 : */
3795 :
3796 1744 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3797 :
3798 : {
3799 1744 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3800 :
3801 1744 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3802 1744 : return poBand->GetUnitType();
3803 : }
3804 :
3805 : /************************************************************************/
3806 : /* SetUnitType() */
3807 : /************************************************************************/
3808 :
3809 : /**
3810 : * \fn GDALRasterBand::SetUnitType(const char*)
3811 : * \brief Set unit type.
3812 : *
3813 : * Set the unit type for a raster band. Values should be one of
3814 : * "" (the default indicating it is unknown), "m" indicating meters,
3815 : * or "ft" indicating feet, though other nonstandard values are allowed.
3816 : *
3817 : * This method is the same as the C function GDALSetRasterUnitType().
3818 : *
3819 : * @param pszNewValue the new unit type value.
3820 : *
3821 : * @return CE_None on success or CE_Failure if not successful, or
3822 : * unsupported.
3823 : */
3824 :
3825 : /**/
3826 : /**/
3827 :
3828 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3829 :
3830 : {
3831 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3832 0 : ReportError(CE_Failure, CPLE_NotSupported,
3833 : "SetUnitType() not supported on this raster band.");
3834 0 : return CE_Failure;
3835 : }
3836 :
3837 : /************************************************************************/
3838 : /* GDALSetRasterUnitType() */
3839 : /************************************************************************/
3840 :
3841 : /**
3842 : * \brief Set unit type.
3843 : *
3844 : * @see GDALRasterBand::SetUnitType()
3845 : *
3846 : */
3847 :
3848 124 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3849 : const char *pszNewValue)
3850 :
3851 : {
3852 124 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3853 :
3854 124 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3855 124 : return poBand->SetUnitType(pszNewValue);
3856 : }
3857 :
3858 : /************************************************************************/
3859 : /* GetXSize() */
3860 : /************************************************************************/
3861 :
3862 : /**
3863 : * \brief Fetch XSize of raster.
3864 : *
3865 : * This method is the same as the C function GDALGetRasterBandXSize().
3866 : *
3867 : * @return the width in pixels of this band.
3868 : */
3869 :
3870 8538340 : int GDALRasterBand::GetXSize() const
3871 :
3872 : {
3873 8538340 : return nRasterXSize;
3874 : }
3875 :
3876 : /************************************************************************/
3877 : /* GDALGetRasterBandXSize() */
3878 : /************************************************************************/
3879 :
3880 : /**
3881 : * \brief Fetch XSize of raster.
3882 : *
3883 : * @see GDALRasterBand::GetXSize()
3884 : */
3885 :
3886 58289 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3887 :
3888 : {
3889 58289 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3890 :
3891 58289 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3892 58289 : return poBand->GetXSize();
3893 : }
3894 :
3895 : /************************************************************************/
3896 : /* GetYSize() */
3897 : /************************************************************************/
3898 :
3899 : /**
3900 : * \brief Fetch YSize of raster.
3901 : *
3902 : * This method is the same as the C function GDALGetRasterBandYSize().
3903 : *
3904 : * @return the height in pixels of this band.
3905 : */
3906 :
3907 4751980 : int GDALRasterBand::GetYSize() const
3908 :
3909 : {
3910 4751980 : return nRasterYSize;
3911 : }
3912 :
3913 : /************************************************************************/
3914 : /* GDALGetRasterBandYSize() */
3915 : /************************************************************************/
3916 :
3917 : /**
3918 : * \brief Fetch YSize of raster.
3919 : *
3920 : * @see GDALRasterBand::GetYSize()
3921 : */
3922 :
3923 57152 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3924 :
3925 : {
3926 57152 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3927 :
3928 57152 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3929 57152 : return poBand->GetYSize();
3930 : }
3931 :
3932 : /************************************************************************/
3933 : /* GetBand() */
3934 : /************************************************************************/
3935 :
3936 : /**
3937 : * \brief Fetch the band number.
3938 : *
3939 : * This method returns the band that this GDALRasterBand objects represents
3940 : * within its dataset. This method may return a value of 0 to indicate
3941 : * GDALRasterBand objects without an apparently relationship to a dataset,
3942 : * such as GDALRasterBands serving as overviews.
3943 : *
3944 : * This method is the same as the C function GDALGetBandNumber().
3945 : *
3946 : * @return band number (1+) or 0 if the band number isn't known.
3947 : */
3948 :
3949 152050 : int GDALRasterBand::GetBand() const
3950 :
3951 : {
3952 152050 : return nBand;
3953 : }
3954 :
3955 : /************************************************************************/
3956 : /* GDALGetBandNumber() */
3957 : /************************************************************************/
3958 :
3959 : /**
3960 : * \brief Fetch the band number.
3961 : *
3962 : * @see GDALRasterBand::GetBand()
3963 : */
3964 :
3965 159 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3966 :
3967 : {
3968 159 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3969 :
3970 159 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3971 159 : return poBand->GetBand();
3972 : }
3973 :
3974 : /************************************************************************/
3975 : /* GetDataset() */
3976 : /************************************************************************/
3977 :
3978 : /**
3979 : * \brief Fetch the owning dataset handle.
3980 : *
3981 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3982 : * such as overviews or other "freestanding" bands.
3983 : *
3984 : * This method is the same as the C function GDALGetBandDataset().
3985 : *
3986 : * @return the pointer to the GDALDataset to which this band belongs, or
3987 : * NULL if this cannot be determined.
3988 : */
3989 :
3990 5318500 : GDALDataset *GDALRasterBand::GetDataset() const
3991 :
3992 : {
3993 5318500 : return poDS;
3994 : }
3995 :
3996 : /************************************************************************/
3997 : /* GDALGetBandDataset() */
3998 : /************************************************************************/
3999 :
4000 : /**
4001 : * \brief Fetch the owning dataset handle.
4002 : *
4003 : * @see GDALRasterBand::GetDataset()
4004 : */
4005 :
4006 360 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4007 :
4008 : {
4009 360 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4010 :
4011 360 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4012 360 : return GDALDataset::ToHandle(poBand->GetDataset());
4013 : }
4014 :
4015 : /************************************************************************/
4016 : /* ComputeFloat16NoDataValue() */
4017 : /************************************************************************/
4018 :
4019 3285 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4020 : double dfNoDataValue,
4021 : int &bGotNoDataValue,
4022 : GFloat16 &hfNoDataValue,
4023 : bool &bGotFloat16NoDataValue)
4024 : {
4025 3285 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4026 : {
4027 7 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4028 7 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4029 : {
4030 7 : hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4031 7 : bGotFloat16NoDataValue = true;
4032 7 : bGotNoDataValue = false;
4033 : }
4034 : }
4035 3285 : }
4036 :
4037 : /************************************************************************/
4038 : /* ComputeFloatNoDataValue() */
4039 : /************************************************************************/
4040 :
4041 3285 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4042 : double dfNoDataValue,
4043 : int &bGotNoDataValue,
4044 : float &fNoDataValue,
4045 : bool &bGotFloatNoDataValue)
4046 : {
4047 3285 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4048 : {
4049 117 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4050 117 : if (GDALIsValueInRange<float>(dfNoDataValue))
4051 : {
4052 117 : fNoDataValue = static_cast<float>(dfNoDataValue);
4053 117 : bGotFloatNoDataValue = true;
4054 117 : bGotNoDataValue = false;
4055 : }
4056 : }
4057 3281 : else if (eDataType == GDT_Int16 && bGotNoDataValue &&
4058 113 : GDALIsValueExactAs<int16_t>(dfNoDataValue))
4059 : {
4060 113 : fNoDataValue = static_cast<float>(dfNoDataValue);
4061 113 : bGotFloatNoDataValue = true;
4062 : }
4063 3088 : else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
4064 33 : GDALIsValueExactAs<uint16_t>(dfNoDataValue))
4065 : {
4066 33 : fNoDataValue = static_cast<float>(dfNoDataValue);
4067 33 : bGotFloatNoDataValue = true;
4068 : }
4069 3029 : else if (eDataType == GDT_Float16 && bGotNoDataValue &&
4070 7 : GDALIsValueExactAs<GFloat16>(dfNoDataValue))
4071 : {
4072 7 : fNoDataValue = static_cast<float>(dfNoDataValue);
4073 7 : bGotFloatNoDataValue = true;
4074 : }
4075 3285 : }
4076 :
4077 : /************************************************************************/
4078 : /* struct GDALNoDataValues */
4079 : /************************************************************************/
4080 :
4081 : /**
4082 : * \brief No-data-values for all types
4083 : *
4084 : * The functions below pass various no-data-values around. To avoid
4085 : * long argument lists, this struct collects the no-data-values for
4086 : * all types into a single, convenient place.
4087 : **/
4088 :
4089 : struct GDALNoDataValues
4090 : {
4091 : int bGotNoDataValue;
4092 : double dfNoDataValue;
4093 :
4094 : bool bGotInt64NoDataValue;
4095 : int64_t nInt64NoDataValue;
4096 :
4097 : bool bGotUInt64NoDataValue;
4098 : uint64_t nUInt64NoDataValue;
4099 :
4100 : bool bGotFloatNoDataValue;
4101 : float fNoDataValue;
4102 :
4103 : bool bGotFloat16NoDataValue;
4104 : GFloat16 hfNoDataValue;
4105 :
4106 3385 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4107 3385 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4108 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4109 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4110 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4111 3385 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4112 : {
4113 3385 : if (eDataType == GDT_Int64)
4114 : {
4115 62 : int nGot = false;
4116 62 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4117 62 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4118 62 : if (bGotInt64NoDataValue)
4119 : {
4120 10 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4121 10 : bGotNoDataValue =
4122 10 : nInt64NoDataValue <=
4123 20 : std::numeric_limits<int64_t>::max() - 1024 &&
4124 10 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4125 : }
4126 : else
4127 52 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4128 : }
4129 3323 : else if (eDataType == GDT_UInt64)
4130 : {
4131 38 : int nGot = false;
4132 38 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4133 38 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4134 38 : if (bGotUInt64NoDataValue)
4135 : {
4136 10 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4137 10 : bGotNoDataValue =
4138 10 : nUInt64NoDataValue <=
4139 20 : std::numeric_limits<uint64_t>::max() - 2048 &&
4140 10 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4141 : }
4142 : else
4143 28 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4144 : }
4145 : else
4146 : {
4147 3285 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4148 3285 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4149 :
4150 3285 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4151 3285 : fNoDataValue, bGotFloatNoDataValue);
4152 :
4153 3285 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4154 3285 : hfNoDataValue, bGotFloat16NoDataValue);
4155 : }
4156 3385 : }
4157 : };
4158 :
4159 : /************************************************************************/
4160 : /* ARE_REAL_EQUAL() */
4161 : /************************************************************************/
4162 :
4163 28 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4164 : {
4165 : using std::abs;
4166 56 : return dfVal1 == dfVal2 || /* Should cover infinity */
4167 28 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4168 28 : abs(dfVal1 + dfVal2) * ulp;
4169 : }
4170 :
4171 : /************************************************************************/
4172 : /* GetHistogram() */
4173 : /************************************************************************/
4174 :
4175 : /**
4176 : * \brief Compute raster histogram.
4177 : *
4178 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4179 : *
4180 : * For example to compute a simple 256 entry histogram of eight bit data,
4181 : * the following would be suitable. The unusual bounds are to ensure that
4182 : * bucket boundaries don't fall right on integer values causing possible errors
4183 : * due to rounding after scaling.
4184 : \code{.cpp}
4185 : GUIntBig anHistogram[256];
4186 :
4187 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4188 : GDALDummyProgress, nullptr );
4189 : \endcode
4190 : *
4191 : * Note that setting bApproxOK will generally result in a subsampling of the
4192 : * file, and will utilize overviews if available. It should generally
4193 : * produce a representative histogram for the data that is suitable for use
4194 : * in generating histogram based luts for instance. Generally bApproxOK is
4195 : * much faster than an exactly computed histogram.
4196 : *
4197 : * This method is the same as the C functions GDALGetRasterHistogram() and
4198 : * GDALGetRasterHistogramEx().
4199 : *
4200 : * @param dfMin the lower bound of the histogram.
4201 : * @param dfMax the upper bound of the histogram.
4202 : * @param nBuckets the number of buckets in panHistogram.
4203 : * @param panHistogram array into which the histogram totals are placed.
4204 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4205 : * mapped into panHistogram[0], and values above will be mapped into
4206 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4207 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4208 : * @param pfnProgress function to report progress to completion.
4209 : * @param pProgressData application data to pass to pfnProgress.
4210 : *
4211 : * @return CE_None on success, or CE_Failure if something goes wrong.
4212 : */
4213 :
4214 45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4215 : GUIntBig *panHistogram,
4216 : int bIncludeOutOfRange, int bApproxOK,
4217 : GDALProgressFunc pfnProgress,
4218 : void *pProgressData)
4219 :
4220 : {
4221 45 : CPLAssert(nullptr != panHistogram);
4222 :
4223 45 : if (pfnProgress == nullptr)
4224 29 : pfnProgress = GDALDummyProgress;
4225 :
4226 : /* -------------------------------------------------------------------- */
4227 : /* If we have overviews, use them for the histogram. */
4228 : /* -------------------------------------------------------------------- */
4229 45 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4230 : {
4231 : // FIXME: should we use the most reduced overview here or use some
4232 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4233 : // does?
4234 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4235 :
4236 0 : if (poBestOverview != this)
4237 : {
4238 0 : return poBestOverview->GetHistogram(
4239 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4240 0 : bApproxOK, pfnProgress, pProgressData);
4241 : }
4242 : }
4243 :
4244 : /* -------------------------------------------------------------------- */
4245 : /* Read actual data and build histogram. */
4246 : /* -------------------------------------------------------------------- */
4247 45 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4248 : {
4249 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4250 0 : return CE_Failure;
4251 : }
4252 :
4253 : // Written this way to deal with NaN
4254 45 : if (!(dfMax > dfMin))
4255 : {
4256 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4257 : "dfMax should be strictly greater than dfMin");
4258 5 : return CE_Failure;
4259 : }
4260 :
4261 : GDALRasterIOExtraArg sExtraArg;
4262 40 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4263 :
4264 40 : const double dfScale = nBuckets / (dfMax - dfMin);
4265 40 : if (dfScale == 0 || !std::isfinite(dfScale))
4266 : {
4267 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4268 : "dfMin and dfMax should be finite values such that "
4269 : "nBuckets / (dfMax - dfMin) is non-zero");
4270 5 : return CE_Failure;
4271 : }
4272 35 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4273 :
4274 35 : GDALNoDataValues sNoDataValues(this, eDataType);
4275 35 : GDALRasterBand *poMaskBand = nullptr;
4276 35 : if (!sNoDataValues.bGotNoDataValue)
4277 : {
4278 34 : const int l_nMaskFlags = GetMaskFlags();
4279 36 : if (l_nMaskFlags != GMF_ALL_VALID &&
4280 2 : GetColorInterpretation() != GCI_AlphaBand)
4281 : {
4282 2 : poMaskBand = GetMaskBand();
4283 : }
4284 : }
4285 :
4286 35 : bool bSignedByte = false;
4287 35 : if (eDataType == GDT_UInt8)
4288 : {
4289 26 : EnablePixelTypeSignedByteWarning(false);
4290 : const char *pszPixelType =
4291 26 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4292 26 : EnablePixelTypeSignedByteWarning(true);
4293 26 : bSignedByte =
4294 26 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4295 : }
4296 :
4297 35 : if (bApproxOK && HasArbitraryOverviews())
4298 : {
4299 : /* --------------------------------------------------------------------
4300 : */
4301 : /* Figure out how much the image should be reduced to get an */
4302 : /* approximate value. */
4303 : /* --------------------------------------------------------------------
4304 : */
4305 : const double dfReduction =
4306 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4307 : GDALSTAT_APPROX_NUMSAMPLES);
4308 :
4309 0 : int nXReduced = nRasterXSize;
4310 0 : int nYReduced = nRasterYSize;
4311 0 : if (dfReduction > 1.0)
4312 : {
4313 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4314 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4315 :
4316 : // Catch the case of huge resizing ratios here
4317 0 : if (nXReduced == 0)
4318 0 : nXReduced = 1;
4319 0 : if (nYReduced == 0)
4320 0 : nYReduced = 1;
4321 : }
4322 :
4323 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4324 : nXReduced, nYReduced);
4325 0 : if (!pData)
4326 0 : return CE_Failure;
4327 :
4328 : const CPLErr eErr =
4329 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4330 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4331 0 : if (eErr != CE_None)
4332 : {
4333 0 : CPLFree(pData);
4334 0 : return eErr;
4335 : }
4336 :
4337 0 : GByte *pabyMaskData = nullptr;
4338 0 : if (poMaskBand)
4339 : {
4340 : pabyMaskData =
4341 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4342 0 : if (!pabyMaskData)
4343 : {
4344 0 : CPLFree(pData);
4345 0 : return CE_Failure;
4346 : }
4347 :
4348 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4349 : pabyMaskData, nXReduced, nYReduced,
4350 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
4351 : {
4352 0 : CPLFree(pData);
4353 0 : CPLFree(pabyMaskData);
4354 0 : return CE_Failure;
4355 : }
4356 : }
4357 :
4358 : // This isn't the fastest way to do this, but is easier for now.
4359 0 : for (int iY = 0; iY < nYReduced; iY++)
4360 : {
4361 0 : for (int iX = 0; iX < nXReduced; iX++)
4362 : {
4363 0 : const int iOffset = iX + iY * nXReduced;
4364 0 : double dfValue = 0.0;
4365 :
4366 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4367 0 : continue;
4368 :
4369 0 : switch (eDataType)
4370 : {
4371 0 : case GDT_UInt8:
4372 : {
4373 0 : if (bSignedByte)
4374 0 : dfValue =
4375 0 : static_cast<signed char *>(pData)[iOffset];
4376 : else
4377 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4378 0 : break;
4379 : }
4380 0 : case GDT_Int8:
4381 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4382 0 : break;
4383 0 : case GDT_UInt16:
4384 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4385 0 : break;
4386 0 : case GDT_Int16:
4387 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4388 0 : break;
4389 0 : case GDT_UInt32:
4390 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4391 0 : break;
4392 0 : case GDT_Int32:
4393 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4394 0 : break;
4395 0 : case GDT_UInt64:
4396 0 : dfValue = static_cast<double>(
4397 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4398 0 : break;
4399 0 : case GDT_Int64:
4400 0 : dfValue = static_cast<double>(
4401 0 : static_cast<GInt64 *>(pData)[iOffset]);
4402 0 : break;
4403 0 : case GDT_Float16:
4404 : {
4405 : using namespace std;
4406 0 : const GFloat16 hfValue =
4407 0 : static_cast<GFloat16 *>(pData)[iOffset];
4408 0 : if (isnan(hfValue) ||
4409 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4410 0 : ARE_REAL_EQUAL(hfValue,
4411 : sNoDataValues.hfNoDataValue)))
4412 0 : continue;
4413 0 : dfValue = hfValue;
4414 0 : break;
4415 : }
4416 0 : case GDT_Float32:
4417 : {
4418 0 : const float fValue =
4419 0 : static_cast<float *>(pData)[iOffset];
4420 0 : if (std::isnan(fValue) ||
4421 0 : (sNoDataValues.bGotFloatNoDataValue &&
4422 0 : ARE_REAL_EQUAL(fValue,
4423 : sNoDataValues.fNoDataValue)))
4424 0 : continue;
4425 0 : dfValue = double(fValue);
4426 0 : break;
4427 : }
4428 0 : case GDT_Float64:
4429 0 : dfValue = static_cast<double *>(pData)[iOffset];
4430 0 : if (std::isnan(dfValue))
4431 0 : continue;
4432 0 : break;
4433 0 : case GDT_CInt16:
4434 : {
4435 0 : const double dfReal =
4436 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4437 0 : const double dfImag =
4438 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4439 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4440 0 : continue;
4441 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4442 : }
4443 0 : break;
4444 0 : case GDT_CInt32:
4445 : {
4446 0 : const double dfReal =
4447 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4448 0 : const double dfImag =
4449 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4450 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4451 0 : continue;
4452 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4453 : }
4454 0 : break;
4455 0 : case GDT_CFloat16:
4456 : {
4457 : const double dfReal =
4458 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4459 : const double dfImag =
4460 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4461 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4462 0 : continue;
4463 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4464 0 : break;
4465 : }
4466 0 : case GDT_CFloat32:
4467 : {
4468 0 : const double dfReal =
4469 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4470 0 : const double dfImag = double(
4471 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4472 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4473 0 : continue;
4474 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4475 0 : break;
4476 : }
4477 0 : case GDT_CFloat64:
4478 : {
4479 0 : const double dfReal =
4480 0 : static_cast<double *>(pData)[iOffset * 2];
4481 0 : const double dfImag =
4482 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4483 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4484 0 : continue;
4485 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4486 0 : break;
4487 : }
4488 0 : case GDT_Unknown:
4489 : case GDT_TypeCount:
4490 0 : CPLAssert(false);
4491 : }
4492 :
4493 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4494 0 : sNoDataValues.bGotNoDataValue &&
4495 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4496 0 : continue;
4497 :
4498 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4499 : // finite, the result of the multiplication cannot be NaN
4500 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4501 :
4502 0 : if (dfIndex < 0)
4503 : {
4504 0 : if (bIncludeOutOfRange)
4505 0 : panHistogram[0]++;
4506 : }
4507 0 : else if (dfIndex >= nBuckets)
4508 : {
4509 0 : if (bIncludeOutOfRange)
4510 0 : ++panHistogram[nBuckets - 1];
4511 : }
4512 : else
4513 : {
4514 0 : ++panHistogram[static_cast<int>(dfIndex)];
4515 : }
4516 : }
4517 : }
4518 :
4519 0 : CPLFree(pData);
4520 0 : CPLFree(pabyMaskData);
4521 : }
4522 : else // No arbitrary overviews.
4523 : {
4524 35 : if (!InitBlockInfo())
4525 0 : return CE_Failure;
4526 :
4527 : /* --------------------------------------------------------------------
4528 : */
4529 : /* Figure out the ratio of blocks we will read to get an */
4530 : /* approximate value. */
4531 : /* --------------------------------------------------------------------
4532 : */
4533 :
4534 35 : int nSampleRate = 1;
4535 35 : if (bApproxOK)
4536 : {
4537 8 : nSampleRate = static_cast<int>(std::max(
4538 16 : 1.0,
4539 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4540 : // We want to avoid probing only the first column of blocks for
4541 : // a square shaped raster, because it is not unlikely that it may
4542 : // be padding only (#6378).
4543 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4544 1 : nSampleRate += 1;
4545 : }
4546 :
4547 35 : GByte *pabyMaskData = nullptr;
4548 35 : if (poMaskBand)
4549 : {
4550 : pabyMaskData = static_cast<GByte *>(
4551 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4552 2 : if (!pabyMaskData)
4553 : {
4554 0 : return CE_Failure;
4555 : }
4556 : }
4557 :
4558 : /* --------------------------------------------------------------------
4559 : */
4560 : /* Read the blocks, and add to histogram. */
4561 : /* --------------------------------------------------------------------
4562 : */
4563 35 : for (GIntBig iSampleBlock = 0;
4564 160 : iSampleBlock <
4565 160 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4566 125 : iSampleBlock += nSampleRate)
4567 : {
4568 125 : if (!pfnProgress(
4569 125 : static_cast<double>(iSampleBlock) /
4570 125 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4571 : "Compute Histogram", pProgressData))
4572 : {
4573 0 : CPLFree(pabyMaskData);
4574 0 : return CE_Failure;
4575 : }
4576 :
4577 125 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4578 125 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4579 :
4580 125 : int nXCheck = 0, nYCheck = 0;
4581 125 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4582 :
4583 127 : if (poMaskBand &&
4584 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4585 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4586 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4587 2 : 0, nBlockXSize, nullptr) != CE_None)
4588 : {
4589 0 : CPLFree(pabyMaskData);
4590 0 : return CE_Failure;
4591 : }
4592 :
4593 125 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4594 125 : if (poBlock == nullptr)
4595 : {
4596 0 : CPLFree(pabyMaskData);
4597 0 : return CE_Failure;
4598 : }
4599 :
4600 125 : void *pData = poBlock->GetDataRef();
4601 :
4602 : // this is a special case for a common situation.
4603 125 : if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4604 89 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4605 86 : nXCheck == nBlockXSize && nBuckets == 256)
4606 : {
4607 86 : const GPtrDiff_t nPixels =
4608 86 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4609 86 : GByte *pabyData = static_cast<GByte *>(pData);
4610 :
4611 79640 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4612 : {
4613 79554 : if (pabyMaskData && pabyMaskData[i] == 0)
4614 0 : continue;
4615 79554 : if (!(sNoDataValues.bGotNoDataValue &&
4616 512 : (pabyData[i] ==
4617 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4618 : {
4619 79298 : panHistogram[pabyData[i]]++;
4620 : }
4621 : }
4622 :
4623 86 : poBlock->DropLock();
4624 86 : continue; // To next sample block.
4625 : }
4626 :
4627 : // This isn't the fastest way to do this, but is easier for now.
4628 257 : for (int iY = 0; iY < nYCheck; iY++)
4629 : {
4630 36389 : for (int iX = 0; iX < nXCheck; iX++)
4631 : {
4632 36171 : const GPtrDiff_t iOffset =
4633 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4634 :
4635 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4636 2 : continue;
4637 :
4638 36169 : double dfValue = 0.0;
4639 :
4640 36169 : switch (eDataType)
4641 : {
4642 19716 : case GDT_UInt8:
4643 : {
4644 19716 : if (bSignedByte)
4645 0 : dfValue =
4646 0 : static_cast<signed char *>(pData)[iOffset];
4647 : else
4648 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4649 19716 : break;
4650 : }
4651 1 : case GDT_Int8:
4652 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4653 1 : break;
4654 16384 : case GDT_UInt16:
4655 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4656 16384 : break;
4657 3 : case GDT_Int16:
4658 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4659 3 : break;
4660 0 : case GDT_UInt32:
4661 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4662 0 : break;
4663 60 : case GDT_Int32:
4664 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4665 60 : break;
4666 0 : case GDT_UInt64:
4667 0 : dfValue = static_cast<double>(
4668 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4669 0 : break;
4670 0 : case GDT_Int64:
4671 0 : dfValue = static_cast<double>(
4672 0 : static_cast<GInt64 *>(pData)[iOffset]);
4673 0 : break;
4674 0 : case GDT_Float16:
4675 : {
4676 : using namespace std;
4677 0 : const GFloat16 hfValue =
4678 0 : static_cast<GFloat16 *>(pData)[iOffset];
4679 0 : if (isnan(hfValue) ||
4680 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4681 0 : ARE_REAL_EQUAL(hfValue,
4682 : sNoDataValues.hfNoDataValue)))
4683 0 : continue;
4684 0 : dfValue = hfValue;
4685 0 : break;
4686 : }
4687 3 : case GDT_Float32:
4688 : {
4689 3 : const float fValue =
4690 3 : static_cast<float *>(pData)[iOffset];
4691 6 : if (std::isnan(fValue) ||
4692 6 : (sNoDataValues.bGotFloatNoDataValue &&
4693 3 : ARE_REAL_EQUAL(fValue,
4694 : sNoDataValues.fNoDataValue)))
4695 0 : continue;
4696 3 : dfValue = double(fValue);
4697 3 : break;
4698 : }
4699 2 : case GDT_Float64:
4700 2 : dfValue = static_cast<double *>(pData)[iOffset];
4701 2 : if (std::isnan(dfValue))
4702 0 : continue;
4703 2 : break;
4704 0 : case GDT_CInt16:
4705 : {
4706 0 : double dfReal =
4707 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4708 0 : double dfImag =
4709 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4710 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4711 0 : break;
4712 : }
4713 0 : case GDT_CInt32:
4714 : {
4715 0 : double dfReal =
4716 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4717 0 : double dfImag =
4718 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4719 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4720 0 : break;
4721 : }
4722 0 : case GDT_CFloat16:
4723 : {
4724 : double dfReal =
4725 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4726 : double dfImag =
4727 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4728 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4729 0 : continue;
4730 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4731 0 : break;
4732 : }
4733 0 : case GDT_CFloat32:
4734 : {
4735 0 : double dfReal = double(
4736 0 : static_cast<float *>(pData)[iOffset * 2]);
4737 0 : double dfImag = double(
4738 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4739 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4740 0 : continue;
4741 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4742 0 : break;
4743 : }
4744 0 : case GDT_CFloat64:
4745 : {
4746 0 : double dfReal =
4747 0 : static_cast<double *>(pData)[iOffset * 2];
4748 0 : double dfImag =
4749 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4750 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4751 0 : continue;
4752 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4753 0 : break;
4754 : }
4755 0 : case GDT_Unknown:
4756 : case GDT_TypeCount:
4757 0 : CPLAssert(false);
4758 : CPLFree(pabyMaskData);
4759 : return CE_Failure;
4760 : }
4761 :
4762 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4763 72338 : sNoDataValues.bGotNoDataValue &&
4764 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4765 0 : continue;
4766 :
4767 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4768 : // and finite, the result of the multiplication cannot be
4769 : // NaN
4770 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4771 :
4772 36169 : if (dfIndex < 0)
4773 : {
4774 1 : if (bIncludeOutOfRange)
4775 1 : panHistogram[0]++;
4776 : }
4777 36168 : else if (dfIndex >= nBuckets)
4778 : {
4779 7 : if (bIncludeOutOfRange)
4780 4 : ++panHistogram[nBuckets - 1];
4781 : }
4782 : else
4783 : {
4784 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4785 : }
4786 : }
4787 : }
4788 :
4789 39 : poBlock->DropLock();
4790 : }
4791 :
4792 35 : CPLFree(pabyMaskData);
4793 : }
4794 :
4795 35 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4796 :
4797 35 : return CE_None;
4798 : }
4799 :
4800 : /************************************************************************/
4801 : /* GDALGetRasterHistogram() */
4802 : /************************************************************************/
4803 :
4804 : /**
4805 : * \brief Compute raster histogram.
4806 : *
4807 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4808 : * exceeding 2 billion.
4809 : *
4810 : * @see GDALRasterBand::GetHistogram()
4811 : * @see GDALGetRasterHistogramEx()
4812 : */
4813 :
4814 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4815 : double dfMax, int nBuckets,
4816 : int *panHistogram,
4817 : int bIncludeOutOfRange, int bApproxOK,
4818 : GDALProgressFunc pfnProgress,
4819 : void *pProgressData)
4820 :
4821 : {
4822 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4823 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4824 :
4825 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4826 :
4827 : GUIntBig *panHistogramTemp =
4828 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4829 0 : if (panHistogramTemp == nullptr)
4830 : {
4831 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4832 : "Out of memory in GDALGetRasterHistogram().");
4833 0 : return CE_Failure;
4834 : }
4835 :
4836 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4837 : bIncludeOutOfRange, bApproxOK,
4838 0 : pfnProgress, pProgressData);
4839 :
4840 0 : if (eErr == CE_None)
4841 : {
4842 0 : for (int i = 0; i < nBuckets; i++)
4843 : {
4844 0 : if (panHistogramTemp[i] > INT_MAX)
4845 : {
4846 0 : CPLError(CE_Warning, CPLE_AppDefined,
4847 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4848 : " exceeds maximum 32 bit value",
4849 0 : i, panHistogramTemp[i]);
4850 0 : panHistogram[i] = INT_MAX;
4851 : }
4852 : else
4853 : {
4854 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4855 : }
4856 : }
4857 : }
4858 :
4859 0 : CPLFree(panHistogramTemp);
4860 :
4861 0 : return eErr;
4862 : }
4863 :
4864 : /************************************************************************/
4865 : /* GDALGetRasterHistogramEx() */
4866 : /************************************************************************/
4867 :
4868 : /**
4869 : * \brief Compute raster histogram.
4870 : *
4871 : * @see GDALRasterBand::GetHistogram()
4872 : *
4873 : */
4874 :
4875 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4876 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4877 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4878 : GDALProgressFunc pfnProgress, void *pProgressData)
4879 :
4880 : {
4881 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4882 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4883 :
4884 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4885 :
4886 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4887 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4888 26 : pProgressData);
4889 : }
4890 :
4891 : /************************************************************************/
4892 : /* GetDefaultHistogram() */
4893 : /************************************************************************/
4894 :
4895 : /**
4896 : * \brief Fetch default raster histogram.
4897 : *
4898 : * The default method in GDALRasterBand will compute a default histogram. This
4899 : * method is overridden by derived classes (such as GDALPamRasterBand,
4900 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4901 : * stored histogram.
4902 : *
4903 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4904 : * GDALGetDefaultHistogramEx().
4905 : *
4906 : * @param pdfMin pointer to double value that will contain the lower bound of
4907 : * the histogram.
4908 : * @param pdfMax pointer to double value that will contain the upper bound of
4909 : * the histogram.
4910 : * @param pnBuckets pointer to int value that will contain the number of buckets
4911 : * in *ppanHistogram.
4912 : * @param ppanHistogram pointer to array into which the histogram totals are
4913 : * placed. To be freed with VSIFree
4914 : * @param bForce TRUE to force the computation. If FALSE and no default
4915 : * histogram is available, the method will return CE_Warning
4916 : * @param pfnProgress function to report progress to completion.
4917 : * @param pProgressData application data to pass to pfnProgress.
4918 : *
4919 : * @return CE_None on success, CE_Failure if something goes wrong, or
4920 : * CE_Warning if no default histogram is available.
4921 : */
4922 :
4923 27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4924 : int *pnBuckets,
4925 : GUIntBig **ppanHistogram, int bForce,
4926 : GDALProgressFunc pfnProgress,
4927 : void *pProgressData)
4928 :
4929 : {
4930 27 : CPLAssert(nullptr != pnBuckets);
4931 27 : CPLAssert(nullptr != ppanHistogram);
4932 27 : CPLAssert(nullptr != pdfMin);
4933 27 : CPLAssert(nullptr != pdfMax);
4934 :
4935 27 : *pnBuckets = 0;
4936 27 : *ppanHistogram = nullptr;
4937 :
4938 27 : if (!bForce)
4939 5 : return CE_Warning;
4940 :
4941 22 : int nBuckets = 256;
4942 :
4943 22 : bool bSignedByte = false;
4944 22 : if (eDataType == GDT_UInt8)
4945 : {
4946 20 : EnablePixelTypeSignedByteWarning(false);
4947 : const char *pszPixelType =
4948 20 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4949 20 : EnablePixelTypeSignedByteWarning(true);
4950 20 : bSignedByte =
4951 20 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4952 : }
4953 :
4954 22 : if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4955 : {
4956 20 : *pdfMin = -0.5;
4957 20 : *pdfMax = 255.5;
4958 : }
4959 2 : else if (GetRasterDataType() == GDT_Int8)
4960 : {
4961 1 : *pdfMin = -128 - 0.5;
4962 1 : *pdfMax = 127 + 0.5;
4963 : }
4964 : else
4965 : {
4966 :
4967 : const CPLErr eErr =
4968 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4969 1 : if (eErr != CE_None)
4970 0 : return eErr;
4971 1 : if (*pdfMin == *pdfMax)
4972 : {
4973 1 : nBuckets = 1;
4974 1 : *pdfMin -= 0.5;
4975 1 : *pdfMax += 0.5;
4976 : }
4977 : else
4978 : {
4979 0 : const double dfHalfBucket =
4980 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4981 0 : *pdfMin -= dfHalfBucket;
4982 0 : *pdfMax += dfHalfBucket;
4983 : }
4984 : }
4985 :
4986 22 : *ppanHistogram =
4987 22 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4988 22 : if (*ppanHistogram == nullptr)
4989 : {
4990 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4991 : "Out of memory in GetDefaultHistogram().");
4992 0 : return CE_Failure;
4993 : }
4994 :
4995 22 : *pnBuckets = nBuckets;
4996 44 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4997 22 : TRUE, FALSE, pfnProgress, pProgressData);
4998 22 : if (eErr != CE_None)
4999 : {
5000 0 : *pnBuckets = 0;
5001 : }
5002 22 : return eErr;
5003 : }
5004 :
5005 : /************************************************************************/
5006 : /* GDALGetDefaultHistogram() */
5007 : /************************************************************************/
5008 :
5009 : /**
5010 : * \brief Fetch default raster histogram.
5011 : *
5012 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5013 : * exceeding 2 billion.
5014 : *
5015 : * @see GDALRasterBand::GDALGetDefaultHistogram()
5016 : * @see GDALGetRasterHistogramEx()
5017 : */
5018 :
5019 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5020 : double *pdfMin, double *pdfMax,
5021 : int *pnBuckets, int **ppanHistogram,
5022 : int bForce,
5023 : GDALProgressFunc pfnProgress,
5024 : void *pProgressData)
5025 :
5026 : {
5027 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5028 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5029 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5030 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5031 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5032 :
5033 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5034 0 : GUIntBig *panHistogramTemp = nullptr;
5035 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5036 : &panHistogramTemp, bForce,
5037 0 : pfnProgress, pProgressData);
5038 0 : if (eErr == CE_None)
5039 : {
5040 0 : const int nBuckets = *pnBuckets;
5041 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5042 0 : if (*ppanHistogram == nullptr)
5043 : {
5044 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5045 : "Out of memory in GDALGetDefaultHistogram().");
5046 0 : VSIFree(panHistogramTemp);
5047 0 : return CE_Failure;
5048 : }
5049 :
5050 0 : for (int i = 0; i < nBuckets; ++i)
5051 : {
5052 0 : if (panHistogramTemp[i] > INT_MAX)
5053 : {
5054 0 : CPLError(CE_Warning, CPLE_AppDefined,
5055 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5056 : " exceeds maximum 32 bit value",
5057 0 : i, panHistogramTemp[i]);
5058 0 : (*ppanHistogram)[i] = INT_MAX;
5059 : }
5060 : else
5061 : {
5062 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5063 : }
5064 : }
5065 :
5066 0 : CPLFree(panHistogramTemp);
5067 : }
5068 : else
5069 : {
5070 0 : *ppanHistogram = nullptr;
5071 : }
5072 :
5073 0 : return eErr;
5074 : }
5075 :
5076 : /************************************************************************/
5077 : /* GDALGetDefaultHistogramEx() */
5078 : /************************************************************************/
5079 :
5080 : /**
5081 : * \brief Fetch default raster histogram.
5082 : *
5083 : * @see GDALRasterBand::GetDefaultHistogram()
5084 : *
5085 : */
5086 :
5087 : CPLErr CPL_STDCALL
5088 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5089 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5090 : GDALProgressFunc pfnProgress, void *pProgressData)
5091 :
5092 : {
5093 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5094 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5095 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5096 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5097 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5098 :
5099 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5100 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5101 30 : bForce, pfnProgress, pProgressData);
5102 : }
5103 :
5104 : /************************************************************************/
5105 : /* AdviseRead() */
5106 : /************************************************************************/
5107 :
5108 : /**
5109 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5110 : * \brief Advise driver of upcoming read requests.
5111 : *
5112 : * Some GDAL drivers operate more efficiently if they know in advance what
5113 : * set of upcoming read requests will be made. The AdviseRead() method allows
5114 : * an application to notify the driver of the region of interest,
5115 : * and at what resolution the region will be read.
5116 : *
5117 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5118 : * accelerate access via some drivers.
5119 : *
5120 : * Depending on call paths, drivers might receive several calls to
5121 : * AdviseRead() with the same parameters.
5122 : *
5123 : * @param nXOff The pixel offset to the top left corner of the region
5124 : * of the band to be accessed. This would be zero to start from the left side.
5125 : *
5126 : * @param nYOff The line offset to the top left corner of the region
5127 : * of the band to be accessed. This would be zero to start from the top.
5128 : *
5129 : * @param nXSize The width of the region of the band to be accessed in pixels.
5130 : *
5131 : * @param nYSize The height of the region of the band to be accessed in lines.
5132 : *
5133 : * @param nBufXSize the width of the buffer image into which the desired region
5134 : * is to be read, or from which it is to be written.
5135 : *
5136 : * @param nBufYSize the height of the buffer image into which the desired
5137 : * region is to be read, or from which it is to be written.
5138 : *
5139 : * @param eBufType the type of the pixel values in the pData data buffer. The
5140 : * pixel values will automatically be translated to/from the GDALRasterBand
5141 : * data type as needed.
5142 : *
5143 : * @param papszOptions a list of name=value strings with special control
5144 : * options. Normally this is NULL.
5145 : *
5146 : * @return CE_Failure if the request is invalid and CE_None if it works or
5147 : * is ignored.
5148 : */
5149 :
5150 : /**/
5151 : /**/
5152 :
5153 114741 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5154 : int /*nYSize*/, int /*nBufXSize*/,
5155 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5156 : CSLConstList /*papszOptions*/)
5157 : {
5158 114741 : return CE_None;
5159 : }
5160 :
5161 : /************************************************************************/
5162 : /* GDALRasterAdviseRead() */
5163 : /************************************************************************/
5164 :
5165 : /**
5166 : * \brief Advise driver of upcoming read requests.
5167 : *
5168 : * @see GDALRasterBand::AdviseRead()
5169 : */
5170 :
5171 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5172 : int nYOff, int nXSize, int nYSize,
5173 : int nBufXSize, int nBufYSize,
5174 : GDALDataType eDT,
5175 : CSLConstList papszOptions)
5176 :
5177 : {
5178 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5179 :
5180 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5181 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5182 : nBufYSize, eDT,
5183 2 : const_cast<char **>(papszOptions));
5184 : }
5185 :
5186 : /************************************************************************/
5187 : /* GetStatistics() */
5188 : /************************************************************************/
5189 :
5190 : /**
5191 : * \brief Fetch image statistics.
5192 : *
5193 : * Returns the minimum, maximum, mean and standard deviation of all
5194 : * pixel values in this band. If approximate statistics are sufficient,
5195 : * the bApproxOK flag can be set to true in which case overviews, or a
5196 : * subset of image tiles may be used in computing the statistics.
5197 : *
5198 : * If bForce is FALSE results will only be returned if it can be done
5199 : * quickly (i.e. without scanning the image, typically by using pre-existing
5200 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5201 : * returned efficiently, the method will return CE_Warning but no warning will
5202 : * be issued. This is a non-standard use of the CE_Warning return value
5203 : * to indicate "nothing done".
5204 : *
5205 : * If bForce is TRUE, and results are quickly available without scanning the
5206 : * image, they will be used. If bForce is TRUE and results are not quickly
5207 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5208 : * which will scan the image.
5209 : *
5210 : * To always force recomputation of statistics, use ComputeStatistics() instead
5211 : * of this method.
5212 : *
5213 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5214 : * will generally cache statistics in the .pam file allowing fast fetch
5215 : * after the first request.
5216 : *
5217 : * This method is the same as the C function GDALGetRasterStatistics().
5218 : *
5219 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5220 : * or a subset of all tiles.
5221 : *
5222 : * @param bForce If FALSE statistics will only be returned if it can
5223 : * be done without rescanning the image. If TRUE, statistics computation will
5224 : * be forced if pre-existing values are not quickly available.
5225 : *
5226 : * @param pdfMin Location into which to load image minimum (may be NULL).
5227 : *
5228 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5229 : *
5230 : * @param pdfMean Location into which to load image mean (may be NULL).
5231 : *
5232 : * @param pdfStdDev Location into which to load image standard deviation
5233 : * (may be NULL).
5234 : *
5235 : * @return CE_None on success, CE_Warning if no values returned,
5236 : * CE_Failure if an error occurs.
5237 : */
5238 :
5239 676 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5240 : double *pdfMax, double *pdfMean,
5241 : double *pdfStdDev)
5242 :
5243 : {
5244 : /* -------------------------------------------------------------------- */
5245 : /* Do we already have metadata items for the requested values? */
5246 : /* -------------------------------------------------------------------- */
5247 1352 : if ((pdfMin == nullptr ||
5248 676 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5249 206 : (pdfMax == nullptr ||
5250 206 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5251 1558 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5252 206 : (pdfStdDev == nullptr ||
5253 206 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5254 : {
5255 206 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5256 : {
5257 199 : if (pdfMin != nullptr)
5258 199 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5259 199 : if (pdfMax != nullptr)
5260 199 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5261 199 : if (pdfMean != nullptr)
5262 199 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5263 199 : if (pdfStdDev != nullptr)
5264 199 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5265 :
5266 199 : return CE_None;
5267 : }
5268 : }
5269 :
5270 : /* -------------------------------------------------------------------- */
5271 : /* Does the driver already know the min/max? */
5272 : /* -------------------------------------------------------------------- */
5273 477 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5274 : {
5275 1 : int bSuccessMin = FALSE;
5276 1 : int bSuccessMax = FALSE;
5277 :
5278 1 : const double dfMin = GetMinimum(&bSuccessMin);
5279 1 : const double dfMax = GetMaximum(&bSuccessMax);
5280 :
5281 1 : if (bSuccessMin && bSuccessMax)
5282 : {
5283 0 : if (pdfMin != nullptr)
5284 0 : *pdfMin = dfMin;
5285 0 : if (pdfMax != nullptr)
5286 0 : *pdfMax = dfMax;
5287 0 : return CE_None;
5288 : }
5289 : }
5290 :
5291 : /* -------------------------------------------------------------------- */
5292 : /* Either return without results, or force computation. */
5293 : /* -------------------------------------------------------------------- */
5294 477 : if (!bForce)
5295 194 : return CE_Warning;
5296 : else
5297 283 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5298 283 : GDALDummyProgress, nullptr);
5299 : }
5300 :
5301 : /************************************************************************/
5302 : /* GDALGetRasterStatistics() */
5303 : /************************************************************************/
5304 :
5305 : /**
5306 : * \brief Fetch image statistics.
5307 : *
5308 : * @see GDALRasterBand::GetStatistics()
5309 : */
5310 :
5311 324 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5312 : int bForce, double *pdfMin,
5313 : double *pdfMax, double *pdfMean,
5314 : double *pdfStdDev)
5315 :
5316 : {
5317 324 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5318 :
5319 324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5320 324 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5321 324 : pdfStdDev);
5322 : }
5323 :
5324 : /************************************************************************/
5325 : /* GDALUInt128 */
5326 : /************************************************************************/
5327 :
5328 : #ifdef HAVE_UINT128_T
5329 : class GDALUInt128
5330 : {
5331 : __uint128_t val;
5332 :
5333 1203 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5334 : {
5335 1203 : }
5336 :
5337 : public:
5338 802 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5339 : {
5340 : // Evaluates to just a single mul on x86_64
5341 802 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5342 : }
5343 :
5344 401 : GDALUInt128 operator-(const GDALUInt128 &other) const
5345 : {
5346 401 : return GDALUInt128(val - other.val);
5347 : }
5348 :
5349 392 : operator double() const
5350 : {
5351 392 : return static_cast<double>(val);
5352 : }
5353 : };
5354 : #else
5355 :
5356 : #if defined(_MSC_VER) && defined(_M_X64)
5357 : #include <intrin.h>
5358 : #endif
5359 :
5360 : class GDALUInt128
5361 : {
5362 : GUIntBig low, high;
5363 :
5364 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5365 : {
5366 : }
5367 :
5368 : public:
5369 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5370 : {
5371 : #if defined(_MSC_VER) && defined(_M_X64)
5372 : GUIntBig highRes;
5373 : GUIntBig lowRes = _umul128(first, second, &highRes);
5374 : return GDALUInt128(lowRes, highRes);
5375 : #else
5376 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5377 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5378 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5379 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5380 : GUIntBig highRes = 0;
5381 : const GUIntBig firstLowSecondHigh =
5382 : static_cast<GUIntBig>(firstLow) * secondHigh;
5383 : const GUIntBig firstHighSecondLow =
5384 : static_cast<GUIntBig>(firstHigh) * secondLow;
5385 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5386 : if (middleTerm < firstLowSecondHigh) // check for overflow
5387 : highRes += static_cast<GUIntBig>(1) << 32;
5388 : const GUIntBig firstLowSecondLow =
5389 : static_cast<GUIntBig>(firstLow) * secondLow;
5390 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5391 : if (lowRes < firstLowSecondLow) // check for overflow
5392 : highRes++;
5393 : highRes +=
5394 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5395 : return GDALUInt128(lowRes, highRes);
5396 : #endif
5397 : }
5398 :
5399 : GDALUInt128 operator-(const GDALUInt128 &other) const
5400 : {
5401 : GUIntBig highRes = high - other.high;
5402 : GUIntBig lowRes = low - other.low;
5403 : if (lowRes > low) // check for underflow
5404 : --highRes;
5405 : return GDALUInt128(lowRes, highRes);
5406 : }
5407 :
5408 : operator double() const
5409 : {
5410 : const double twoPow64 = 18446744073709551616.0;
5411 : return high * twoPow64 + low;
5412 : }
5413 : };
5414 : #endif
5415 :
5416 : /************************************************************************/
5417 : /* ComputeStatisticsInternal() */
5418 : /************************************************************************/
5419 :
5420 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5421 : // not needed.
5422 : #define static_cast_for_coverity_scan static_cast
5423 :
5424 : // The rationale for below optimizations is detailed in statistics.txt
5425 :
5426 : // Use with T = GByte or GUInt16 only !
5427 : template <class T, bool COMPUTE_OTHER_STATS>
5428 : struct ComputeStatisticsInternalGeneric
5429 : {
5430 301 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5431 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5432 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5433 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5434 : {
5435 : static_assert(std::is_same<T, GByte>::value ||
5436 : std::is_same<T, GUInt16>::value,
5437 : "bad type for T");
5438 301 : if (bHasNoData)
5439 : {
5440 : // General case
5441 700 : for (int iY = 0; iY < nYCheck; iY++)
5442 : {
5443 161945 : for (int iX = 0; iX < nXCheck; iX++)
5444 : {
5445 161413 : const GPtrDiff_t iOffset =
5446 161413 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5447 161413 : const GUInt32 nValue = pData[iOffset];
5448 161413 : if (nValue == nNoDataValue)
5449 339 : continue;
5450 161074 : if (nValue < nMin)
5451 64 : nMin = nValue;
5452 161074 : if (nValue > nMax)
5453 179 : nMax = nValue;
5454 : if constexpr (COMPUTE_OTHER_STATS)
5455 : {
5456 159334 : nValidCount++;
5457 159334 : nSum += nValue;
5458 159334 : nSumSquare +=
5459 159334 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5460 159334 : nValue;
5461 : }
5462 : }
5463 : }
5464 : if constexpr (COMPUTE_OTHER_STATS)
5465 : {
5466 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5467 : }
5468 : }
5469 153 : else if (nMin == std::numeric_limits<T>::lowest() &&
5470 20 : nMax == std::numeric_limits<T>::max())
5471 : {
5472 : if constexpr (COMPUTE_OTHER_STATS)
5473 : {
5474 : // Optimization when there is no nodata and we know we have already
5475 : // reached the min and max
5476 416 : for (int iY = 0; iY < nYCheck; iY++)
5477 : {
5478 : int iX;
5479 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5480 : {
5481 1600 : const GPtrDiff_t iOffset =
5482 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5483 1600 : const GUIntBig nValue = pData[iOffset];
5484 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5485 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5486 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5487 1600 : nSum += nValue;
5488 1600 : nSumSquare += nValue * nValue;
5489 1600 : nSum += nValue2;
5490 1600 : nSumSquare += nValue2 * nValue2;
5491 1600 : nSum += nValue3;
5492 1600 : nSumSquare += nValue3 * nValue3;
5493 1600 : nSum += nValue4;
5494 1600 : nSumSquare += nValue4 * nValue4;
5495 : }
5496 414 : for (; iX < nXCheck; ++iX)
5497 : {
5498 10 : const GPtrDiff_t iOffset =
5499 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5500 10 : const GUIntBig nValue = pData[iOffset];
5501 10 : nSum += nValue;
5502 10 : nSumSquare += nValue * nValue;
5503 : }
5504 : }
5505 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5506 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5507 : }
5508 : }
5509 : else
5510 : {
5511 6531 : for (int iY = 0; iY < nYCheck; iY++)
5512 : {
5513 : int iX;
5514 1329024 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5515 : {
5516 1322620 : const GPtrDiff_t iOffset =
5517 1322620 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5518 1322620 : const GUInt32 nValue = pData[iOffset];
5519 1322620 : const GUInt32 nValue2 = pData[iOffset + 1];
5520 1322620 : if (nValue < nValue2)
5521 : {
5522 2329 : if (nValue < nMin)
5523 53 : nMin = nValue;
5524 2329 : if (nValue2 > nMax)
5525 123 : nMax = nValue2;
5526 : }
5527 : else
5528 : {
5529 1320289 : if (nValue2 < nMin)
5530 67 : nMin = nValue2;
5531 1320289 : if (nValue > nMax)
5532 219 : nMax = nValue;
5533 : }
5534 : if constexpr (COMPUTE_OTHER_STATS)
5535 : {
5536 1315560 : nSum += nValue;
5537 1315560 : nSumSquare +=
5538 1315560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5539 1315560 : nValue;
5540 1315560 : nSum += nValue2;
5541 1315560 : nSumSquare +=
5542 1315560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5543 1315560 : nValue2;
5544 : }
5545 : }
5546 6410 : if (iX < nXCheck)
5547 : {
5548 31 : const GPtrDiff_t iOffset =
5549 31 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5550 31 : const GUInt32 nValue = pData[iOffset];
5551 31 : if (nValue < nMin)
5552 19 : nMin = nValue;
5553 31 : if (nValue > nMax)
5554 22 : nMax = nValue;
5555 : if (COMPUTE_OTHER_STATS)
5556 : {
5557 19 : nSum += nValue;
5558 19 : nSumSquare +=
5559 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5560 19 : nValue;
5561 : }
5562 : }
5563 : }
5564 : if constexpr (COMPUTE_OTHER_STATS)
5565 : {
5566 62 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5567 62 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5568 : }
5569 : }
5570 301 : }
5571 : };
5572 :
5573 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5574 : // using 64bit accumulators in internal loops. This also slightly helps in
5575 : // 64bit mode.
5576 : template <bool COMPUTE_OTHER_STATS>
5577 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5578 : {
5579 13848 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5580 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5581 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5582 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5583 : {
5584 13848 : int nOuterLoops = nXCheck / 65536;
5585 13848 : if (nXCheck % 65536)
5586 13848 : nOuterLoops++;
5587 :
5588 13848 : if (bHasNoData)
5589 : {
5590 : // General case
5591 23881 : for (int iY = 0; iY < nYCheck; iY++)
5592 : {
5593 13245 : int iX = 0;
5594 26490 : for (int k = 0; k < nOuterLoops; k++)
5595 : {
5596 13245 : int iMax = iX + 65536;
5597 13245 : if (iMax > nXCheck)
5598 13245 : iMax = nXCheck;
5599 13245 : GUInt32 nSum32bit = 0;
5600 13245 : GUInt32 nSumSquare32bit = 0;
5601 13245 : GUInt32 nValidCount32bit = 0;
5602 13245 : GUInt32 nSampleCount32bit = 0;
5603 20723132 : for (; iX < iMax; iX++)
5604 : {
5605 20709887 : const GPtrDiff_t iOffset =
5606 20709887 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5607 20709887 : const GUInt32 nValue = pData[iOffset];
5608 :
5609 20709887 : nSampleCount32bit++;
5610 20709887 : if (nValue == nNoDataValue)
5611 20353620 : continue;
5612 356216 : if (nValue < nMin)
5613 401 : nMin = nValue;
5614 356216 : if (nValue > nMax)
5615 942 : nMax = nValue;
5616 : if constexpr (COMPUTE_OTHER_STATS)
5617 : {
5618 32367 : nValidCount32bit++;
5619 32367 : nSum32bit += nValue;
5620 32367 : nSumSquare32bit += nValue * nValue;
5621 : }
5622 : }
5623 : if constexpr (COMPUTE_OTHER_STATS)
5624 : {
5625 945 : nSampleCount += nSampleCount32bit;
5626 945 : nValidCount += nValidCount32bit;
5627 945 : nSum += nSum32bit;
5628 945 : nSumSquare += nSumSquare32bit;
5629 : }
5630 : }
5631 : }
5632 : }
5633 3212 : else if (nMin == 0 && nMax == 255)
5634 : {
5635 : if constexpr (COMPUTE_OTHER_STATS)
5636 : {
5637 : // Optimization when there is no nodata and we know we have already
5638 : // reached the min and max
5639 2850 : for (int iY = 0; iY < nYCheck; iY++)
5640 : {
5641 2818 : int iX = 0;
5642 5636 : for (int k = 0; k < nOuterLoops; k++)
5643 : {
5644 2818 : int iMax = iX + 65536;
5645 2818 : if (iMax > nXCheck)
5646 2818 : iMax = nXCheck;
5647 2818 : GUInt32 nSum32bit = 0;
5648 2818 : GUInt32 nSumSquare32bit = 0;
5649 177298 : for (; iX + 3 < iMax; iX += 4)
5650 : {
5651 174480 : const GPtrDiff_t iOffset =
5652 174480 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5653 174480 : const GUInt32 nValue = pData[iOffset];
5654 174480 : const GUInt32 nValue2 = pData[iOffset + 1];
5655 174480 : const GUInt32 nValue3 = pData[iOffset + 2];
5656 174480 : const GUInt32 nValue4 = pData[iOffset + 3];
5657 174480 : nSum32bit += nValue;
5658 174480 : nSumSquare32bit += nValue * nValue;
5659 174480 : nSum32bit += nValue2;
5660 174480 : nSumSquare32bit += nValue2 * nValue2;
5661 174480 : nSum32bit += nValue3;
5662 174480 : nSumSquare32bit += nValue3 * nValue3;
5663 174480 : nSum32bit += nValue4;
5664 174480 : nSumSquare32bit += nValue4 * nValue4;
5665 : }
5666 2818 : nSum += nSum32bit;
5667 2818 : nSumSquare += nSumSquare32bit;
5668 : }
5669 2824 : for (; iX < nXCheck; ++iX)
5670 : {
5671 6 : const GPtrDiff_t iOffset =
5672 6 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673 6 : const GUIntBig nValue = pData[iOffset];
5674 6 : nSum += nValue;
5675 6 : nSumSquare += nValue * nValue;
5676 : }
5677 : }
5678 32 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5679 32 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5680 32 : }
5681 : }
5682 : else
5683 : {
5684 9066 : for (int iY = 0; iY < nYCheck; iY++)
5685 : {
5686 5886 : int iX = 0;
5687 11772 : for (int k = 0; k < nOuterLoops; k++)
5688 : {
5689 5886 : int iMax = iX + 65536;
5690 5886 : if (iMax > nXCheck)
5691 5886 : iMax = nXCheck;
5692 5886 : GUInt32 nSum32bit = 0;
5693 5886 : GUInt32 nSumSquare32bit = 0;
5694 343988 : for (; iX + 1 < iMax; iX += 2)
5695 : {
5696 338102 : const GPtrDiff_t iOffset =
5697 338102 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5698 338102 : const GUInt32 nValue = pData[iOffset];
5699 338102 : const GUInt32 nValue2 = pData[iOffset + 1];
5700 338102 : if (nValue < nValue2)
5701 : {
5702 8208 : if (nValue < nMin)
5703 239 : nMin = nValue;
5704 8208 : if (nValue2 > nMax)
5705 230 : nMax = nValue2;
5706 : }
5707 : else
5708 : {
5709 329894 : if (nValue2 < nMin)
5710 367 : nMin = nValue2;
5711 329894 : if (nValue > nMax)
5712 845 : nMax = nValue;
5713 : }
5714 : if constexpr (COMPUTE_OTHER_STATS)
5715 : {
5716 315746 : nSum32bit += nValue;
5717 315746 : nSumSquare32bit += nValue * nValue;
5718 315746 : nSum32bit += nValue2;
5719 315746 : nSumSquare32bit += nValue2 * nValue2;
5720 : }
5721 : }
5722 : if constexpr (COMPUTE_OTHER_STATS)
5723 : {
5724 2670 : nSum += nSum32bit;
5725 2670 : nSumSquare += nSumSquare32bit;
5726 : }
5727 : }
5728 5886 : if (iX < nXCheck)
5729 : {
5730 1541 : const GPtrDiff_t iOffset =
5731 1541 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5732 1541 : const GUInt32 nValue = pData[iOffset];
5733 1541 : if (nValue < nMin)
5734 117 : nMin = nValue;
5735 1541 : if (nValue > nMax)
5736 103 : nMax = nValue;
5737 : if constexpr (COMPUTE_OTHER_STATS)
5738 : {
5739 321 : nSum += nValue;
5740 321 : nSumSquare +=
5741 321 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5742 321 : nValue;
5743 : }
5744 : }
5745 : }
5746 : if constexpr (COMPUTE_OTHER_STATS)
5747 : {
5748 958 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5749 958 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5750 : }
5751 : }
5752 13848 : }
5753 : };
5754 :
5755 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5756 : {
5757 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5758 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5759 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5760 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5761 : {
5762 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5763 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5764 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5765 : }
5766 : };
5767 :
5768 : constexpr int ALIGNMENT_AVX2_OPTIM = 32;
5769 :
5770 : #if (defined(__x86_64__) || defined(_M_X64) || \
5771 : defined(USE_NEON_OPTIMIZATIONS)) && \
5772 : (defined(__GNUC__) || defined(_MSC_VER))
5773 :
5774 : #include "gdal_avx2_emulation.hpp"
5775 :
5776 : #define ZERO256 GDALmm256_setzero_si256()
5777 :
5778 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5779 : static void
5780 21355 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5781 : // assumed to be aligned on 256 bits
5782 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5783 : GUIntBig &nSum, GUIntBig &nSumSquare,
5784 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5785 : {
5786 : // 32-byte alignment may not be enforced by linker, so do it at hand
5787 : GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
5788 : ALIGNMENT_AVX2_OPTIM +
5789 : (COMPUTE_OTHER_STATS
5790 : ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
5791 : : 0)];
5792 21355 : GByte *paby32ByteAligned =
5793 : aby32ByteUnaligned +
5794 21355 : (ALIGNMENT_AVX2_OPTIM -
5795 21355 : (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
5796 : ALIGNMENT_AVX2_OPTIM));
5797 21355 : GByte *pabyMin = paby32ByteAligned;
5798 21355 : GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
5799 21355 : GUInt32 *panSum = COMPUTE_OTHER_STATS
5800 : ? reinterpret_cast<GUInt32 *>(
5801 : paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
5802 : : nullptr;
5803 21355 : GUInt32 *panSumSquare =
5804 : COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
5805 : paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
5806 : : nullptr;
5807 :
5808 21355 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
5809 :
5810 21355 : GPtrDiff_t i = 0;
5811 : // Make sure that sumSquare can fit on uint32
5812 : // * 8 since we can hold 8 sums per vector register
5813 21355 : const int nMaxIterationsPerInnerLoop =
5814 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5815 21355 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5816 21355 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5817 21355 : nOuterLoops++;
5818 :
5819 : GDALm256i ymm_min =
5820 21355 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5821 21355 : GDALm256i ymm_max = ymm_min;
5822 21355 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5823 :
5824 42710 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5825 : {
5826 21355 : const auto iMax =
5827 21355 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5828 :
5829 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5830 21355 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5831 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5832 21355 : ZERO256; // holds 8 uint32 sums
5833 752431 : for (; i + 31 < iMax; i += 32)
5834 : {
5835 731076 : const GDALm256i ymm = GDALmm256_load_si256(
5836 731076 : reinterpret_cast<const GDALm256i *>(pData + i));
5837 : if (COMPUTE_MIN)
5838 : {
5839 270967 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5840 : }
5841 : if (COMPUTE_MAX)
5842 : {
5843 635873 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5844 : }
5845 :
5846 : if constexpr (COMPUTE_OTHER_STATS)
5847 : {
5848 : // Extract even-8bit values
5849 : const GDALm256i ymm_even =
5850 531792 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5851 : // Compute square of those 16 values as 32 bit result
5852 : // and add adjacent pairs
5853 : const GDALm256i ymm_even_square =
5854 531792 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5855 : // Add to the sumsquare accumulator
5856 : ymm_sumsquare =
5857 531792 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5858 :
5859 : // Extract odd-8bit values
5860 531792 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5861 : const GDALm256i ymm_odd_square =
5862 531792 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5863 : ymm_sumsquare =
5864 531792 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5865 :
5866 : // Now compute the sums
5867 531792 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5868 : GDALmm256_sad_epu8(ymm, ZERO256));
5869 : }
5870 : }
5871 :
5872 : if constexpr (COMPUTE_OTHER_STATS)
5873 : {
5874 10685 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5875 : ymm_sum);
5876 10685 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5877 : ymm_sumsquare);
5878 :
5879 10685 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5880 10685 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5881 10685 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5882 10685 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5883 : panSumSquare[7];
5884 : }
5885 : }
5886 :
5887 : if constexpr (COMPUTE_MIN)
5888 : {
5889 8458 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5890 : }
5891 : if constexpr (COMPUTE_MAX)
5892 : {
5893 17341 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5894 : }
5895 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5896 : {
5897 589578 : for (int j = 0; j < 32; j++)
5898 : {
5899 : if constexpr (COMPUTE_MIN)
5900 : {
5901 270656 : if (pabyMin[j] < nMin)
5902 1244 : nMin = pabyMin[j];
5903 : }
5904 : if constexpr (COMPUTE_MAX)
5905 : {
5906 554912 : if (pabyMax[j] > nMax)
5907 1806 : nMax = pabyMax[j];
5908 : }
5909 : }
5910 : }
5911 :
5912 234373 : for (; i < nBlockPixels; i++)
5913 : {
5914 213018 : const GUInt32 nValue = pData[i];
5915 : if constexpr (COMPUTE_MIN)
5916 : {
5917 88342 : if (nValue < nMin)
5918 2 : nMin = nValue;
5919 : }
5920 : if constexpr (COMPUTE_MAX)
5921 : {
5922 210243 : if (nValue > nMax)
5923 1150 : nMax = nValue;
5924 : }
5925 : if constexpr (COMPUTE_OTHER_STATS)
5926 : {
5927 77203 : nSum += nValue;
5928 77203 : nSumSquare +=
5929 77203 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5930 : }
5931 : }
5932 :
5933 : if constexpr (COMPUTE_OTHER_STATS)
5934 : {
5935 10685 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5936 10685 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5937 : }
5938 21355 : }
5939 :
5940 : // SSE2/AVX2 optimization for GByte case
5941 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5942 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5943 : // there are strictly equivalent to 2 parallel SSE2 streams.
5944 : template <bool COMPUTE_OTHER_STATS>
5945 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5946 : {
5947 30372 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5948 : // assumed to be aligned on 256 bits
5949 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5950 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5951 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5952 : GUIntBig &nValidCount)
5953 : {
5954 30372 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5955 30372 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5956 11610 : nMin <= nMax)
5957 : {
5958 : // 32-byte alignment may not be enforced by linker, so do it at hand
5959 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5960 1492 : GByte *paby32ByteAligned =
5961 : aby32ByteUnaligned +
5962 1492 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5963 1492 : GByte *pabyMin = paby32ByteAligned;
5964 1492 : GByte *pabyMax = paby32ByteAligned + 32;
5965 1492 : GUInt32 *panSum =
5966 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5967 1492 : GUInt32 *panSumSquare =
5968 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5969 :
5970 1492 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5971 :
5972 1492 : GPtrDiff_t i = 0;
5973 : // Make sure that sumSquare can fit on uint32
5974 : // * 8 since we can hold 8 sums per vector register
5975 1492 : const int nMaxIterationsPerInnerLoop =
5976 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5977 1492 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5978 1492 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5979 1492 : nOuterLoops++;
5980 :
5981 : const GDALm256i ymm_nodata =
5982 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5983 : // any non noData value in [min,max] would do.
5984 : const GDALm256i ymm_neutral =
5985 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5986 1492 : GDALm256i ymm_min = ymm_neutral;
5987 1492 : GDALm256i ymm_max = ymm_neutral;
5988 : [[maybe_unused]] const auto ymm_mask_8bits =
5989 1492 : GDALmm256_set1_epi16(0xFF);
5990 :
5991 1492 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5992 1492 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5993 1492 : const bool bComputeMinMax =
5994 1492 : nMin > nMinThreshold || nMax < nMaxThreshold;
5995 :
5996 2984 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5997 : {
5998 1492 : const auto iMax =
5999 1492 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6000 :
6001 : // holds 4 uint32 sums in [0], [2], [4] and [6]
6002 1492 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
6003 : // holds 8 uint32 sums
6004 1492 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
6005 : // holds 4 uint32 sums in [0], [2], [4] and [6]
6006 1492 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
6007 1492 : const auto iInit = i;
6008 18982 : for (; i + 31 < iMax; i += 32)
6009 : {
6010 17490 : const GDALm256i ymm = GDALmm256_load_si256(
6011 17490 : reinterpret_cast<const GDALm256i *>(pData + i));
6012 :
6013 : // Check which values are nodata
6014 : const GDALm256i ymm_eq_nodata =
6015 17490 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6016 : if constexpr (COMPUTE_OTHER_STATS)
6017 : {
6018 : // Count how many values are nodata (due to cmpeq
6019 : // putting 255 when condition is met, this will actually
6020 : // be 255 times the number of nodata value, spread in 4
6021 : // 64 bits words). We can use add_epi32 as the counter
6022 : // will not overflow uint32
6023 9148 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6024 : ymm_count_nodata_mul_255,
6025 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6026 : }
6027 : // Replace all nodata values by zero for the purpose of sum
6028 : // and sumquare.
6029 : const GDALm256i ymm_nodata_by_zero =
6030 17490 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6031 17490 : if (bComputeMinMax)
6032 : {
6033 : // Replace all nodata values by a neutral value for the
6034 : // purpose of min and max.
6035 : const GDALm256i ymm_nodata_by_neutral =
6036 8720 : GDALmm256_or_si256(
6037 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6038 : ymm_nodata_by_zero);
6039 :
6040 : ymm_min =
6041 8720 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6042 : ymm_max =
6043 8720 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6044 : }
6045 :
6046 : if constexpr (COMPUTE_OTHER_STATS)
6047 : {
6048 : // Extract even-8bit values
6049 9148 : const GDALm256i ymm_even = GDALmm256_and_si256(
6050 : ymm_nodata_by_zero, ymm_mask_8bits);
6051 : // Compute square of those 16 values as 32 bit result
6052 : // and add adjacent pairs
6053 : const GDALm256i ymm_even_square =
6054 9148 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6055 : // Add to the sumsquare accumulator
6056 : ymm_sumsquare =
6057 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6058 :
6059 : // Extract odd-8bit values
6060 : const GDALm256i ymm_odd =
6061 9148 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6062 : const GDALm256i ymm_odd_square =
6063 9148 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6064 : ymm_sumsquare =
6065 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6066 :
6067 : // Now compute the sums
6068 9148 : ymm_sum = GDALmm256_add_epi32(
6069 : ymm_sum,
6070 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6071 : }
6072 : }
6073 :
6074 : if constexpr (COMPUTE_OTHER_STATS)
6075 : {
6076 186 : GUInt32 *panCoutNoDataMul255 = panSum;
6077 186 : GDALmm256_store_si256(
6078 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6079 : ymm_count_nodata_mul_255);
6080 :
6081 186 : nSampleCount += (i - iInit);
6082 :
6083 186 : nValidCount +=
6084 186 : (i - iInit) -
6085 186 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6086 186 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6087 : 255;
6088 :
6089 186 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6090 : ymm_sum);
6091 186 : GDALmm256_store_si256(
6092 : reinterpret_cast<GDALm256i *>(panSumSquare),
6093 : ymm_sumsquare);
6094 186 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6095 186 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6096 186 : panSumSquare[1] + panSumSquare[2] +
6097 186 : panSumSquare[3] + panSumSquare[4] +
6098 186 : panSumSquare[5] + panSumSquare[6] +
6099 : panSumSquare[7];
6100 : }
6101 : }
6102 :
6103 1492 : if (bComputeMinMax)
6104 : {
6105 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6106 : ymm_min);
6107 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6108 : ymm_max);
6109 47190 : for (int j = 0; j < 32; j++)
6110 : {
6111 45760 : if (pabyMin[j] < nMin)
6112 40 : nMin = pabyMin[j];
6113 45760 : if (pabyMax[j] > nMax)
6114 161 : nMax = pabyMax[j];
6115 : }
6116 : }
6117 :
6118 : if constexpr (COMPUTE_OTHER_STATS)
6119 : {
6120 186 : nSampleCount += nBlockPixels - i;
6121 : }
6122 34048 : for (; i < nBlockPixels; i++)
6123 : {
6124 32556 : const GUInt32 nValue = pData[i];
6125 32556 : if (nValue == nNoDataValue)
6126 24923 : continue;
6127 7633 : if (nValue < nMin)
6128 2 : nMin = nValue;
6129 7633 : if (nValue > nMax)
6130 14 : nMax = nValue;
6131 : if constexpr (COMPUTE_OTHER_STATS)
6132 : {
6133 3700 : nValidCount++;
6134 3700 : nSum += nValue;
6135 3700 : nSumSquare +=
6136 3700 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6137 3700 : nValue;
6138 : }
6139 1492 : }
6140 : }
6141 28880 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6142 : {
6143 14999 : if (nMin > 0)
6144 : {
6145 2102 : if (nMax < 255)
6146 : {
6147 : ComputeStatisticsByteNoNodata<true, true,
6148 1577 : COMPUTE_OTHER_STATS>(
6149 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6150 : nSampleCount, nValidCount);
6151 : }
6152 : else
6153 : {
6154 : ComputeStatisticsByteNoNodata<true, false,
6155 525 : COMPUTE_OTHER_STATS>(
6156 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6157 : nSampleCount, nValidCount);
6158 : }
6159 : }
6160 : else
6161 : {
6162 12897 : if (nMax < 255)
6163 : {
6164 : ComputeStatisticsByteNoNodata<false, true,
6165 9408 : COMPUTE_OTHER_STATS>(
6166 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6167 : nSampleCount, nValidCount);
6168 : }
6169 : else
6170 : {
6171 : ComputeStatisticsByteNoNodata<false, false,
6172 3489 : COMPUTE_OTHER_STATS>(
6173 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6174 : nSampleCount, nValidCount);
6175 : }
6176 : }
6177 : }
6178 12561 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6179 33 : (nBlockXSize % 32) == 0)
6180 : {
6181 6389 : for (int iY = 0; iY < nYCheck; iY++)
6182 : {
6183 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6184 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6185 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6186 33 : }
6187 : }
6188 : else
6189 : {
6190 13848 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6191 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6192 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6193 : }
6194 30372 : }
6195 : };
6196 :
6197 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6198 578 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6199 : GUIntBig i)
6200 : {
6201 578 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6202 578 : }
6203 :
6204 : // AVX2/SSE2 optimization for GUInt16 case
6205 : template <bool COMPUTE_OTHER_STATS>
6206 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6207 : {
6208 2153 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6209 : // assumed to be aligned on 128 bits
6210 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6211 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6212 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6213 : GUIntBig &nValidCount)
6214 : {
6215 2153 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6216 2153 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6217 : {
6218 1852 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6219 :
6220 1852 : GPtrDiff_t i = 0;
6221 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6222 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6223 : // Furthermore the shift is also needed to use madd_epi16
6224 1852 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6225 1852 : GDALm256i ymm_min = GDALmm256_load_si256(
6226 1852 : reinterpret_cast<const GDALm256i *>(pData + i));
6227 1852 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6228 1852 : GDALm256i ymm_max = ymm_min;
6229 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6230 1852 : ZERO256; // holds 4 uint64 sums
6231 :
6232 : // Make sure that sum can fit on uint32
6233 : // * 8 since we can hold 8 sums per vector register
6234 1852 : const int nMaxIterationsPerInnerLoop =
6235 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6236 1852 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6237 1852 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6238 1852 : nOuterLoops++;
6239 :
6240 1852 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6241 : [[maybe_unused]] const auto ymm_mask_16bits =
6242 1852 : GDALmm256_set1_epi32(0xFFFF);
6243 : [[maybe_unused]] const auto ymm_mask_32bits =
6244 1852 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6245 :
6246 1852 : GUIntBig nSumThis = 0;
6247 3728 : for (int k = 0; k < nOuterLoops; k++)
6248 : {
6249 1876 : const auto iMax =
6250 1876 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6251 :
6252 : [[maybe_unused]] GDALm256i ymm_sum =
6253 1876 : ZERO256; // holds 8 uint32 sums
6254 1112456 : for (; i + 15 < iMax; i += 16)
6255 : {
6256 1110580 : const GDALm256i ymm = GDALmm256_load_si256(
6257 1110580 : reinterpret_cast<const GDALm256i *>(pData + i));
6258 : const GDALm256i ymm_shifted =
6259 1110580 : GDALmm256_add_epi16(ymm, ymm_m32768);
6260 1110580 : if (bComputeMinMax)
6261 : {
6262 1092542 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6263 1092542 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6264 : }
6265 :
6266 : if constexpr (COMPUTE_OTHER_STATS)
6267 : {
6268 : // Note: the int32 range can overflow for (0-32768)^2 +
6269 : // (0-32768)^2 = 0x80000000, but as we know the result
6270 : // is positive, this is OK as we interpret is a uint32.
6271 : const GDALm256i ymm_square =
6272 243562 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6273 243562 : ymm_sumsquare = GDALmm256_add_epi64(
6274 : ymm_sumsquare,
6275 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6276 243562 : ymm_sumsquare = GDALmm256_add_epi64(
6277 : ymm_sumsquare,
6278 : GDALmm256_srli_epi64(ymm_square, 32));
6279 :
6280 : // Now compute the sums
6281 243562 : ymm_sum = GDALmm256_add_epi32(
6282 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6283 243562 : ymm_sum = GDALmm256_add_epi32(
6284 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6285 : }
6286 : }
6287 :
6288 : if constexpr (COMPUTE_OTHER_STATS)
6289 : {
6290 : GUInt32 anSum[8];
6291 578 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6292 : ymm_sum);
6293 578 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6294 578 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6295 578 : anSum[6] + anSum[7];
6296 : }
6297 : }
6298 :
6299 1852 : if (bComputeMinMax)
6300 : {
6301 : GUInt16 anMin[16];
6302 : GUInt16 anMax[16];
6303 :
6304 : // Unshift the result
6305 1770 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6306 1770 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6307 1770 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6308 : ymm_min);
6309 1770 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6310 : ymm_max);
6311 30090 : for (int j = 0; j < 16; j++)
6312 : {
6313 28320 : if (anMin[j] < nMin)
6314 394 : nMin = anMin[j];
6315 28320 : if (anMax[j] > nMax)
6316 571 : nMax = anMax[j];
6317 : }
6318 : }
6319 :
6320 : if constexpr (COMPUTE_OTHER_STATS)
6321 : {
6322 : GUIntBig anSumSquare[4];
6323 578 : GDALmm256_storeu_si256(
6324 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6325 578 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6326 : anSumSquare[3];
6327 :
6328 : // Unshift the sum of squares
6329 578 : UnshiftSumSquare(nSumSquare, nSumThis,
6330 : static_cast<GUIntBig>(i));
6331 :
6332 578 : nSum += nSumThis;
6333 :
6334 1022 : for (; i < nBlockPixels; i++)
6335 : {
6336 444 : const GUInt32 nValue = pData[i];
6337 444 : if (nValue < nMin)
6338 2 : nMin = nValue;
6339 444 : if (nValue > nMax)
6340 2 : nMax = nValue;
6341 444 : nSum += nValue;
6342 444 : nSumSquare +=
6343 444 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6344 444 : nValue;
6345 : }
6346 :
6347 578 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6348 578 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6349 1852 : }
6350 : }
6351 : else
6352 : {
6353 301 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6354 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6355 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6356 : }
6357 2153 : }
6358 : };
6359 :
6360 : #endif
6361 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6362 : // defined(_MSC_VER))
6363 :
6364 : /************************************************************************/
6365 : /* GetPixelValue() */
6366 : /************************************************************************/
6367 :
6368 15872500 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6369 : const void *pData, GPtrDiff_t iOffset,
6370 : const GDALNoDataValues &sNoDataValues,
6371 : bool &bValid)
6372 : {
6373 15872500 : bValid = true;
6374 15872500 : double dfValue = 0;
6375 15872500 : switch (eDataType)
6376 : {
6377 1400770 : case GDT_UInt8:
6378 : {
6379 1400770 : if (bSignedByte)
6380 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6381 : else
6382 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6383 1400770 : break;
6384 : }
6385 641 : case GDT_Int8:
6386 641 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6387 641 : break;
6388 200608 : case GDT_UInt16:
6389 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6390 200608 : break;
6391 54336 : case GDT_Int16:
6392 54336 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6393 54336 : break;
6394 10478 : case GDT_UInt32:
6395 10478 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6396 10478 : break;
6397 140220 : case GDT_Int32:
6398 140220 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6399 140220 : break;
6400 60 : case GDT_UInt64:
6401 60 : dfValue = static_cast<double>(
6402 60 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6403 60 : break;
6404 3268 : case GDT_Int64:
6405 3268 : dfValue = static_cast<double>(
6406 3268 : static_cast<const std::int64_t *>(pData)[iOffset]);
6407 3268 : break;
6408 40 : case GDT_Float16:
6409 : {
6410 : using namespace std;
6411 40 : const GFloat16 hfValue =
6412 40 : static_cast<const GFloat16 *>(pData)[iOffset];
6413 74 : if (isnan(hfValue) ||
6414 34 : (sNoDataValues.bGotFloat16NoDataValue &&
6415 28 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6416 : {
6417 6 : bValid = false;
6418 6 : return 0.0;
6419 : }
6420 34 : dfValue = hfValue;
6421 34 : return dfValue;
6422 : }
6423 13644000 : case GDT_Float32:
6424 : {
6425 13644000 : const float fValue = static_cast<const float *>(pData)[iOffset];
6426 27261100 : if (std::isnan(fValue) ||
6427 26886000 : (sNoDataValues.bGotFloatNoDataValue &&
6428 13268900 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6429 : {
6430 26883 : bValid = false;
6431 26883 : return 0.0;
6432 : }
6433 13617100 : dfValue = double(fValue);
6434 13617100 : return dfValue;
6435 : }
6436 400956 : case GDT_Float64:
6437 400956 : dfValue = static_cast<const double *>(pData)[iOffset];
6438 400956 : if (std::isnan(dfValue))
6439 : {
6440 6 : bValid = false;
6441 6 : return 0.0;
6442 : }
6443 400950 : break;
6444 2692 : case GDT_CInt16:
6445 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6446 2692 : break;
6447 2692 : case GDT_CInt32:
6448 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6449 2692 : break;
6450 0 : case GDT_CFloat16:
6451 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6452 0 : if (std::isnan(dfValue))
6453 : {
6454 0 : bValid = false;
6455 0 : return 0.0;
6456 : }
6457 0 : break;
6458 5812 : case GDT_CFloat32:
6459 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6460 5812 : if (std::isnan(dfValue))
6461 : {
6462 0 : bValid = false;
6463 0 : return 0.0;
6464 : }
6465 5812 : break;
6466 5892 : case GDT_CFloat64:
6467 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6468 5892 : if (std::isnan(dfValue))
6469 : {
6470 0 : bValid = false;
6471 0 : return 0.0;
6472 : }
6473 5892 : break;
6474 0 : case GDT_Unknown:
6475 : case GDT_TypeCount:
6476 0 : CPLAssert(false);
6477 : break;
6478 : }
6479 :
6480 2483820 : if (sNoDataValues.bGotNoDataValue &&
6481 255405 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6482 : {
6483 4222 : bValid = false;
6484 4222 : return 0.0;
6485 : }
6486 2224190 : return dfValue;
6487 : }
6488 :
6489 : /************************************************************************/
6490 : /* SetValidPercent() */
6491 : /************************************************************************/
6492 :
6493 : //! @cond Doxygen_Suppress
6494 : /**
6495 : * \brief Set percentage of valid (not nodata) pixels.
6496 : *
6497 : * Stores the percentage of valid pixels in the metadata item
6498 : * STATISTICS_VALID_PERCENT
6499 : *
6500 : * @param nSampleCount Number of sampled pixels.
6501 : *
6502 : * @param nValidCount Number of valid pixels.
6503 : */
6504 :
6505 600 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6506 : GUIntBig nValidCount)
6507 : {
6508 600 : if (nValidCount == 0)
6509 : {
6510 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6511 : }
6512 588 : else if (nValidCount == nSampleCount)
6513 : {
6514 495 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6515 : }
6516 : else /* nValidCount < nSampleCount */
6517 : {
6518 93 : char szValue[128] = {0};
6519 :
6520 : /* percentage is only an indicator: limit precision */
6521 93 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6522 93 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6523 :
6524 93 : if (EQUAL(szValue, "100"))
6525 : {
6526 : /* don't set 100 percent valid
6527 : * because some of the sampled pixels were nodata */
6528 4 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6529 : }
6530 : else
6531 : {
6532 89 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6533 : }
6534 : }
6535 600 : }
6536 :
6537 : //! @endcond
6538 :
6539 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6540 :
6541 : #ifdef __AVX2__
6542 :
6543 : #define set1_ps _mm256_set1_ps
6544 : #define loadu_ps _mm256_loadu_ps
6545 : #define or_ps _mm256_or_ps
6546 : #define min_ps _mm256_min_ps
6547 : #define max_ps _mm256_max_ps
6548 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6549 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6550 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6551 : #define movemask_ps _mm256_movemask_ps
6552 : #define storeu_ps _mm256_storeu_ps
6553 : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6554 : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6555 :
6556 : #define unpacklo_ps _mm256_unpacklo_ps
6557 : #define castps_pd _mm256_castps_pd
6558 :
6559 : inline __m256 dup_hi_ps(__m256 x)
6560 : {
6561 : const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6562 : return _mm256_permutevar8x32_ps(x, idx);
6563 : }
6564 :
6565 : #define setzero_pd _mm256_setzero_pd
6566 : #define set1_pd _mm256_set1_pd
6567 : #define loadu_pd _mm256_loadu_pd
6568 : #define or_pd _mm256_or_pd
6569 : #define min_pd _mm256_min_pd
6570 : #define max_pd _mm256_max_pd
6571 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6572 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6573 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6574 : #define movemask_pd _mm256_movemask_pd
6575 : #define add_pd _mm256_add_pd
6576 : #define sub_pd _mm256_sub_pd
6577 : #define mul_pd _mm256_mul_pd
6578 : #define div_pd _mm256_div_pd
6579 : #define storeu_pd _mm256_storeu_pd
6580 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6581 : #define blendv_pd _mm256_blendv_pd
6582 : #ifdef __FMA__
6583 : #define fmadd_pd _mm256_fmadd_pd
6584 : #else
6585 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6586 : #endif
6587 :
6588 : #else
6589 :
6590 : #define set1_ps _mm_set1_ps
6591 : #define loadu_ps _mm_loadu_ps
6592 : #define or_ps _mm_or_ps
6593 : #define min_ps _mm_min_ps
6594 : #define max_ps _mm_max_ps
6595 : #define cmpeq_ps _mm_cmpeq_ps
6596 : #define cmpneq_ps _mm_cmpneq_ps
6597 : #define cmpunord_ps _mm_cmpunord_ps
6598 : #define movemask_ps _mm_movemask_ps
6599 : #define storeu_ps _mm_storeu_ps
6600 : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6601 : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6602 : #define unpacklo_ps _mm_unpacklo_ps
6603 : #define castps_pd _mm_castps_pd
6604 : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6605 :
6606 : #define setzero_pd _mm_setzero_pd
6607 : #define set1_pd _mm_set1_pd
6608 : #define loadu_pd _mm_loadu_pd
6609 : #define or_pd _mm_or_pd
6610 : #define min_pd _mm_min_pd
6611 : #define max_pd _mm_max_pd
6612 : #define cmpeq_pd _mm_cmpeq_pd
6613 : #define cmpneq_pd _mm_cmpneq_pd
6614 : #define cmpunord_pd _mm_cmpunord_pd
6615 : #define movemask_pd _mm_movemask_pd
6616 : #define add_pd _mm_add_pd
6617 : #define sub_pd _mm_sub_pd
6618 : #define mul_pd _mm_mul_pd
6619 : #define div_pd _mm_div_pd
6620 : #define storeu_pd _mm_storeu_pd
6621 : #define cvtsd_f64 _mm_cvtsd_f64
6622 : #ifdef __FMA__
6623 : #define fmadd_pd _mm_fmadd_pd
6624 : #else
6625 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6626 : #endif
6627 :
6628 4299340 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6629 : {
6630 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6631 : return _mm_blendv_pd(a, b, mask);
6632 : #else
6633 12898000 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6634 : #endif
6635 : }
6636 : #endif
6637 :
6638 : #define dup_lo_ps(x) unpacklo_ps((x), (x))
6639 :
6640 : /************************************************************************/
6641 : /* ComputeStatisticsFloat32_SSE2() */
6642 : /************************************************************************/
6643 :
6644 : template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6645 : #if defined(__GNUC__)
6646 : __attribute__((noinline))
6647 : #endif
6648 8326 : static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
6649 : [[maybe_unused]] float fNoDataValue,
6650 : int iX, int nCount, float &fMin,
6651 : float &fMax, double &dfBlockMean,
6652 : double &dfBlockM2,
6653 : double &dfBlockValidCount)
6654 : {
6655 8326 : auto vValidCount = setzero_pd();
6656 8326 : const auto vOne = set1_pd(1);
6657 8326 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6658 :
6659 8326 : auto vMin = set1_ps(fMin);
6660 16652 : auto vMax = set1_ps(fMax);
6661 :
6662 8326 : auto vMean_lo = setzero_pd();
6663 8326 : auto vM2_lo = setzero_pd();
6664 :
6665 8326 : auto vMean_hi = setzero_pd();
6666 8326 : auto vM2_hi = setzero_pd();
6667 :
6668 8326 : constexpr int VALS_PER_LOOP =
6669 : static_cast<int>(sizeof(vOne) / sizeof(float));
6670 1258075 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6671 : {
6672 2499510 : const auto vValues = loadu_ps(pafData + iX);
6673 :
6674 : if constexpr (HAS_NAN)
6675 : {
6676 1236117 : auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6677 : if constexpr (HAS_NODATA)
6678 : {
6679 : isNaNOrNoData =
6680 0 : or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6681 : }
6682 1236117 : if (movemask_ps(isNaNOrNoData))
6683 : {
6684 1 : break;
6685 : }
6686 : }
6687 : else if constexpr (HAS_NODATA)
6688 : {
6689 0 : if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6690 : {
6691 0 : break;
6692 : }
6693 : }
6694 :
6695 1249754 : vMin = min_ps(vMin, vValues);
6696 1249754 : vMax = max_ps(vMax, vValues);
6697 :
6698 1249754 : const auto vValues_lo = cvtps_lo_pd(vValues);
6699 2499508 : const auto vValues_hi = cvtps_hi_pd(vValues);
6700 1249754 : [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6701 :
6702 1249754 : vValidCount = add_pd(vValidCount, vOne);
6703 1249754 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6704 :
6705 1249754 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6706 2298362 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6707 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6708 : {
6709 : const auto vMinNotSameAsMax_lo =
6710 1048608 : castps_pd(dup_lo_ps(vMinNotSameAsMax));
6711 1048608 : vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6712 : const auto vNewM2_lo =
6713 2097216 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6714 1048608 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6715 : }
6716 : else
6717 : {
6718 201146 : vMean_lo = vNewMean_lo;
6719 603438 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6720 : }
6721 :
6722 1249754 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6723 2298362 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6724 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6725 : {
6726 : const auto vMinNotSameAsMax_hi =
6727 1048608 : castps_pd(dup_hi_ps(vMinNotSameAsMax));
6728 1048608 : vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6729 : const auto vNewM2_hi =
6730 2097216 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6731 1048608 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6732 : }
6733 : else
6734 : {
6735 201146 : vMean_hi = vNewMean_hi;
6736 603438 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6737 : }
6738 : }
6739 8326 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6740 8326 : if (dfValidVectorCount > 0)
6741 : {
6742 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6743 : storeu_ps(afMin, vMin);
6744 : storeu_ps(afMax, vMax);
6745 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6746 : {
6747 31964 : fMin = std::min(fMin, afMin[i]);
6748 31964 : fMax = std::max(fMax, afMax[i]);
6749 : }
6750 :
6751 : double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6752 : storeu_pd(adfMean, vMean_lo);
6753 : storeu_pd(adfM2, vM2_lo);
6754 7991 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6755 7991 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6756 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6757 : {
6758 31964 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6759 31964 : dfBlockM2 += adfM2[i];
6760 31964 : if (adfMean[i] != dfBlockMean)
6761 : {
6762 13172 : const double dfDelta = adfMean[i] - dfBlockMean;
6763 13172 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6764 13172 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6765 13172 : dfValidVectorCount / dfNewValidCount;
6766 : }
6767 31964 : dfBlockValidCount = dfNewValidCount;
6768 : }
6769 : }
6770 :
6771 8326 : return iX;
6772 : }
6773 :
6774 : /************************************************************************/
6775 : /* ComputeStatisticsFloat64_SSE2() */
6776 : /************************************************************************/
6777 :
6778 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6779 : #if defined(__GNUC__)
6780 : __attribute__((noinline))
6781 : #endif
6782 2367 : static int ComputeStatisticsFloat64_SSE2(const double *padfData,
6783 : [[maybe_unused]] double dfNoDataValue,
6784 : int iX, int nCount, double &dfMin,
6785 : double &dfMax, double &dfBlockMean,
6786 : double &dfBlockM2,
6787 : double &dfBlockValidCount)
6788 : {
6789 2367 : auto vValidCount = setzero_pd();
6790 2367 : const auto vOne = set1_pd(1);
6791 2367 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6792 :
6793 2367 : auto vMin_lo = set1_pd(dfMin);
6794 4734 : auto vMax_lo = set1_pd(dfMax);
6795 2367 : auto vMean_lo = setzero_pd();
6796 2367 : auto vM2_lo = setzero_pd();
6797 :
6798 2367 : auto vMin_hi = vMin_lo;
6799 2367 : auto vMax_hi = vMax_lo;
6800 2367 : auto vMean_hi = setzero_pd();
6801 2367 : auto vM2_hi = setzero_pd();
6802 :
6803 2367 : constexpr int VALS_PER_LOOP =
6804 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6805 107199 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6806 : {
6807 104875 : const auto vValues_lo = loadu_pd(padfData + iX);
6808 209750 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6809 : // Check if there's at least one NaN in both vectors
6810 104875 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6811 : if constexpr (HAS_NODATA)
6812 : {
6813 : isNaNOrNoData =
6814 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6815 : cmpeq_pd(vValues_hi, vNoData)));
6816 : }
6817 104875 : if (movemask_pd(isNaNOrNoData))
6818 : {
6819 43 : break;
6820 : }
6821 :
6822 104832 : vValidCount = add_pd(vValidCount, vOne);
6823 104832 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6824 :
6825 104832 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6826 104832 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6827 104832 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6828 131060 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6829 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6830 : {
6831 26228 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6832 26228 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6833 : const auto vNewM2_lo =
6834 52456 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6835 26228 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6836 : }
6837 : else
6838 : {
6839 78604 : vMean_lo = vNewMean_lo;
6840 235812 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6841 : }
6842 :
6843 104832 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6844 104832 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6845 104832 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6846 131060 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6847 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6848 : {
6849 26228 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6850 26228 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6851 : const auto vNewM2_hi =
6852 52456 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6853 26228 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6854 : }
6855 : else
6856 : {
6857 78604 : vMean_hi = vNewMean_hi;
6858 235812 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6859 : }
6860 : }
6861 2367 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6862 2367 : if (dfValidVectorCount > 0)
6863 : {
6864 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6865 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6866 : storeu_pd(adfMin, vMin_lo);
6867 : storeu_pd(adfMax, vMax_lo);
6868 : storeu_pd(adfMean, vMean_lo);
6869 : storeu_pd(adfM2, vM2_lo);
6870 1801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6871 1801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6872 1801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6873 1801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6874 :
6875 9005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6876 : {
6877 7204 : dfMin = std::min(dfMin, adfMin[i]);
6878 7204 : dfMax = std::max(dfMax, adfMax[i]);
6879 7204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6880 7204 : dfBlockM2 += adfM2[i];
6881 7204 : if (adfMean[i] != dfBlockMean)
6882 : {
6883 5871 : const double dfDelta = adfMean[i] - dfBlockMean;
6884 5871 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6885 5871 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6886 5871 : dfValidVectorCount / dfNewValidCount;
6887 : }
6888 7204 : dfBlockValidCount = dfNewValidCount;
6889 : }
6890 : }
6891 :
6892 2367 : return iX;
6893 : }
6894 :
6895 : #endif
6896 :
6897 : /************************************************************************/
6898 : /* ComputeBlockStatisticsFloat32() */
6899 : /************************************************************************/
6900 :
6901 : template <bool HAS_NAN, bool HAS_NODATA>
6902 4729 : static void ComputeBlockStatisticsFloat32(
6903 : const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6904 : const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6905 : float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6906 : double &dfBlockValidCountInOut)
6907 : {
6908 4729 : float fMin = fMinInOut;
6909 4729 : float fMax = fMaxInOut;
6910 4729 : double dfBlockMean = dfBlockMeanInOut;
6911 4729 : double dfBlockM2 = dfBlockM2InOut;
6912 4729 : double dfBlockValidCount = dfBlockValidCountInOut;
6913 :
6914 13055 : for (int iY = 0; iY < nYCheck; iY++)
6915 : {
6916 8326 : const int iOffset = iY * nBlockXSize;
6917 8326 : if (dfBlockValidCount > 0 && fMin != fMax)
6918 : {
6919 3470 : int iX = 0;
6920 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6921 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6922 : /* bCheckMinEqMax = */ false,
6923 3470 : HAS_NODATA>(
6924 3470 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6925 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6926 : #endif
6927 4011 : for (; iX < nXCheck; iX++)
6928 : {
6929 541 : const float fValue = pafSrcData[iOffset + iX];
6930 : if constexpr (HAS_NAN)
6931 : {
6932 535 : if (std::isnan(fValue))
6933 13 : continue;
6934 : }
6935 : if constexpr (HAS_NODATA)
6936 : {
6937 6 : if (fValue == sNoDataValues.fNoDataValue)
6938 1 : continue;
6939 : }
6940 527 : fMin = std::min(fMin, fValue);
6941 527 : fMax = std::max(fMax, fValue);
6942 527 : dfBlockValidCount += 1.0;
6943 527 : const double dfValue = static_cast<double>(fValue);
6944 527 : const double dfDelta = dfValue - dfBlockMean;
6945 527 : dfBlockMean += dfDelta / dfBlockValidCount;
6946 527 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6947 3470 : }
6948 : }
6949 : else
6950 : {
6951 4856 : int iX = 0;
6952 4856 : if (dfBlockValidCount == 0)
6953 : {
6954 4730 : while (iX < nXCheck)
6955 : {
6956 4730 : const float fValue = pafSrcData[iOffset + iX];
6957 4730 : ++iX;
6958 : if constexpr (HAS_NAN)
6959 : {
6960 2338 : if (std::isnan(fValue))
6961 0 : continue;
6962 : }
6963 : if constexpr (HAS_NODATA)
6964 : {
6965 7 : if (fValue == sNoDataValues.fNoDataValue)
6966 1 : continue;
6967 : }
6968 4729 : fMin = std::min(fMin, fValue);
6969 4729 : fMax = std::max(fMax, fValue);
6970 4729 : dfBlockValidCount = 1;
6971 4729 : dfBlockMean = static_cast<double>(fValue);
6972 4729 : break;
6973 : }
6974 : }
6975 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6976 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6977 : /* bCheckMinEqMax = */ true,
6978 4856 : HAS_NODATA>(
6979 4856 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6980 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6981 : #endif
6982 14986 : for (; iX < nXCheck; iX++)
6983 : {
6984 10130 : const float fValue = pafSrcData[iOffset + iX];
6985 : if constexpr (HAS_NAN)
6986 : {
6987 6873 : if (std::isnan(fValue))
6988 5 : continue;
6989 : }
6990 : if constexpr (HAS_NODATA)
6991 : {
6992 9 : if (fValue == sNoDataValues.fNoDataValue)
6993 2 : continue;
6994 : }
6995 10123 : fMin = std::min(fMin, fValue);
6996 10123 : fMax = std::max(fMax, fValue);
6997 10123 : dfBlockValidCount += 1.0;
6998 10123 : if (fMin != fMax)
6999 : {
7000 3258 : const double dfValue = static_cast<double>(fValue);
7001 3258 : const double dfDelta = dfValue - dfBlockMean;
7002 3258 : dfBlockMean += dfDelta / dfBlockValidCount;
7003 3258 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7004 : }
7005 : }
7006 : }
7007 : }
7008 :
7009 4729 : fMinInOut = fMin;
7010 4729 : fMaxInOut = fMax;
7011 4729 : dfBlockMeanInOut = dfBlockMean;
7012 4729 : dfBlockM2InOut = dfBlockM2;
7013 4729 : dfBlockValidCountInOut = dfBlockValidCount;
7014 4729 : }
7015 :
7016 : /************************************************************************/
7017 : /* StatisticsTaskFloat32 */
7018 : /************************************************************************/
7019 :
7020 : namespace
7021 : {
7022 : struct StatisticsTaskFloat32
7023 : {
7024 : double dfBlockMean = 0;
7025 : double dfBlockM2 = 0;
7026 : double dfBlockValidCount = 0;
7027 : GDALDataType eDataType = GDT_Unknown;
7028 : bool bHasNoData = false;
7029 : GDALNoDataValues *psNoDataValues = nullptr;
7030 : const float *pafSrcData = nullptr;
7031 : float fMin = std::numeric_limits<float>::infinity();
7032 : float fMax = -std::numeric_limits<float>::infinity();
7033 : int nChunkXSize = 0;
7034 : int nXCheck = 0;
7035 : int nYCheck = 0;
7036 :
7037 4729 : void Perform()
7038 : {
7039 4729 : if (GDALDataTypeIsInteger(eDataType))
7040 : {
7041 2391 : if (bHasNoData)
7042 : {
7043 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7044 6 : /* HAS_NODATA = */ true>(
7045 6 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7046 6 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7047 : }
7048 : else
7049 : {
7050 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7051 2385 : /* HAS_NODATA = */ false>(
7052 2385 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7053 2385 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7054 : }
7055 : }
7056 : else
7057 : {
7058 2338 : if (bHasNoData)
7059 : {
7060 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7061 0 : /* HAS_NODATA = */ true>(
7062 0 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7063 0 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7064 : }
7065 : else
7066 : {
7067 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7068 2338 : /* HAS_NODATA = */ false>(
7069 2338 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7070 2338 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7071 : }
7072 : }
7073 4729 : }
7074 : };
7075 : } // namespace
7076 :
7077 : /************************************************************************/
7078 : /* ComputeStatistics() */
7079 : /************************************************************************/
7080 :
7081 : /**
7082 : * \brief Compute image statistics.
7083 : *
7084 : * Returns the minimum, maximum, mean and standard deviation of all
7085 : * pixel values in this band. If approximate statistics are sufficient,
7086 : * the bApproxOK flag can be set to true in which case overviews, or a
7087 : * subset of image tiles may be used in computing the statistics.
7088 : *
7089 : * Once computed, the statistics will generally be "set" back on the
7090 : * raster band using SetStatistics().
7091 : *
7092 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7093 : *
7094 : * This method is the same as the C function GDALComputeRasterStatistics().
7095 : *
7096 : * @param bApproxOK If TRUE statistics may be computed based on overviews
7097 : * or a subset of all tiles.
7098 : *
7099 : * @param pdfMin Location into which to load image minimum (may be NULL).
7100 : *
7101 : * @param pdfMax Location into which to load image maximum (may be NULL).-
7102 : *
7103 : * @param pdfMean Location into which to load image mean (may be NULL).
7104 : *
7105 : * @param pdfStdDev Location into which to load image standard deviation
7106 : * (may be NULL).
7107 : *
7108 : * @param pfnProgress a function to call to report progress, or NULL.
7109 : *
7110 : * @param pProgressData application data to pass to the progress function.
7111 : *
7112 : * @return CE_None on success, or CE_Failure if an error occurs or processing
7113 : * is terminated by the user.
7114 : */
7115 :
7116 582 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7117 : double *pdfMax, double *pdfMean,
7118 : double *pdfStdDev,
7119 : GDALProgressFunc pfnProgress,
7120 : void *pProgressData)
7121 :
7122 : {
7123 582 : if (pfnProgress == nullptr)
7124 252 : pfnProgress = GDALDummyProgress;
7125 :
7126 : /* -------------------------------------------------------------------- */
7127 : /* If we have overview bands, use them for statistics. */
7128 : /* -------------------------------------------------------------------- */
7129 582 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7130 : {
7131 : GDALRasterBand *poBand =
7132 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7133 :
7134 3 : if (poBand != this)
7135 : {
7136 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
7137 : pdfMean, pdfStdDev,
7138 3 : pfnProgress, pProgressData);
7139 3 : if (eErr == CE_None)
7140 : {
7141 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7142 : {
7143 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7144 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7145 : }
7146 :
7147 : /* transfer metadata from overview band to this */
7148 : const char *pszPercentValid =
7149 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7150 :
7151 3 : if (pszPercentValid != nullptr)
7152 : {
7153 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
7154 3 : pszPercentValid);
7155 : }
7156 : }
7157 3 : return eErr;
7158 : }
7159 : }
7160 :
7161 579 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7162 : {
7163 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7164 0 : return CE_Failure;
7165 : }
7166 :
7167 : /* -------------------------------------------------------------------- */
7168 : /* Read actual data and compute statistics. */
7169 : /* -------------------------------------------------------------------- */
7170 : // Using Welford algorithm:
7171 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7172 : // to compute standard deviation in a more numerically robust way than
7173 : // the difference of the sum of square values with the square of the sum.
7174 : // dfMean and dfM2 are updated at each sample.
7175 : // dfM2 is the sum of square of differences to the current mean.
7176 579 : double dfMin = std::numeric_limits<double>::infinity();
7177 579 : double dfMax = -std::numeric_limits<double>::infinity();
7178 579 : double dfMean = 0.0;
7179 579 : double dfM2 = 0.0;
7180 :
7181 : GDALRasterIOExtraArg sExtraArg;
7182 579 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7183 :
7184 579 : GDALNoDataValues sNoDataValues(this, eDataType);
7185 579 : GDALRasterBand *poMaskBand = nullptr;
7186 579 : if (!sNoDataValues.bGotNoDataValue)
7187 : {
7188 508 : const int l_nMaskFlags = GetMaskFlags();
7189 566 : if (l_nMaskFlags != GMF_ALL_VALID &&
7190 58 : GetColorInterpretation() != GCI_AlphaBand)
7191 : {
7192 58 : poMaskBand = GetMaskBand();
7193 : }
7194 : }
7195 :
7196 579 : bool bSignedByte = false;
7197 579 : if (eDataType == GDT_UInt8)
7198 : {
7199 222 : EnablePixelTypeSignedByteWarning(false);
7200 : const char *pszPixelType =
7201 222 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7202 222 : EnablePixelTypeSignedByteWarning(true);
7203 222 : bSignedByte =
7204 222 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7205 : }
7206 :
7207 579 : GUIntBig nSampleCount = 0;
7208 579 : GUIntBig nValidCount = 0;
7209 :
7210 579 : if (bApproxOK && HasArbitraryOverviews())
7211 : {
7212 : /* --------------------------------------------------------------------
7213 : */
7214 : /* Figure out how much the image should be reduced to get an */
7215 : /* approximate value. */
7216 : /* --------------------------------------------------------------------
7217 : */
7218 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7219 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7220 :
7221 0 : int nXReduced = nRasterXSize;
7222 0 : int nYReduced = nRasterYSize;
7223 0 : if (dfReduction > 1.0)
7224 : {
7225 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7226 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7227 :
7228 : // Catch the case of huge resizing ratios here
7229 0 : if (nXReduced == 0)
7230 0 : nXReduced = 1;
7231 0 : if (nYReduced == 0)
7232 0 : nYReduced = 1;
7233 : }
7234 :
7235 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7236 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7237 :
7238 : const CPLErr eErr =
7239 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7240 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7241 0 : if (eErr != CE_None)
7242 : {
7243 0 : CPLFree(pData);
7244 0 : return eErr;
7245 : }
7246 :
7247 0 : GByte *pabyMaskData = nullptr;
7248 0 : if (poMaskBand)
7249 : {
7250 : pabyMaskData =
7251 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7252 0 : if (!pabyMaskData)
7253 : {
7254 0 : CPLFree(pData);
7255 0 : return CE_Failure;
7256 : }
7257 :
7258 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7259 : pabyMaskData, nXReduced, nYReduced,
7260 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
7261 : {
7262 0 : CPLFree(pData);
7263 0 : CPLFree(pabyMaskData);
7264 0 : return CE_Failure;
7265 : }
7266 : }
7267 :
7268 : /* this isn't the fastest way to do this, but is easier for now */
7269 0 : for (int iY = 0; iY < nYReduced; iY++)
7270 : {
7271 0 : for (int iX = 0; iX < nXReduced; iX++)
7272 : {
7273 0 : const int iOffset = iX + iY * nXReduced;
7274 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7275 0 : continue;
7276 :
7277 0 : bool bValid = true;
7278 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7279 0 : iOffset, sNoDataValues, bValid);
7280 0 : if (!bValid)
7281 0 : continue;
7282 :
7283 0 : dfMin = std::min(dfMin, dfValue);
7284 0 : dfMax = std::max(dfMax, dfValue);
7285 :
7286 0 : nValidCount++;
7287 0 : if (dfMin == dfMax)
7288 : {
7289 0 : if (nValidCount == 1)
7290 0 : dfMean = dfMin;
7291 : }
7292 : else
7293 : {
7294 0 : const double dfDelta = dfValue - dfMean;
7295 0 : dfMean += dfDelta / nValidCount;
7296 0 : dfM2 += dfDelta * (dfValue - dfMean);
7297 : }
7298 : }
7299 : }
7300 :
7301 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7302 :
7303 0 : CPLFree(pData);
7304 0 : CPLFree(pabyMaskData);
7305 : }
7306 :
7307 : else // No arbitrary overviews.
7308 : {
7309 579 : if (!InitBlockInfo())
7310 260 : return CE_Failure;
7311 :
7312 : /* --------------------------------------------------------------------
7313 : */
7314 : /* Figure out the ratio of blocks we will read to get an */
7315 : /* approximate value. */
7316 : /* --------------------------------------------------------------------
7317 : */
7318 579 : int nSampleRate = 1;
7319 579 : if (bApproxOK)
7320 : {
7321 43 : nSampleRate = static_cast<int>(std::max(
7322 86 : 1.0,
7323 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7324 : // We want to avoid probing only the first column of blocks for
7325 : // a square shaped raster, because it is not unlikely that it may
7326 : // be padding only (#6378)
7327 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7328 1 : nSampleRate += 1;
7329 : }
7330 579 : if (nSampleRate == 1)
7331 545 : bApproxOK = false;
7332 :
7333 : // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7334 : // for each block, and possibly for the whole raster.
7335 579 : if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7336 316 : eDataType == GDT_UInt16))
7337 : {
7338 : // We can do integer computation on the whole raster in the Byte case
7339 : // only if the number of pixels explored is lower than
7340 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7341 : // Should be 99.99999% of cases.
7342 : // For GUInt16, this limits to raster of 4 giga pixels
7343 :
7344 : const bool bIntegerStats =
7345 465 : ((eDataType == GDT_UInt8 &&
7346 205 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7347 205 : nSampleRate <
7348 205 : GUINTBIG_MAX / (255U * 255U) /
7349 205 : (static_cast<GUInt64>(nBlockXSize) *
7350 205 : static_cast<GUInt64>(nBlockYSize))) ||
7351 55 : (eDataType == GDT_UInt16 &&
7352 55 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7353 55 : nSampleRate <
7354 55 : GUINTBIG_MAX / (65535U * 65535U) /
7355 55 : (static_cast<GUInt64>(nBlockXSize) *
7356 575 : static_cast<GUInt64>(nBlockYSize)))) &&
7357 : // Can be set to NO for easier debugging of the !bIntegerStats
7358 : // case which requires huge rasters to trigger
7359 260 : CPLTestBool(
7360 260 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7361 :
7362 260 : const GUInt32 nMaxValueType =
7363 260 : (eDataType == GDT_UInt8) ? 255 : 65535;
7364 260 : GUInt32 nMin = nMaxValueType;
7365 260 : GUInt32 nMax = 0;
7366 260 : GUIntBig nSum = 0;
7367 260 : GUIntBig nSumSquare = 0;
7368 : // If no valid nodata, map to invalid value (256 for Byte)
7369 260 : const GUInt32 nNoDataValue =
7370 295 : (sNoDataValues.bGotNoDataValue &&
7371 35 : sNoDataValues.dfNoDataValue >= 0 &&
7372 35 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7373 35 : fabs(sNoDataValues.dfNoDataValue -
7374 35 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7375 : 1e-10)) < 1e-10)
7376 295 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7377 : : nMaxValueType + 1;
7378 :
7379 260 : int nChunkXSize = nBlockXSize;
7380 260 : int nChunkYSize = nBlockYSize;
7381 260 : int nChunksPerRow = nBlocksPerRow;
7382 260 : int nChunksPerCol = nBlocksPerColumn;
7383 :
7384 260 : int nThreads = 1;
7385 260 : if (nChunkYSize > 1)
7386 : {
7387 115 : nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7388 : /* bDefaultToAllCPUs = */ false);
7389 : }
7390 :
7391 260 : int nNewChunkXSize = nChunkXSize;
7392 260 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
7393 268 : if (!bApproxOK && nThreads > 1 &&
7394 8 : MayMultiBlockReadingBeMultiThreaded())
7395 : {
7396 4 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7397 4 : const size_t nChunkPixels =
7398 4 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7399 8 : if (nRAMAmount > 0 &&
7400 : nChunkPixels <=
7401 4 : std::numeric_limits<size_t>::max() / nDTSize)
7402 : {
7403 4 : const size_t nBlockSize = nDTSize * nChunkPixels;
7404 4 : const int64_t nBlockCount = nRAMAmount / nBlockSize;
7405 4 : if (nBlockCount >= 2)
7406 : {
7407 4 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7408 12 : nChunkXSize * std::min<int64_t>(
7409 : nBlockCount,
7410 8 : (std::numeric_limits<int>::max() -
7411 8 : ALIGNMENT_AVX2_OPTIM) /
7412 4 : nChunkPixels),
7413 8 : nRasterXSize));
7414 :
7415 4 : CPLAssert(nChunkXSize <
7416 : std::numeric_limits<int>::max() /
7417 : nChunkYSize);
7418 : }
7419 : }
7420 : }
7421 :
7422 260 : std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
7423 260 : GByte *pabyTemp = nullptr;
7424 260 : if (nNewChunkXSize != nBlockXSize)
7425 : {
7426 4 : pabyTempUnaligned.reset(static_cast<GByte *>(
7427 4 : VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
7428 : ALIGNMENT_AVX2_OPTIM)));
7429 4 : if (pabyTempUnaligned)
7430 : {
7431 4 : pabyTemp = reinterpret_cast<GByte *>(
7432 4 : reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
7433 : (ALIGNMENT_AVX2_OPTIM -
7434 4 : (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
7435 : ALIGNMENT_AVX2_OPTIM)));
7436 4 : nChunkXSize = nNewChunkXSize;
7437 : nChunksPerRow =
7438 4 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7439 : }
7440 : }
7441 :
7442 260 : for (GIntBig iSampleBlock = 0;
7443 13147 : iSampleBlock <
7444 13147 : static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7445 12887 : iSampleBlock += nSampleRate)
7446 : {
7447 12891 : const int iYBlock =
7448 12891 : static_cast<int>(iSampleBlock / nChunksPerRow);
7449 12891 : const int iXBlock =
7450 12891 : static_cast<int>(iSampleBlock % nChunksPerRow);
7451 :
7452 : const int nXCheck =
7453 12891 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7454 : const int nYCheck =
7455 12891 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7456 :
7457 12891 : GDALRasterBlock *poBlock = nullptr;
7458 12891 : if (pabyTemp)
7459 : {
7460 12 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7461 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7462 : pabyTemp, nXCheck, nYCheck, eDataType, 0,
7463 6 : static_cast<GSpacing>(nChunkXSize) * nDTSize,
7464 6 : nullptr) != CE_None)
7465 : {
7466 4 : return CE_Failure;
7467 : }
7468 : }
7469 : else
7470 : {
7471 12885 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7472 12885 : if (poBlock == nullptr)
7473 : {
7474 2 : return CE_Failure;
7475 : }
7476 : }
7477 :
7478 : const void *const pData =
7479 12887 : poBlock ? poBlock->GetDataRef() : pabyTemp;
7480 :
7481 12887 : GUIntBig nBlockSum = 0;
7482 12887 : GUIntBig nBlockSumSquare = 0;
7483 12887 : GUIntBig nBlockSampleCount = 0;
7484 12887 : GUIntBig nBlockValidCount = 0;
7485 12887 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7486 12887 : GUIntBig &nBlockSumSquareRef =
7487 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7488 12887 : GUIntBig &nBlockSampleCountRef =
7489 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7490 12887 : GUIntBig &nBlockValidCountRef =
7491 : bIntegerStats ? nValidCount : nBlockValidCount;
7492 :
7493 12887 : if (eDataType == GDT_UInt8)
7494 : {
7495 : ComputeStatisticsInternal<
7496 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7497 12191 : f(nXCheck, nChunkXSize, nYCheck,
7498 : static_cast<const GByte *>(pData),
7499 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7500 : nMax, nBlockSumRef, nBlockSumSquareRef,
7501 : nBlockSampleCountRef, nBlockValidCountRef);
7502 : }
7503 : else
7504 : {
7505 : ComputeStatisticsInternal<
7506 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7507 696 : f(nXCheck, nChunkXSize, nYCheck,
7508 : static_cast<const GUInt16 *>(pData),
7509 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7510 : nMax, nBlockSumRef, nBlockSumSquareRef,
7511 : nBlockSampleCountRef, nBlockValidCountRef);
7512 : }
7513 :
7514 12887 : if (poBlock)
7515 12883 : poBlock->DropLock();
7516 :
7517 12887 : if (!bIntegerStats)
7518 : {
7519 169 : nSampleCount += nBlockSampleCount;
7520 169 : if (nBlockValidCount)
7521 : {
7522 : // Update the global mean and M2 (the difference of the
7523 : // square to the mean) from the values of the block
7524 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7525 169 : const double dfBlockValidCount =
7526 169 : static_cast<double>(nBlockValidCount);
7527 169 : const double dfBlockMean =
7528 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7529 : const double dfBlockM2 =
7530 169 : static_cast<double>(
7531 169 : GDALUInt128::Mul(nBlockSumSquare,
7532 169 : nBlockValidCount) -
7533 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7534 169 : dfBlockValidCount;
7535 169 : const double dfDelta = dfBlockMean - dfMean;
7536 169 : const auto nNewValidCount =
7537 169 : nValidCount + nBlockValidCount;
7538 169 : const double dfNewValidCount =
7539 : static_cast<double>(nNewValidCount);
7540 169 : dfMean +=
7541 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7542 169 : dfM2 +=
7543 169 : dfBlockM2 + dfDelta * dfDelta *
7544 169 : static_cast<double>(nValidCount) *
7545 169 : dfBlockValidCount / dfNewValidCount;
7546 169 : nValidCount = nNewValidCount;
7547 : }
7548 : }
7549 :
7550 12887 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7551 12887 : (static_cast<double>(nChunksPerRow) *
7552 : nChunksPerCol),
7553 : "Compute Statistics", pProgressData))
7554 : {
7555 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7556 : "User terminated");
7557 0 : return CE_Failure;
7558 : }
7559 : }
7560 :
7561 256 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7562 : {
7563 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7564 0 : return CE_Failure;
7565 : }
7566 :
7567 256 : double dfStdDev = 0;
7568 256 : if (bIntegerStats)
7569 : {
7570 232 : if (nValidCount)
7571 223 : dfMean = static_cast<double>(nSum) / nValidCount;
7572 :
7573 : // To avoid potential precision issues when doing the difference,
7574 : // we need to do that computation on 128 bit rather than casting
7575 : // to double
7576 : const GDALUInt128 nTmpForStdDev(
7577 232 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7578 464 : GDALUInt128::Mul(nSum, nSum));
7579 232 : dfStdDev =
7580 232 : nValidCount > 0
7581 232 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7582 : : 0.0;
7583 : }
7584 24 : else if (nValidCount > 0)
7585 : {
7586 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7587 : }
7588 :
7589 : /// Save computed information
7590 256 : if (nValidCount > 0)
7591 : {
7592 247 : if (bApproxOK)
7593 : {
7594 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7595 : }
7596 223 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7597 : {
7598 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7599 : }
7600 247 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7601 : }
7602 :
7603 256 : SetValidPercent(nSampleCount, nValidCount);
7604 :
7605 : /* --------------------------------------------------------------------
7606 : */
7607 : /* Record results. */
7608 : /* --------------------------------------------------------------------
7609 : */
7610 256 : if (pdfMin != nullptr)
7611 253 : *pdfMin = nValidCount ? nMin : 0;
7612 256 : if (pdfMax != nullptr)
7613 253 : *pdfMax = nValidCount ? nMax : 0;
7614 :
7615 256 : if (pdfMean != nullptr)
7616 249 : *pdfMean = dfMean;
7617 :
7618 256 : if (pdfStdDev != nullptr)
7619 249 : *pdfStdDev = dfStdDev;
7620 :
7621 256 : if (nValidCount > 0)
7622 247 : return CE_None;
7623 :
7624 9 : ReportError(CE_Failure, CPLE_AppDefined,
7625 : "Failed to compute statistics, no valid pixels found "
7626 : "in sampling.");
7627 9 : return CE_Failure;
7628 : }
7629 :
7630 319 : GByte *pabyMaskData = nullptr;
7631 319 : if (poMaskBand)
7632 : {
7633 : pabyMaskData = static_cast<GByte *>(
7634 58 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7635 58 : if (!pabyMaskData)
7636 : {
7637 0 : return CE_Failure;
7638 : }
7639 : }
7640 :
7641 319 : float fMin = std::numeric_limits<float>::infinity();
7642 319 : float fMax = -std::numeric_limits<float>::infinity();
7643 : bool bFloat32Optim =
7644 133 : (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7645 319 : eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7646 209 : !pabyMaskData &&
7647 847 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7648 209 : CPLTestBool(
7649 319 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7650 0 : std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7651 :
7652 319 : int nChunkXSize = nBlockXSize;
7653 319 : int nChunkYSize = nBlockYSize;
7654 319 : int nChunksPerRow = nBlocksPerRow;
7655 319 : int nChunksPerCol = nBlocksPerColumn;
7656 :
7657 : #define nBlockXSize use_nChunkXSize_instead
7658 : #define nBlockYSize use_nChunkYSize_instead
7659 : #define nBlocksPerRow use_nChunksPerRow_instead
7660 : #define nBlocksPerColumn use_nChunksPerCol_instead
7661 :
7662 319 : int nThreads = 1;
7663 319 : CPLWorkerThreadPool *psThreadPool = nullptr;
7664 319 : if (bFloat32Optim)
7665 : {
7666 207 : if (nChunkYSize > 1)
7667 : {
7668 15 : nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7669 : /* bDefaultToAllCPUs = */ false);
7670 : }
7671 :
7672 207 : int nNewChunkXSize = nChunkXSize;
7673 211 : if (!bApproxOK && nThreads > 1 &&
7674 4 : MayMultiBlockReadingBeMultiThreaded())
7675 : {
7676 0 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7677 0 : const size_t nChunkPixels =
7678 0 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7679 0 : if (nRAMAmount > 0 &&
7680 : nChunkPixels <=
7681 0 : std::numeric_limits<size_t>::max() / sizeof(float))
7682 : {
7683 0 : const size_t nBlockSizeAsFloat32 =
7684 : sizeof(float) * nChunkPixels;
7685 0 : const int64_t nBlockCount =
7686 0 : nRAMAmount / nBlockSizeAsFloat32;
7687 0 : if (nBlockCount >= 2)
7688 : {
7689 0 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7690 0 : nChunkXSize * std::min<int64_t>(
7691 : nBlockCount,
7692 0 : std::numeric_limits<int>::max() /
7693 0 : nChunkPixels),
7694 0 : nRasterXSize));
7695 :
7696 0 : CPLAssert(nChunkXSize <
7697 : std::numeric_limits<int>::max() /
7698 : nChunkYSize);
7699 : }
7700 : }
7701 : }
7702 207 : if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7703 : {
7704 187 : pafTemp.reset(static_cast<float *>(
7705 187 : VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7706 187 : bFloat32Optim = pafTemp != nullptr;
7707 187 : if (bFloat32Optim)
7708 : {
7709 187 : nChunkXSize = nNewChunkXSize;
7710 : nChunksPerRow =
7711 187 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7712 : }
7713 : }
7714 207 : CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7715 : nChunkXSize, nChunkYSize);
7716 : }
7717 :
7718 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7719 : const bool bFloat64Optim =
7720 23 : eDataType == GDT_Float64 && !pabyMaskData &&
7721 365 : nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7722 23 : CPLTestBool(
7723 319 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7724 : #endif
7725 :
7726 319 : std::vector<StatisticsTaskFloat32> tasksFloat32;
7727 :
7728 319 : for (GIntBig iSampleBlock = 0;
7729 6034 : iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7730 5715 : iSampleBlock += nSampleRate)
7731 : {
7732 5715 : const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7733 5715 : const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7734 :
7735 : const int nXCheck =
7736 5715 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7737 : const int nYCheck =
7738 5715 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7739 :
7740 6300 : if (poMaskBand &&
7741 585 : poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7742 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7743 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7744 : 0, nChunkXSize, nullptr) != CE_None)
7745 : {
7746 0 : CPLFree(pabyMaskData);
7747 0 : return CE_Failure;
7748 : }
7749 :
7750 5715 : GDALRasterBlock *poBlock = nullptr;
7751 5715 : if (pafTemp)
7752 : {
7753 2393 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7754 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7755 2393 : pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7756 2393 : static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7757 2393 : nullptr) != CE_None)
7758 : {
7759 0 : CPLFree(pabyMaskData);
7760 0 : return CE_Failure;
7761 : }
7762 : }
7763 : else
7764 : {
7765 3322 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7766 3322 : if (poBlock == nullptr)
7767 : {
7768 0 : CPLFree(pabyMaskData);
7769 0 : return CE_Failure;
7770 : }
7771 : }
7772 :
7773 : const void *const pData =
7774 5715 : poBlock ? poBlock->GetDataRef() : pafTemp.get();
7775 :
7776 5715 : if (bFloat32Optim)
7777 : {
7778 4729 : const float *const pafSrcData =
7779 : static_cast<const float *>(pData);
7780 :
7781 4735 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7782 6 : !std::isnan(sNoDataValues.fNoDataValue);
7783 4729 : const int nTasks = std::min(nYCheck, nThreads);
7784 4729 : const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7785 4729 : tasksFloat32.clear();
7786 9462 : for (int i = 0; i < nTasks; ++i)
7787 : {
7788 4733 : StatisticsTaskFloat32 task;
7789 4733 : task.eDataType = eDataType;
7790 4733 : task.bHasNoData = bHasNoData;
7791 4733 : task.psNoDataValues = &sNoDataValues;
7792 4733 : task.nChunkXSize = nChunkXSize;
7793 4733 : task.fMin = fMin;
7794 4733 : task.fMax = fMax;
7795 4733 : task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7796 4733 : nRowsPerTask *
7797 4733 : nChunkXSize;
7798 4733 : task.nXCheck = nXCheck;
7799 4733 : task.nYCheck =
7800 4733 : std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7801 4733 : tasksFloat32.emplace_back(std::move(task));
7802 : }
7803 4729 : if (psThreadPool)
7804 : {
7805 0 : auto poJobQueue = psThreadPool->CreateJobQueue();
7806 0 : for (auto &task : tasksFloat32)
7807 : {
7808 0 : poJobQueue->SubmitJob([&task]() { task.Perform(); });
7809 : }
7810 0 : poJobQueue->WaitCompletion();
7811 : }
7812 : else
7813 : {
7814 4729 : tasksFloat32[0].Perform();
7815 : }
7816 :
7817 9462 : for (const auto &task : tasksFloat32)
7818 : {
7819 4733 : if (task.dfBlockValidCount > 0)
7820 : {
7821 4729 : fMin = std::min(fMin, task.fMin);
7822 4729 : fMax = std::max(fMax, task.fMax);
7823 :
7824 : // Update the global mean and M2 (the difference of the
7825 : // square to the mean) from the values of the block
7826 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7827 4729 : const auto nNewValidCount =
7828 4729 : nValidCount +
7829 4729 : static_cast<int>(task.dfBlockValidCount);
7830 4729 : dfM2 += task.dfBlockM2;
7831 4729 : if (task.dfBlockMean != dfMean)
7832 : {
7833 1166 : if (nValidCount == 0)
7834 : {
7835 50 : dfMean = task.dfBlockMean;
7836 : }
7837 : else
7838 : {
7839 1116 : const double dfDelta =
7840 1116 : task.dfBlockMean - dfMean;
7841 1116 : const double dfNewValidCount =
7842 : static_cast<double>(nNewValidCount);
7843 1116 : dfMean += dfDelta * (task.dfBlockValidCount /
7844 : dfNewValidCount);
7845 1116 : dfM2 += dfDelta * dfDelta *
7846 1116 : static_cast<double>(nValidCount) *
7847 1116 : task.dfBlockValidCount /
7848 : dfNewValidCount;
7849 : }
7850 : }
7851 4729 : nValidCount = nNewValidCount;
7852 : }
7853 : }
7854 : }
7855 :
7856 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7857 986 : else if (bFloat64Optim)
7858 : {
7859 : const bool bHasNoData =
7860 563 : sNoDataValues.bGotNoDataValue &&
7861 269 : !std::isnan(sNoDataValues.dfNoDataValue);
7862 294 : double dfBlockMean = 0;
7863 294 : double dfBlockM2 = 0;
7864 294 : double dfBlockValidCount = 0;
7865 2661 : for (int iY = 0; iY < nYCheck; iY++)
7866 : {
7867 2367 : const int iOffset = iY * nChunkXSize;
7868 2367 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7869 : {
7870 1817 : int iX = 0;
7871 1817 : if (bHasNoData)
7872 : {
7873 : iX = ComputeStatisticsFloat64_SSE2<
7874 : /* bCheckMinEqMax = */ false,
7875 387 : /* bHasNoData = */ true>(
7876 387 : static_cast<const double *>(pData) + iOffset,
7877 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7878 : dfMax, dfBlockMean, dfBlockM2,
7879 : dfBlockValidCount);
7880 : }
7881 : else
7882 : {
7883 : iX = ComputeStatisticsFloat64_SSE2<
7884 : /* bCheckMinEqMax = */ false,
7885 1430 : /* bHasNoData = */ false>(
7886 1430 : static_cast<const double *>(pData) + iOffset,
7887 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7888 : dfMax, dfBlockMean, dfBlockM2,
7889 : dfBlockValidCount);
7890 : }
7891 2959 : for (; iX < nXCheck; iX++)
7892 : {
7893 1142 : const double dfValue = static_cast<const double *>(
7894 1142 : pData)[iOffset + iX];
7895 1665 : if (std::isnan(dfValue) ||
7896 523 : (bHasNoData &&
7897 523 : dfValue == sNoDataValues.dfNoDataValue))
7898 59 : continue;
7899 1083 : dfMin = std::min(dfMin, dfValue);
7900 1083 : dfMax = std::max(dfMax, dfValue);
7901 1083 : dfBlockValidCount += 1.0;
7902 1083 : const double dfDelta = dfValue - dfBlockMean;
7903 1083 : dfBlockMean += dfDelta / dfBlockValidCount;
7904 1083 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7905 1817 : }
7906 : }
7907 : else
7908 : {
7909 550 : int iX = 0;
7910 550 : if (dfBlockValidCount == 0)
7911 : {
7912 7673 : for (; iX < nXCheck; iX++)
7913 : {
7914 7639 : const double dfValue =
7915 : static_cast<const double *>(
7916 7639 : pData)[iOffset + iX];
7917 15253 : if (std::isnan(dfValue) ||
7918 7614 : (bHasNoData &&
7919 7614 : dfValue == sNoDataValues.dfNoDataValue))
7920 7377 : continue;
7921 262 : dfMin = std::min(dfMin, dfValue);
7922 262 : dfMax = std::max(dfMax, dfValue);
7923 262 : dfBlockValidCount = 1;
7924 262 : dfBlockMean = dfValue;
7925 262 : iX++;
7926 262 : break;
7927 : }
7928 : }
7929 550 : if (bHasNoData)
7930 : {
7931 : iX = ComputeStatisticsFloat64_SSE2<
7932 : /* bCheckMinEqMax = */ true,
7933 398 : /* bHasNoData = */ true>(
7934 398 : static_cast<const double *>(pData) + iOffset,
7935 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7936 : dfMax, dfBlockMean, dfBlockM2,
7937 : dfBlockValidCount);
7938 : }
7939 : else
7940 : {
7941 : iX = ComputeStatisticsFloat64_SSE2<
7942 : /* bCheckMinEqMax = */ true,
7943 152 : /* bHasNoData = */ false>(
7944 152 : static_cast<const double *>(pData) + iOffset,
7945 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7946 : dfMax, dfBlockMean, dfBlockM2,
7947 : dfBlockValidCount);
7948 : }
7949 1121 : for (; iX < nXCheck; iX++)
7950 : {
7951 571 : const double dfValue = static_cast<const double *>(
7952 571 : pData)[iOffset + iX];
7953 1103 : if (std::isnan(dfValue) ||
7954 532 : (bHasNoData &&
7955 532 : dfValue == sNoDataValues.dfNoDataValue))
7956 146 : continue;
7957 425 : dfMin = std::min(dfMin, dfValue);
7958 425 : dfMax = std::max(dfMax, dfValue);
7959 425 : dfBlockValidCount += 1.0;
7960 425 : if (dfMin != dfMax)
7961 : {
7962 150 : const double dfDelta = dfValue - dfBlockMean;
7963 150 : dfBlockMean += dfDelta / dfBlockValidCount;
7964 150 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7965 : }
7966 : }
7967 : }
7968 : }
7969 :
7970 294 : if (dfBlockValidCount > 0)
7971 : {
7972 : // Update the global mean and M2 (the difference of the
7973 : // square to the mean) from the values of the block
7974 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7975 262 : const auto nNewValidCount =
7976 262 : nValidCount + static_cast<int>(dfBlockValidCount);
7977 262 : dfM2 += dfBlockM2;
7978 262 : if (dfBlockMean != dfMean)
7979 : {
7980 249 : if (nValidCount == 0)
7981 : {
7982 20 : dfMean = dfBlockMean;
7983 : }
7984 : else
7985 : {
7986 229 : const double dfDelta = dfBlockMean - dfMean;
7987 229 : const double dfNewValidCount =
7988 : static_cast<double>(nNewValidCount);
7989 229 : dfMean +=
7990 229 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7991 229 : dfM2 += dfDelta * dfDelta *
7992 229 : static_cast<double>(nValidCount) *
7993 229 : dfBlockValidCount / dfNewValidCount;
7994 : }
7995 : }
7996 262 : nValidCount = nNewValidCount;
7997 : }
7998 : }
7999 : #endif // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
8000 :
8001 : else
8002 : {
8003 : // This isn't the fastest way to do this, but is easier for now.
8004 6046 : for (int iY = 0; iY < nYCheck; iY++)
8005 : {
8006 5354 : if (nValidCount && dfMin != dfMax)
8007 : {
8008 712990 : for (int iX = 0; iX < nXCheck; iX++)
8009 : {
8010 708474 : const GPtrDiff_t iOffset =
8011 708474 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8012 708474 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8013 9653 : continue;
8014 :
8015 698847 : bool bValid = true;
8016 : double dfValue =
8017 698847 : GetPixelValue(eDataType, bSignedByte, pData,
8018 698847 : iOffset, sNoDataValues, bValid);
8019 :
8020 698847 : if (!bValid)
8021 26 : continue;
8022 :
8023 698821 : dfMin = std::min(dfMin, dfValue);
8024 698821 : dfMax = std::max(dfMax, dfValue);
8025 :
8026 698821 : nValidCount++;
8027 698821 : const double dfDelta = dfValue - dfMean;
8028 698821 : dfMean += dfDelta / nValidCount;
8029 698821 : dfM2 += dfDelta * (dfValue - dfMean);
8030 4516 : }
8031 : }
8032 : else
8033 : {
8034 838 : int iX = 0;
8035 838 : if (nValidCount == 0)
8036 : {
8037 94429 : for (; iX < nXCheck; iX++)
8038 : {
8039 94372 : const GPtrDiff_t iOffset =
8040 94372 : iX +
8041 94372 : static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8042 94372 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8043 94281 : continue;
8044 :
8045 91 : bool bValid = true;
8046 91 : double dfValue = GetPixelValue(
8047 : eDataType, bSignedByte, pData, iOffset,
8048 : sNoDataValues, bValid);
8049 :
8050 91 : if (!bValid)
8051 0 : continue;
8052 :
8053 91 : dfMin = dfValue;
8054 91 : dfMax = dfValue;
8055 91 : dfMean = dfValue;
8056 91 : nValidCount = 1;
8057 91 : iX++;
8058 91 : break;
8059 : }
8060 : }
8061 167021 : for (; iX < nXCheck; iX++)
8062 : {
8063 166183 : const GPtrDiff_t iOffset =
8064 166183 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8065 166183 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8066 376 : continue;
8067 :
8068 165822 : bool bValid = true;
8069 : double dfValue =
8070 165822 : GetPixelValue(eDataType, bSignedByte, pData,
8071 165822 : iOffset, sNoDataValues, bValid);
8072 :
8073 165822 : if (!bValid)
8074 15 : continue;
8075 :
8076 165807 : dfMin = std::min(dfMin, dfValue);
8077 165807 : dfMax = std::max(dfMax, dfValue);
8078 :
8079 165807 : nValidCount++;
8080 165807 : if (dfMin != dfMax)
8081 : {
8082 2636 : const double dfDelta = dfValue - dfMean;
8083 2636 : dfMean += dfDelta / nValidCount;
8084 2636 : dfM2 += dfDelta * (dfValue - dfMean);
8085 : }
8086 : }
8087 : }
8088 : }
8089 : }
8090 :
8091 5715 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8092 :
8093 5715 : if (poBlock)
8094 3322 : poBlock->DropLock();
8095 :
8096 5715 : if (!pfnProgress(
8097 5715 : static_cast<double>(iSampleBlock) /
8098 5715 : (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8099 : "Compute Statistics", pProgressData))
8100 : {
8101 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8102 0 : CPLFree(pabyMaskData);
8103 0 : return CE_Failure;
8104 : }
8105 : }
8106 :
8107 : #undef nBlockXSize
8108 : #undef nBlockYSize
8109 : #undef nBlocksPerRow
8110 : #undef nBlocksPerColumn
8111 :
8112 319 : if (bFloat32Optim)
8113 : {
8114 207 : dfMin = static_cast<double>(fMin);
8115 207 : dfMax = static_cast<double>(fMax);
8116 : }
8117 319 : CPLFree(pabyMaskData);
8118 : }
8119 :
8120 319 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8121 : {
8122 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8123 0 : return CE_Failure;
8124 : }
8125 :
8126 : /* -------------------------------------------------------------------- */
8127 : /* Save computed information. */
8128 : /* -------------------------------------------------------------------- */
8129 319 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8130 :
8131 319 : if (nValidCount > 0)
8132 : {
8133 318 : if (bApproxOK)
8134 : {
8135 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8136 : }
8137 310 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8138 : {
8139 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8140 : }
8141 318 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8142 : }
8143 : else
8144 : {
8145 1 : dfMin = 0.0;
8146 1 : dfMax = 0.0;
8147 : }
8148 :
8149 319 : SetValidPercent(nSampleCount, nValidCount);
8150 :
8151 : /* -------------------------------------------------------------------- */
8152 : /* Record results. */
8153 : /* -------------------------------------------------------------------- */
8154 319 : if (pdfMin != nullptr)
8155 316 : *pdfMin = dfMin;
8156 319 : if (pdfMax != nullptr)
8157 316 : *pdfMax = dfMax;
8158 :
8159 319 : if (pdfMean != nullptr)
8160 313 : *pdfMean = dfMean;
8161 :
8162 319 : if (pdfStdDev != nullptr)
8163 313 : *pdfStdDev = dfStdDev;
8164 :
8165 319 : if (nValidCount > 0)
8166 318 : return CE_None;
8167 :
8168 1 : ReportError(
8169 : CE_Failure, CPLE_AppDefined,
8170 : "Failed to compute statistics, no valid pixels found in sampling.");
8171 1 : return CE_Failure;
8172 : }
8173 :
8174 : /************************************************************************/
8175 : /* GDALComputeRasterStatistics() */
8176 : /************************************************************************/
8177 :
8178 : /**
8179 : * \brief Compute image statistics.
8180 : *
8181 : * @see GDALRasterBand::ComputeStatistics()
8182 : */
8183 :
8184 238 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8185 : int bApproxOK, double *pdfMin,
8186 : double *pdfMax, double *pdfMean,
8187 : double *pdfStdDev,
8188 : GDALProgressFunc pfnProgress,
8189 : void *pProgressData)
8190 :
8191 : {
8192 238 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8193 :
8194 238 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8195 :
8196 238 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8197 238 : pdfStdDev, pfnProgress, pProgressData);
8198 : }
8199 :
8200 : /************************************************************************/
8201 : /* SetStatistics() */
8202 : /************************************************************************/
8203 :
8204 : /**
8205 : * \brief Set statistics on band.
8206 : *
8207 : * This method can be used to store min/max/mean/standard deviation
8208 : * statistics on a raster band.
8209 : *
8210 : * The default implementation stores them as metadata, and will only work
8211 : * on formats that can save arbitrary metadata. This method cannot detect
8212 : * whether metadata will be properly saved and so may return CE_None even
8213 : * if the statistics will never be saved.
8214 : *
8215 : * This method is the same as the C function GDALSetRasterStatistics().
8216 : *
8217 : * @param dfMin minimum pixel value.
8218 : *
8219 : * @param dfMax maximum pixel value.
8220 : *
8221 : * @param dfMean mean (average) of all pixel values.
8222 : *
8223 : * @param dfStdDev Standard deviation of all pixel values.
8224 : *
8225 : * @return CE_None on success or CE_Failure on failure.
8226 : */
8227 :
8228 598 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8229 : double dfStdDev)
8230 :
8231 : {
8232 598 : char szValue[128] = {0};
8233 :
8234 598 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8235 598 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
8236 :
8237 598 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8238 598 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8239 :
8240 598 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8241 598 : SetMetadataItem("STATISTICS_MEAN", szValue);
8242 :
8243 598 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8244 598 : SetMetadataItem("STATISTICS_STDDEV", szValue);
8245 :
8246 598 : return CE_None;
8247 : }
8248 :
8249 : /************************************************************************/
8250 : /* GDALSetRasterStatistics() */
8251 : /************************************************************************/
8252 :
8253 : /**
8254 : * \brief Set statistics on band.
8255 : *
8256 : * @see GDALRasterBand::SetStatistics()
8257 : */
8258 :
8259 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8260 : double dfMax, double dfMean,
8261 : double dfStdDev)
8262 :
8263 : {
8264 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8265 :
8266 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8267 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8268 : }
8269 :
8270 : /************************************************************************/
8271 : /* ComputeRasterMinMax() */
8272 : /************************************************************************/
8273 :
8274 : template <class T, bool HAS_NODATA>
8275 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8276 : T *pMax)
8277 : {
8278 2 : T min0 = *pMin;
8279 2 : T max0 = *pMax;
8280 2 : T min1 = *pMin;
8281 2 : T max1 = *pMax;
8282 : size_t i;
8283 2 : for (i = 0; i + 1 < nElts; i += 2)
8284 : {
8285 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8286 : {
8287 0 : min0 = std::min(min0, buffer[i]);
8288 0 : max0 = std::max(max0, buffer[i]);
8289 : }
8290 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8291 : {
8292 0 : min1 = std::min(min1, buffer[i + 1]);
8293 0 : max1 = std::max(max1, buffer[i + 1]);
8294 : }
8295 : }
8296 2 : T min = std::min(min0, min1);
8297 2 : T max = std::max(max0, max1);
8298 2 : if (i < nElts)
8299 : {
8300 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8301 : {
8302 2 : min = std::min(min, buffer[i]);
8303 2 : max = std::max(max, buffer[i]);
8304 : }
8305 : }
8306 2 : *pMin = min;
8307 2 : *pMax = max;
8308 2 : }
8309 :
8310 : template <GDALDataType eDataType, bool bSignedByte>
8311 : static void
8312 6743 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8313 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8314 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
8315 : {
8316 6743 : double dfLocalMin = dfMin;
8317 6743 : double dfLocalMax = dfMax;
8318 :
8319 22131 : for (int iY = 0; iY < nYCheck; iY++)
8320 : {
8321 14858621 : for (int iX = 0; iX < nXCheck; iX++)
8322 : {
8323 14843185 : const GPtrDiff_t iOffset =
8324 14843185 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8325 14843185 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8326 109852 : continue;
8327 14760202 : bool bValid = true;
8328 14760202 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8329 : iOffset, sNoDataValues, bValid);
8330 14760202 : if (!bValid)
8331 26871 : continue;
8332 :
8333 14733402 : dfLocalMin = std::min(dfLocalMin, dfValue);
8334 14733402 : dfLocalMax = std::max(dfLocalMax, dfValue);
8335 : }
8336 : }
8337 :
8338 6743 : dfMin = dfLocalMin;
8339 6743 : dfMax = dfLocalMax;
8340 6743 : }
8341 :
8342 6743 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8343 : bool bSignedByte, int nXCheck, int nYCheck,
8344 : int nBlockXSize,
8345 : const GDALNoDataValues &sNoDataValues,
8346 : const GByte *pabyMaskData, double &dfMin,
8347 : double &dfMax)
8348 : {
8349 6743 : switch (eDataType)
8350 : {
8351 0 : case GDT_Unknown:
8352 0 : CPLAssert(false);
8353 : break;
8354 660 : case GDT_UInt8:
8355 660 : if (bSignedByte)
8356 : {
8357 3 : ComputeMinMaxGeneric<GDT_UInt8, true>(
8358 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8359 : pabyMaskData, dfMin, dfMax);
8360 : }
8361 : else
8362 : {
8363 657 : ComputeMinMaxGeneric<GDT_UInt8, false>(
8364 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8365 : pabyMaskData, dfMin, dfMax);
8366 : }
8367 660 : break;
8368 4 : case GDT_Int8:
8369 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8370 : nBlockXSize, sNoDataValues,
8371 : pabyMaskData, dfMin, dfMax);
8372 4 : break;
8373 969 : case GDT_UInt16:
8374 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8375 : nBlockXSize, sNoDataValues,
8376 : pabyMaskData, dfMin, dfMax);
8377 969 : break;
8378 2 : case GDT_Int16:
8379 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8380 : nBlockXSize, sNoDataValues,
8381 : pabyMaskData, dfMin, dfMax);
8382 2 : break;
8383 3 : case GDT_UInt32:
8384 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8385 : nBlockXSize, sNoDataValues,
8386 : pabyMaskData, dfMin, dfMax);
8387 3 : break;
8388 3 : case GDT_Int32:
8389 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8390 : nBlockXSize, sNoDataValues,
8391 : pabyMaskData, dfMin, dfMax);
8392 3 : break;
8393 4 : case GDT_UInt64:
8394 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8395 : nBlockXSize, sNoDataValues,
8396 : pabyMaskData, dfMin, dfMax);
8397 4 : break;
8398 4 : case GDT_Int64:
8399 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8400 : nBlockXSize, sNoDataValues,
8401 : pabyMaskData, dfMin, dfMax);
8402 4 : break;
8403 2 : case GDT_Float16:
8404 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8405 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8406 : pabyMaskData, dfMin, dfMax);
8407 2 : break;
8408 4981 : case GDT_Float32:
8409 4981 : ComputeMinMaxGeneric<GDT_Float32, false>(
8410 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8411 : pabyMaskData, dfMin, dfMax);
8412 4981 : break;
8413 1 : case GDT_Float64:
8414 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8415 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8416 : pabyMaskData, dfMin, dfMax);
8417 1 : break;
8418 9 : case GDT_CInt16:
8419 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8420 : nBlockXSize, sNoDataValues,
8421 : pabyMaskData, dfMin, dfMax);
8422 9 : break;
8423 9 : case GDT_CInt32:
8424 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8425 : nBlockXSize, sNoDataValues,
8426 : pabyMaskData, dfMin, dfMax);
8427 9 : break;
8428 0 : case GDT_CFloat16:
8429 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8430 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8431 : pabyMaskData, dfMin, dfMax);
8432 0 : break;
8433 75 : case GDT_CFloat32:
8434 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8435 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8436 : pabyMaskData, dfMin, dfMax);
8437 75 : break;
8438 17 : case GDT_CFloat64:
8439 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8440 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8441 : pabyMaskData, dfMin, dfMax);
8442 17 : break;
8443 0 : case GDT_TypeCount:
8444 0 : CPLAssert(false);
8445 : break;
8446 : }
8447 6743 : }
8448 :
8449 209 : static bool ComputeMinMaxGenericIterBlocks(
8450 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8451 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8452 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8453 : double &dfMin, double &dfMax)
8454 :
8455 : {
8456 209 : GByte *pabyMaskData = nullptr;
8457 : int nBlockXSize, nBlockYSize;
8458 209 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8459 :
8460 209 : if (poMaskBand)
8461 : {
8462 : pabyMaskData =
8463 145 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8464 145 : if (!pabyMaskData)
8465 : {
8466 0 : return false;
8467 : }
8468 : }
8469 :
8470 6952 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8471 6743 : iSampleBlock += nSampleRate)
8472 : {
8473 6743 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8474 6743 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8475 :
8476 6743 : int nXCheck = 0, nYCheck = 0;
8477 6743 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8478 :
8479 13363 : if (poMaskBand &&
8480 6620 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8481 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8482 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8483 : nBlockXSize, nullptr) != CE_None)
8484 : {
8485 0 : CPLFree(pabyMaskData);
8486 0 : return false;
8487 : }
8488 :
8489 6743 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8490 6743 : if (poBlock == nullptr)
8491 : {
8492 0 : CPLFree(pabyMaskData);
8493 0 : return false;
8494 : }
8495 :
8496 6743 : void *const pData = poBlock->GetDataRef();
8497 :
8498 6743 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8499 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8500 : dfMax);
8501 :
8502 6743 : poBlock->DropLock();
8503 : }
8504 :
8505 209 : CPLFree(pabyMaskData);
8506 209 : return true;
8507 : }
8508 :
8509 : /**
8510 : * \brief Compute the min/max values for a band.
8511 : *
8512 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8513 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8514 : * get an approximate min/max. If the band has a nodata value it will
8515 : * be excluded from the minimum and maximum.
8516 : *
8517 : * If bApprox is FALSE, then all pixels will be read and used to compute
8518 : * an exact range.
8519 : *
8520 : * This method is the same as the C function GDALComputeRasterMinMax().
8521 : *
8522 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8523 : * FALSE.
8524 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8525 : * maximum (adfMinMax[1]) are returned.
8526 : *
8527 : * @return CE_None on success or CE_Failure on failure.
8528 : */
8529 :
8530 1953 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8531 : {
8532 : /* -------------------------------------------------------------------- */
8533 : /* Does the driver already know the min/max? */
8534 : /* -------------------------------------------------------------------- */
8535 1953 : if (bApproxOK)
8536 : {
8537 23 : int bSuccessMin = FALSE;
8538 23 : int bSuccessMax = FALSE;
8539 :
8540 23 : double dfMin = GetMinimum(&bSuccessMin);
8541 23 : double dfMax = GetMaximum(&bSuccessMax);
8542 :
8543 23 : if (bSuccessMin && bSuccessMax)
8544 : {
8545 1 : adfMinMax[0] = dfMin;
8546 1 : adfMinMax[1] = dfMax;
8547 1 : return CE_None;
8548 : }
8549 : }
8550 :
8551 : /* -------------------------------------------------------------------- */
8552 : /* If we have overview bands, use them for min/max. */
8553 : /* -------------------------------------------------------------------- */
8554 : // cppcheck-suppress knownConditionTrueFalse
8555 1952 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8556 : {
8557 : GDALRasterBand *poBand =
8558 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8559 :
8560 0 : if (poBand != this)
8561 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8562 : }
8563 :
8564 : /* -------------------------------------------------------------------- */
8565 : /* Read actual data and compute minimum and maximum. */
8566 : /* -------------------------------------------------------------------- */
8567 1952 : GDALNoDataValues sNoDataValues(this, eDataType);
8568 1952 : GDALRasterBand *poMaskBand = nullptr;
8569 1952 : if (!sNoDataValues.bGotNoDataValue)
8570 : {
8571 1589 : const int l_nMaskFlags = GetMaskFlags();
8572 1734 : if (l_nMaskFlags != GMF_ALL_VALID &&
8573 145 : GetColorInterpretation() != GCI_AlphaBand)
8574 : {
8575 145 : poMaskBand = GetMaskBand();
8576 : }
8577 : }
8578 :
8579 1952 : if (!bApproxOK &&
8580 1930 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8581 1770 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8582 1545 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8583 1499 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8584 1930 : eDataType == GDT_Float64) &&
8585 : !poMaskBand)
8586 : {
8587 1606 : CPLErr eErr = ComputeRasterMinMaxLocation(
8588 803 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8589 803 : if (eErr == CE_Warning)
8590 : {
8591 9 : ReportError(CE_Failure, CPLE_AppDefined,
8592 : "Failed to compute min/max, no valid pixels found in "
8593 : "sampling.");
8594 9 : eErr = CE_Failure;
8595 : }
8596 803 : return eErr;
8597 : }
8598 :
8599 1149 : bool bSignedByte = false;
8600 1149 : if (eDataType == GDT_UInt8)
8601 : {
8602 807 : EnablePixelTypeSignedByteWarning(false);
8603 : const char *pszPixelType =
8604 807 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8605 807 : EnablePixelTypeSignedByteWarning(true);
8606 807 : bSignedByte =
8607 807 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8608 : }
8609 :
8610 : GDALRasterIOExtraArg sExtraArg;
8611 1149 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8612 :
8613 2298 : GUInt32 nMin = (eDataType == GDT_UInt8)
8614 1149 : ? 255
8615 : : 65535; // used for GByte & GUInt16 cases
8616 1149 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8617 1149 : GInt16 nMinInt16 =
8618 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8619 1149 : GInt16 nMaxInt16 =
8620 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8621 1149 : double dfMin =
8622 : std::numeric_limits<double>::infinity(); // used for generic code path
8623 1149 : double dfMax =
8624 : -std::numeric_limits<double>::infinity(); // used for generic code path
8625 1149 : const bool bUseOptimizedPath =
8626 1377 : !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8627 228 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8628 :
8629 : const auto ComputeMinMaxForBlock =
8630 19640 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8631 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8632 113770 : int nYCheck)
8633 : {
8634 19640 : if (eDataType == GDT_UInt8 && !bSignedByte)
8635 : {
8636 : const bool bHasNoData =
8637 11612 : sNoDataValues.bGotNoDataValue &&
8638 29793 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8639 11612 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8640 11612 : sNoDataValues.dfNoDataValue;
8641 18181 : const GUInt32 nNoDataValue =
8642 18181 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8643 : : 0;
8644 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8645 : ComputeStatisticsInternal<GByte,
8646 : /* COMPUTE_OTHER_STATS = */ false>::
8647 18181 : f(nXCheck, nBufferWidth, nYCheck,
8648 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8649 18181 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8650 : }
8651 1459 : else if (eDataType == GDT_UInt16)
8652 : {
8653 : const bool bHasNoData =
8654 124 : sNoDataValues.bGotNoDataValue &&
8655 1581 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8656 124 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8657 124 : sNoDataValues.dfNoDataValue;
8658 1457 : const GUInt32 nNoDataValue =
8659 1457 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8660 : : 0;
8661 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8662 : ComputeStatisticsInternal<GUInt16,
8663 : /* COMPUTE_OTHER_STATS = */ false>::
8664 1457 : f(nXCheck, nBufferWidth, nYCheck,
8665 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8666 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8667 : }
8668 2 : else if (eDataType == GDT_Int16)
8669 : {
8670 : const bool bHasNoData =
8671 0 : sNoDataValues.bGotNoDataValue &&
8672 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8673 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8674 0 : sNoDataValues.dfNoDataValue;
8675 2 : if (bHasNoData)
8676 : {
8677 0 : const int16_t nNoDataValue =
8678 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8679 0 : for (int iY = 0; iY < nYCheck; iY++)
8680 : {
8681 0 : ComputeMinMax<int16_t, true>(
8682 0 : static_cast<const int16_t *>(pData) +
8683 0 : static_cast<size_t>(iY) * nBufferWidth,
8684 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8685 : }
8686 : }
8687 : else
8688 : {
8689 4 : for (int iY = 0; iY < nYCheck; iY++)
8690 : {
8691 2 : ComputeMinMax<int16_t, false>(
8692 2 : static_cast<const int16_t *>(pData) +
8693 2 : static_cast<size_t>(iY) * nBufferWidth,
8694 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8695 : }
8696 : }
8697 : }
8698 19640 : };
8699 :
8700 1149 : if (bApproxOK && HasArbitraryOverviews())
8701 : {
8702 : /* --------------------------------------------------------------------
8703 : */
8704 : /* Figure out how much the image should be reduced to get an */
8705 : /* approximate value. */
8706 : /* --------------------------------------------------------------------
8707 : */
8708 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8709 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8710 :
8711 0 : int nXReduced = nRasterXSize;
8712 0 : int nYReduced = nRasterYSize;
8713 0 : if (dfReduction > 1.0)
8714 : {
8715 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8716 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8717 :
8718 : // Catch the case of huge resizing ratios here
8719 0 : if (nXReduced == 0)
8720 0 : nXReduced = 1;
8721 0 : if (nYReduced == 0)
8722 0 : nYReduced = 1;
8723 : }
8724 :
8725 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8726 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8727 :
8728 : const CPLErr eErr =
8729 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8730 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8731 0 : if (eErr != CE_None)
8732 : {
8733 0 : CPLFree(pData);
8734 0 : return eErr;
8735 : }
8736 :
8737 0 : GByte *pabyMaskData = nullptr;
8738 0 : if (poMaskBand)
8739 : {
8740 : pabyMaskData =
8741 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8742 0 : if (!pabyMaskData)
8743 : {
8744 0 : CPLFree(pData);
8745 0 : return CE_Failure;
8746 : }
8747 :
8748 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8749 : pabyMaskData, nXReduced, nYReduced,
8750 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
8751 : {
8752 0 : CPLFree(pData);
8753 0 : CPLFree(pabyMaskData);
8754 0 : return CE_Failure;
8755 : }
8756 : }
8757 :
8758 0 : if (bUseOptimizedPath)
8759 : {
8760 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8761 : }
8762 : else
8763 : {
8764 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8765 : nYReduced, nXReduced, sNoDataValues,
8766 : pabyMaskData, dfMin, dfMax);
8767 : }
8768 :
8769 0 : CPLFree(pData);
8770 0 : CPLFree(pabyMaskData);
8771 : }
8772 :
8773 : else // No arbitrary overviews
8774 : {
8775 1149 : if (!InitBlockInfo())
8776 0 : return CE_Failure;
8777 :
8778 : /* --------------------------------------------------------------------
8779 : */
8780 : /* Figure out the ratio of blocks we will read to get an */
8781 : /* approximate value. */
8782 : /* --------------------------------------------------------------------
8783 : */
8784 1149 : int nSampleRate = 1;
8785 :
8786 1149 : if (bApproxOK)
8787 : {
8788 22 : nSampleRate = static_cast<int>(std::max(
8789 44 : 1.0,
8790 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8791 : // We want to avoid probing only the first column of blocks for
8792 : // a square shaped raster, because it is not unlikely that it may
8793 : // be padding only (#6378).
8794 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8795 0 : nSampleRate += 1;
8796 : }
8797 :
8798 1149 : if (bUseOptimizedPath)
8799 : {
8800 940 : for (GIntBig iSampleBlock = 0;
8801 20506 : iSampleBlock <
8802 20506 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8803 19566 : iSampleBlock += nSampleRate)
8804 : {
8805 19642 : const int iYBlock =
8806 19642 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8807 19642 : const int iXBlock =
8808 19642 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8809 :
8810 19642 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8811 19642 : if (poBlock == nullptr)
8812 2 : return CE_Failure;
8813 :
8814 19640 : void *const pData = poBlock->GetDataRef();
8815 :
8816 19640 : int nXCheck = 0, nYCheck = 0;
8817 19640 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8818 :
8819 19640 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8820 :
8821 19640 : poBlock->DropLock();
8822 :
8823 19640 : if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8824 4114 : nMax == 255)
8825 74 : break;
8826 : }
8827 : }
8828 : else
8829 : {
8830 209 : const GIntBig nTotalBlocks =
8831 209 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8832 209 : if (!ComputeMinMaxGenericIterBlocks(
8833 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8834 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8835 : {
8836 0 : return CE_Failure;
8837 : }
8838 : }
8839 : }
8840 :
8841 1147 : if (bUseOptimizedPath)
8842 : {
8843 938 : if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8844 : {
8845 937 : dfMin = nMin;
8846 937 : dfMax = nMax;
8847 : }
8848 1 : else if (eDataType == GDT_Int16)
8849 : {
8850 1 : dfMin = nMinInt16;
8851 1 : dfMax = nMaxInt16;
8852 : }
8853 : }
8854 :
8855 1147 : if (dfMin > dfMax)
8856 : {
8857 24 : adfMinMax[0] = 0;
8858 24 : adfMinMax[1] = 0;
8859 24 : ReportError(
8860 : CE_Failure, CPLE_AppDefined,
8861 : "Failed to compute min/max, no valid pixels found in sampling.");
8862 24 : return CE_Failure;
8863 : }
8864 :
8865 1123 : adfMinMax[0] = dfMin;
8866 1123 : adfMinMax[1] = dfMax;
8867 :
8868 1123 : return CE_None;
8869 : }
8870 :
8871 : /************************************************************************/
8872 : /* GDALComputeRasterMinMax() */
8873 : /************************************************************************/
8874 :
8875 : /**
8876 : * \brief Compute the min/max values for a band.
8877 : *
8878 : * @see GDALRasterBand::ComputeRasterMinMax()
8879 : *
8880 : * @note Prior to GDAL 3.6, this function returned void
8881 : */
8882 :
8883 1802 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8884 : double adfMinMax[2])
8885 :
8886 : {
8887 1802 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8888 :
8889 1802 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8890 1802 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8891 : }
8892 :
8893 : /************************************************************************/
8894 : /* ComputeRasterMinMaxLocation() */
8895 : /************************************************************************/
8896 :
8897 : /**
8898 : * \brief Compute the min/max values for a band, and their location.
8899 : *
8900 : * Pixels whose value matches the nodata value or are masked by the mask
8901 : * band are ignored.
8902 : *
8903 : * If the minimum or maximum value is hit in several locations, it is not
8904 : * specified which one will be returned.
8905 : *
8906 : * @param[out] pdfMin Pointer to the minimum value.
8907 : * @param[out] pdfMax Pointer to the maximum value.
8908 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8909 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8910 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8911 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8912 : *
8913 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8914 : * CE_Failure in case of error.
8915 : *
8916 : * @since GDAL 3.11
8917 : */
8918 :
8919 819 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8920 : double *pdfMax, int *pnMinX,
8921 : int *pnMinY, int *pnMaxX,
8922 : int *pnMaxY)
8923 : {
8924 819 : int nMinX = -1;
8925 819 : int nMinY = -1;
8926 819 : int nMaxX = -1;
8927 819 : int nMaxY = -1;
8928 819 : double dfMin = std::numeric_limits<double>::infinity();
8929 819 : double dfMax = -std::numeric_limits<double>::infinity();
8930 819 : if (pdfMin)
8931 816 : *pdfMin = dfMin;
8932 819 : if (pdfMax)
8933 816 : *pdfMax = dfMax;
8934 819 : if (pnMinX)
8935 14 : *pnMinX = nMinX;
8936 819 : if (pnMinY)
8937 14 : *pnMinY = nMinY;
8938 819 : if (pnMaxX)
8939 14 : *pnMaxX = nMaxX;
8940 819 : if (pnMaxY)
8941 14 : *pnMaxY = nMaxY;
8942 :
8943 819 : if (GDALDataTypeIsComplex(eDataType))
8944 : {
8945 0 : CPLError(CE_Failure, CPLE_NotSupported,
8946 : "Complex data type not supported");
8947 0 : return CE_Failure;
8948 : }
8949 :
8950 819 : if (!InitBlockInfo())
8951 0 : return CE_Failure;
8952 :
8953 819 : GDALNoDataValues sNoDataValues(this, eDataType);
8954 819 : GDALRasterBand *poMaskBand = nullptr;
8955 819 : if (!sNoDataValues.bGotNoDataValue)
8956 : {
8957 586 : const int l_nMaskFlags = GetMaskFlags();
8958 587 : if (l_nMaskFlags != GMF_ALL_VALID &&
8959 1 : GetColorInterpretation() != GCI_AlphaBand)
8960 : {
8961 1 : poMaskBand = GetMaskBand();
8962 : }
8963 : }
8964 :
8965 819 : bool bSignedByte = false;
8966 819 : if (eDataType == GDT_UInt8)
8967 : {
8968 7 : EnablePixelTypeSignedByteWarning(false);
8969 : const char *pszPixelType =
8970 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8971 7 : EnablePixelTypeSignedByteWarning(true);
8972 7 : bSignedByte =
8973 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8974 : }
8975 :
8976 819 : GByte *pabyMaskData = nullptr;
8977 819 : if (poMaskBand)
8978 : {
8979 : pabyMaskData =
8980 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8981 1 : if (!pabyMaskData)
8982 : {
8983 0 : return CE_Failure;
8984 : }
8985 : }
8986 :
8987 819 : const GIntBig nTotalBlocks =
8988 819 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8989 819 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8990 819 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8991 8061 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8992 : {
8993 7245 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8994 7245 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8995 :
8996 7245 : int nXCheck = 0, nYCheck = 0;
8997 7245 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8998 :
8999 7247 : if (poMaskBand &&
9000 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
9001 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
9002 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
9003 2 : nBlockXSize, nullptr) != CE_None)
9004 : {
9005 0 : CPLFree(pabyMaskData);
9006 0 : return CE_Failure;
9007 : }
9008 :
9009 7245 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
9010 7245 : if (poBlock == nullptr)
9011 : {
9012 0 : CPLFree(pabyMaskData);
9013 0 : return CE_Failure;
9014 : }
9015 :
9016 7245 : void *const pData = poBlock->GetDataRef();
9017 :
9018 7245 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
9019 : {
9020 5059 : for (int iY = 0; iY < nYCheck; ++iY)
9021 : {
9022 238290 : for (int iX = 0; iX < nXCheck; ++iX)
9023 : {
9024 233478 : const GPtrDiff_t iOffset =
9025 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9026 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
9027 2 : continue;
9028 233476 : bool bValid = true;
9029 : double dfValue =
9030 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
9031 : sNoDataValues, bValid);
9032 233476 : if (!bValid)
9033 0 : continue;
9034 233476 : if (dfValue < dfMin)
9035 : {
9036 606 : dfMin = dfValue;
9037 606 : nMinX = iXBlock * nBlockXSize + iX;
9038 606 : nMinY = iYBlock * nBlockYSize + iY;
9039 : }
9040 233476 : if (dfValue > dfMax)
9041 : {
9042 1515 : dfMax = dfValue;
9043 1515 : nMaxX = iXBlock * nBlockXSize + iX;
9044 1515 : nMaxY = iYBlock * nBlockYSize + iY;
9045 : }
9046 : }
9047 247 : }
9048 : }
9049 : else
9050 : {
9051 6998 : size_t pos_min = 0;
9052 6998 : size_t pos_max = 0;
9053 6998 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
9054 6998 : if (bNeedsMin && bNeedsMax)
9055 : {
9056 13988 : std::tie(pos_min, pos_max) = gdal::minmax_element(
9057 6994 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9058 6994 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
9059 13988 : sNoDataValues.dfNoDataValue);
9060 : }
9061 4 : else if (bNeedsMin)
9062 : {
9063 1 : pos_min = gdal::min_element(
9064 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9065 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
9066 : sNoDataValues.dfNoDataValue);
9067 : }
9068 3 : else if (bNeedsMax)
9069 : {
9070 2 : pos_max = gdal::max_element(
9071 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9072 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
9073 : sNoDataValues.dfNoDataValue);
9074 : }
9075 :
9076 6998 : if (bNeedsMin)
9077 : {
9078 6995 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
9079 6995 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
9080 6995 : bool bValid = true;
9081 : const double dfMinValueBlock =
9082 6995 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9083 : sNoDataValues, bValid);
9084 6995 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9085 : {
9086 1110 : dfMin = dfMinValueBlock;
9087 1110 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
9088 1110 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
9089 : }
9090 : }
9091 :
9092 6998 : if (bNeedsMax)
9093 : {
9094 6996 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9095 6996 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9096 6996 : bool bValid = true;
9097 : const double dfMaxValueBlock =
9098 6996 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9099 : sNoDataValues, bValid);
9100 6996 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9101 : {
9102 1098 : dfMax = dfMaxValueBlock;
9103 1098 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9104 1098 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9105 : }
9106 : }
9107 : }
9108 :
9109 7245 : poBlock->DropLock();
9110 :
9111 7245 : if (eDataType == GDT_UInt8)
9112 : {
9113 10 : if (bNeedsMin && dfMin == 0)
9114 : {
9115 1 : bNeedsMin = false;
9116 : }
9117 10 : if (bNeedsMax && dfMax == 255)
9118 : {
9119 4 : bNeedsMax = false;
9120 : }
9121 10 : if (!bNeedsMin && !bNeedsMax)
9122 : {
9123 3 : break;
9124 : }
9125 : }
9126 : }
9127 :
9128 819 : CPLFree(pabyMaskData);
9129 :
9130 819 : if (pdfMin)
9131 816 : *pdfMin = dfMin;
9132 819 : if (pdfMax)
9133 816 : *pdfMax = dfMax;
9134 819 : if (pnMinX)
9135 14 : *pnMinX = nMinX;
9136 819 : if (pnMinY)
9137 14 : *pnMinY = nMinY;
9138 819 : if (pnMaxX)
9139 14 : *pnMaxX = nMaxX;
9140 819 : if (pnMaxY)
9141 14 : *pnMaxY = nMaxY;
9142 819 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9143 819 : : CE_None;
9144 : }
9145 :
9146 : /************************************************************************/
9147 : /* GDALComputeRasterMinMaxLocation() */
9148 : /************************************************************************/
9149 :
9150 : /**
9151 : * \brief Compute the min/max values for a band, and their location.
9152 : *
9153 : * @see GDALRasterBand::ComputeRasterMinMax()
9154 : * @since GDAL 3.11
9155 : */
9156 :
9157 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9158 : double *pdfMax, int *pnMinX, int *pnMinY,
9159 : int *pnMaxX, int *pnMaxY)
9160 :
9161 : {
9162 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9163 :
9164 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9165 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9166 14 : pnMaxX, pnMaxY);
9167 : }
9168 :
9169 : /************************************************************************/
9170 : /* SetDefaultHistogram() */
9171 : /************************************************************************/
9172 :
9173 : /* FIXME : add proper documentation */
9174 : /**
9175 : * \brief Set default histogram.
9176 : *
9177 : * This method is the same as the C function GDALSetDefaultHistogram() and
9178 : * GDALSetDefaultHistogramEx()
9179 : */
9180 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9181 : double /* dfMax */,
9182 : int /* nBuckets */,
9183 : GUIntBig * /* panHistogram */)
9184 :
9185 : {
9186 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9187 0 : ReportError(CE_Failure, CPLE_NotSupported,
9188 : "SetDefaultHistogram() not implemented for this format.");
9189 :
9190 0 : return CE_Failure;
9191 : }
9192 :
9193 : /************************************************************************/
9194 : /* GDALSetDefaultHistogram() */
9195 : /************************************************************************/
9196 :
9197 : /**
9198 : * \brief Set default histogram.
9199 : *
9200 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9201 : * 2 billion.
9202 : *
9203 : * @see GDALRasterBand::SetDefaultHistogram()
9204 : * @see GDALSetRasterHistogramEx()
9205 : */
9206 :
9207 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9208 : double dfMax, int nBuckets,
9209 : int *panHistogram)
9210 :
9211 : {
9212 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9213 :
9214 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9215 :
9216 : GUIntBig *panHistogramTemp =
9217 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9218 0 : if (panHistogramTemp == nullptr)
9219 : {
9220 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9221 : "Out of memory in GDALSetDefaultHistogram().");
9222 0 : return CE_Failure;
9223 : }
9224 :
9225 0 : for (int i = 0; i < nBuckets; ++i)
9226 : {
9227 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9228 : }
9229 :
9230 : const CPLErr eErr =
9231 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9232 :
9233 0 : CPLFree(panHistogramTemp);
9234 :
9235 0 : return eErr;
9236 : }
9237 :
9238 : /************************************************************************/
9239 : /* GDALSetDefaultHistogramEx() */
9240 : /************************************************************************/
9241 :
9242 : /**
9243 : * \brief Set default histogram.
9244 : *
9245 : * @see GDALRasterBand::SetDefaultHistogram()
9246 : *
9247 : */
9248 :
9249 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9250 : double dfMin, double dfMax,
9251 : int nBuckets,
9252 : GUIntBig *panHistogram)
9253 :
9254 : {
9255 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9256 :
9257 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9258 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9259 : }
9260 :
9261 : /************************************************************************/
9262 : /* GetDefaultRAT() */
9263 : /************************************************************************/
9264 :
9265 : /**
9266 : * \brief Fetch default Raster Attribute Table.
9267 : *
9268 : * A RAT will be returned if there is a default one associated with the
9269 : * band, otherwise NULL is returned. The returned RAT is owned by the
9270 : * band and should not be deleted by the application.
9271 : *
9272 : * This method is the same as the C function GDALGetDefaultRAT().
9273 : *
9274 : * @return NULL, or a pointer to an internal RAT owned by the band.
9275 : */
9276 :
9277 180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9278 :
9279 : {
9280 180 : return nullptr;
9281 : }
9282 :
9283 : /************************************************************************/
9284 : /* GDALGetDefaultRAT() */
9285 : /************************************************************************/
9286 :
9287 : /**
9288 : * \brief Fetch default Raster Attribute Table.
9289 : *
9290 : * @see GDALRasterBand::GetDefaultRAT()
9291 : */
9292 :
9293 1326 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9294 :
9295 : {
9296 1326 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9297 :
9298 1326 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9299 1326 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9300 : }
9301 :
9302 : /************************************************************************/
9303 : /* SetDefaultRAT() */
9304 : /************************************************************************/
9305 :
9306 : /**
9307 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9308 : * \brief Set default Raster Attribute Table.
9309 : *
9310 : * Associates a default RAT with the band. If not implemented for the
9311 : * format a CPLE_NotSupported error will be issued. If successful a copy
9312 : * of the RAT is made, the original remains owned by the caller.
9313 : *
9314 : * This method is the same as the C function GDALSetDefaultRAT().
9315 : *
9316 : * @param poRAT the RAT to assign to the band.
9317 : *
9318 : * @return CE_None on success or CE_Failure if unsupported or otherwise
9319 : * failing.
9320 : */
9321 :
9322 : /**/
9323 : /**/
9324 :
9325 : CPLErr
9326 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9327 : {
9328 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9329 : {
9330 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
9331 0 : ReportError(CE_Failure, CPLE_NotSupported,
9332 : "SetDefaultRAT() not implemented for this format.");
9333 0 : CPLPopErrorHandler();
9334 : }
9335 0 : return CE_Failure;
9336 : }
9337 :
9338 : /************************************************************************/
9339 : /* GDALSetDefaultRAT() */
9340 : /************************************************************************/
9341 :
9342 : /**
9343 : * \brief Set default Raster Attribute Table.
9344 : *
9345 : * @see GDALRasterBand::GDALSetDefaultRAT()
9346 : */
9347 :
9348 65 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9349 : GDALRasterAttributeTableH hRAT)
9350 :
9351 : {
9352 65 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9353 :
9354 65 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9355 :
9356 65 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9357 : }
9358 :
9359 : /************************************************************************/
9360 : /* HasNoData() */
9361 : /************************************************************************/
9362 :
9363 133907 : bool GDALRasterBand::HasNoData() const
9364 : {
9365 133907 : int bHaveNoDataRaw = FALSE;
9366 133907 : bool bHaveNoData = false;
9367 133907 : GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9368 133907 : if (eDataType == GDT_Int64)
9369 : {
9370 212 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9371 212 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9372 : }
9373 133695 : else if (eDataType == GDT_UInt64)
9374 : {
9375 160 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9376 160 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9377 : }
9378 : else
9379 : {
9380 133535 : const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9381 133535 : if (bHaveNoDataRaw &&
9382 133535 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9383 : {
9384 1256 : bHaveNoData = true;
9385 : }
9386 : }
9387 133907 : return bHaveNoData;
9388 : }
9389 :
9390 : /************************************************************************/
9391 : /* GetMaskBand() */
9392 : /************************************************************************/
9393 :
9394 : /**
9395 : * \brief Return the mask band associated with the band.
9396 : *
9397 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9398 : * that returns one of four default implementations :
9399 : * <ul>
9400 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9401 : * </li>
9402 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9403 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9404 : * GMF_NODATA | GMF_PER_DATASET.
9405 : * </li>
9406 : * <li>If the band has a nodata value set, an instance of the new
9407 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9408 : * GMF_NODATA.
9409 : * </li>
9410 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9411 : * to apply to this band (specific rules yet to be determined) and that is of
9412 : * type GDT_UInt8 then that alpha band will be returned, and the flags
9413 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9414 : * </li>
9415 : * <li>If neither of the above apply, an instance of the new
9416 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9417 : * pixels. The null flags will return GMF_ALL_VALID.
9418 : * </li>
9419 : * </ul>
9420 : *
9421 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9422 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9423 : *
9424 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9425 : * dataset, with the same name as the main dataset and suffixed with .msk,
9426 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9427 : * main dataset.
9428 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9429 : * level, where xx matches the band number of a band of the main dataset. The
9430 : * value of those items is a combination of the flags GMF_ALL_VALID,
9431 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9432 : * a band, then the other rules explained above will be used to generate a
9433 : * on-the-fly mask band.
9434 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9435 : *
9436 : * This method is the same as the C function GDALGetMaskBand().
9437 : *
9438 : * @return a valid mask band.
9439 : *
9440 : *
9441 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9442 : *
9443 : */
9444 814602 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9445 :
9446 : {
9447 814602 : if (poMask != nullptr)
9448 : {
9449 714485 : if (poMask.IsOwned())
9450 : {
9451 334404 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9452 : {
9453 33708 : if (HasNoData())
9454 : {
9455 9 : InvalidateMaskBand();
9456 : }
9457 : }
9458 300696 : else if (auto poNoDataMaskBand =
9459 300696 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9460 : {
9461 435 : int bHaveNoDataRaw = FALSE;
9462 435 : bool bIsSame = false;
9463 435 : if (eDataType == GDT_Int64)
9464 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9465 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9466 10 : bHaveNoDataRaw;
9467 418 : else if (eDataType == GDT_UInt64)
9468 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9469 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9470 10 : bHaveNoDataRaw;
9471 : else
9472 : {
9473 : const double dfNoDataValue =
9474 401 : GetNoDataValue(&bHaveNoDataRaw);
9475 401 : if (bHaveNoDataRaw)
9476 : {
9477 398 : bIsSame =
9478 398 : std::isnan(dfNoDataValue)
9479 398 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9480 363 : : poNoDataMaskBand->m_dfNoDataValue ==
9481 : dfNoDataValue;
9482 : }
9483 : }
9484 435 : if (!bIsSame)
9485 23 : InvalidateMaskBand();
9486 : }
9487 : }
9488 :
9489 714485 : if (poMask)
9490 714453 : return poMask.get();
9491 : }
9492 :
9493 : /* -------------------------------------------------------------------- */
9494 : /* Check for a mask in a .msk file. */
9495 : /* -------------------------------------------------------------------- */
9496 100149 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9497 : {
9498 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9499 47 : if (poMask != nullptr)
9500 : {
9501 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9502 45 : return poMask.get();
9503 : }
9504 : }
9505 :
9506 : /* -------------------------------------------------------------------- */
9507 : /* Check for NODATA_VALUES metadata. */
9508 : /* -------------------------------------------------------------------- */
9509 100104 : if (poDS != nullptr)
9510 : {
9511 : const char *pszGDALNoDataValues =
9512 100084 : poDS->GetMetadataItem("NODATA_VALUES");
9513 100084 : if (pszGDALNoDataValues != nullptr)
9514 : {
9515 71 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9516 : pszGDALNoDataValues, " ", FALSE, FALSE);
9517 :
9518 : // Make sure we have as many values as bands.
9519 140 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9520 69 : poDS->GetRasterCount() != 0)
9521 : {
9522 : // Make sure that all bands have the same data type
9523 : // This is clearly not a fundamental condition, just a
9524 : // condition to make implementation easier.
9525 69 : GDALDataType eDT = GDT_Unknown;
9526 69 : int i = 0; // Used after for.
9527 272 : for (; i < poDS->GetRasterCount(); ++i)
9528 : {
9529 203 : if (i == 0)
9530 69 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9531 134 : else if (eDT !=
9532 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9533 : {
9534 0 : break;
9535 : }
9536 : }
9537 69 : if (i == poDS->GetRasterCount())
9538 : {
9539 69 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9540 : try
9541 : {
9542 69 : poMask.reset(
9543 138 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9544 : }
9545 0 : catch (const std::bad_alloc &)
9546 : {
9547 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9548 0 : poMask.reset();
9549 : }
9550 69 : CSLDestroy(papszGDALNoDataValues);
9551 69 : return poMask.get();
9552 : }
9553 : else
9554 : {
9555 0 : ReportError(CE_Warning, CPLE_AppDefined,
9556 : "All bands should have the same type in "
9557 : "order the NODATA_VALUES metadata item "
9558 : "to be used as a mask.");
9559 : }
9560 : }
9561 : else
9562 : {
9563 2 : ReportError(
9564 : CE_Warning, CPLE_AppDefined,
9565 : "NODATA_VALUES metadata item doesn't have the same number "
9566 : "of values as the number of bands. "
9567 : "Ignoring it for mask.");
9568 : }
9569 :
9570 2 : CSLDestroy(papszGDALNoDataValues);
9571 : }
9572 : }
9573 :
9574 : /* -------------------------------------------------------------------- */
9575 : /* Check for nodata case. */
9576 : /* -------------------------------------------------------------------- */
9577 100035 : if (HasNoData())
9578 : {
9579 1246 : nMaskFlags = GMF_NODATA;
9580 : try
9581 : {
9582 1246 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9583 : }
9584 0 : catch (const std::bad_alloc &)
9585 : {
9586 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9587 0 : poMask.reset();
9588 : }
9589 1246 : return poMask.get();
9590 : }
9591 :
9592 : /* -------------------------------------------------------------------- */
9593 : /* Check for alpha case. */
9594 : /* -------------------------------------------------------------------- */
9595 98770 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9596 198187 : this == poDS->GetRasterBand(1) &&
9597 628 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9598 : {
9599 235 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9600 : {
9601 189 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9602 189 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9603 189 : return poMask.get();
9604 : }
9605 46 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9606 : {
9607 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9608 : try
9609 : {
9610 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9611 46 : poDS->GetRasterBand(2)));
9612 : }
9613 0 : catch (const std::bad_alloc &)
9614 : {
9615 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9616 0 : poMask.reset();
9617 : }
9618 23 : return poMask.get();
9619 : }
9620 : }
9621 :
9622 98558 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9623 3250 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9624 197894 : this == poDS->GetRasterBand(3)) &&
9625 2542 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9626 : {
9627 1666 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9628 : {
9629 1610 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9630 1610 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9631 1610 : return poMask.get();
9632 : }
9633 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9634 : {
9635 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9636 : try
9637 : {
9638 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9639 84 : poDS->GetRasterBand(4)));
9640 : }
9641 0 : catch (const std::bad_alloc &)
9642 : {
9643 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9644 0 : poMask.reset();
9645 : }
9646 42 : return poMask.get();
9647 : }
9648 : }
9649 :
9650 : /* -------------------------------------------------------------------- */
9651 : /* Fallback to all valid case. */
9652 : /* -------------------------------------------------------------------- */
9653 96925 : nMaskFlags = GMF_ALL_VALID;
9654 : try
9655 : {
9656 96925 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9657 : }
9658 0 : catch (const std::bad_alloc &)
9659 : {
9660 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9661 0 : poMask.reset();
9662 : }
9663 :
9664 96925 : return poMask.get();
9665 : }
9666 :
9667 : /************************************************************************/
9668 : /* GDALGetMaskBand() */
9669 : /************************************************************************/
9670 :
9671 : /**
9672 : * \brief Return the mask band associated with the band.
9673 : *
9674 : * @see GDALRasterBand::GetMaskBand()
9675 : */
9676 :
9677 11078 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9678 :
9679 : {
9680 11078 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9681 :
9682 11078 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9683 11078 : return poBand->GetMaskBand();
9684 : }
9685 :
9686 : /************************************************************************/
9687 : /* GetMaskFlags() */
9688 : /************************************************************************/
9689 :
9690 : /**
9691 : * \brief Return the status flags of the mask band associated with the band.
9692 : *
9693 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9694 : * the following available definitions that may be extended in the future:
9695 : * <ul>
9696 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9697 : * 255. When used this will normally be the only flag set.
9698 : * </li>
9699 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9700 : * dataset.
9701 : * </li>
9702 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9703 : * and may have values other than 0 and 255.
9704 : * </li>
9705 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9706 : * nodata values. (mutually exclusive of GMF_ALPHA)
9707 : * </li>
9708 : * </ul>
9709 : *
9710 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9711 : * that returns one of four default implementations:
9712 : * <ul>
9713 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9714 : * </li>
9715 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9716 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9717 : * GMF_NODATA | GMF_PER_DATASET.
9718 : * </li>
9719 : * <li>If the band has a nodata value set, an instance of the new
9720 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9721 : * GMF_NODATA.
9722 : * </li>
9723 : * <li>If there is no nodata value, but the dataset has an alpha band that
9724 : * seems to apply to this band (specific rules yet to be determined) and that is
9725 : * of type GDT_UInt8 then that alpha band will be returned, and the flags
9726 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9727 : * </li>
9728 : * <li>If neither of the above apply, an instance of the new
9729 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9730 : * pixels. The null flags will return GMF_ALL_VALID.
9731 : * </li>
9732 : * </ul>
9733 : *
9734 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9735 : * dataset, with the same name as the main dataset and suffixed with .msk,
9736 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9737 : * main dataset.
9738 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9739 : * level, where xx matches the band number of a band of the main dataset. The
9740 : * value of those items is a combination of the flags GMF_ALL_VALID,
9741 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9742 : * a band, then the other rules explained above will be used to generate a
9743 : * on-the-fly mask band.
9744 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9745 : *
9746 : * This method is the same as the C function GDALGetMaskFlags().
9747 : *
9748 : *
9749 : * @return a valid mask band.
9750 : *
9751 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9752 : *
9753 : */
9754 161329 : int GDALRasterBand::GetMaskFlags()
9755 :
9756 : {
9757 : // If we don't have a band yet, force this now so that the masks value
9758 : // will be initialized.
9759 :
9760 161329 : if (poMask == nullptr)
9761 98418 : GetMaskBand();
9762 :
9763 161329 : return nMaskFlags;
9764 : }
9765 :
9766 : /************************************************************************/
9767 : /* GDALGetMaskFlags() */
9768 : /************************************************************************/
9769 :
9770 : /**
9771 : * \brief Return the status flags of the mask band associated with the band.
9772 : *
9773 : * @see GDALRasterBand::GetMaskFlags()
9774 : */
9775 :
9776 9981 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9777 :
9778 : {
9779 9981 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9780 :
9781 9981 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9782 9981 : return poBand->GetMaskFlags();
9783 : }
9784 :
9785 : /************************************************************************/
9786 : /* InvalidateMaskBand() */
9787 : /************************************************************************/
9788 :
9789 : //! @cond Doxygen_Suppress
9790 1860250 : void GDALRasterBand::InvalidateMaskBand()
9791 : {
9792 1860250 : poMask.reset();
9793 1860250 : nMaskFlags = 0;
9794 1860250 : }
9795 :
9796 : //! @endcond
9797 :
9798 : /************************************************************************/
9799 : /* CreateMaskBand() */
9800 : /************************************************************************/
9801 :
9802 : /**
9803 : * \brief Adds a mask band to the current band
9804 : *
9805 : * The default implementation of the CreateMaskBand() method is implemented
9806 : * based on similar rules to the .ovr handling implemented using the
9807 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9808 : * be created with the same basename as the original file, and it will have
9809 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9810 : * The mask images will be deflate compressed tiled images with the same
9811 : * block size as the original image if possible.
9812 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9813 : * level, where xx matches the band number of a band of the main dataset. The
9814 : * value of those items will be the one of the nFlagsIn parameter.
9815 : *
9816 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9817 : * it might be invalidated by CreateMaskBand(). So you have to call
9818 : * GetMaskBand() again.
9819 : *
9820 : * This method is the same as the C function GDALCreateMaskBand().
9821 : *
9822 : *
9823 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9824 : *
9825 : * @return CE_None on success or CE_Failure on an error.
9826 : *
9827 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9828 : * @see GDALDataset::CreateMaskBand()
9829 : *
9830 : */
9831 :
9832 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9833 :
9834 : {
9835 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9836 : {
9837 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9838 10 : if (eErr != CE_None)
9839 1 : return eErr;
9840 :
9841 9 : InvalidateMaskBand();
9842 :
9843 9 : return CE_None;
9844 : }
9845 :
9846 0 : ReportError(CE_Failure, CPLE_NotSupported,
9847 : "CreateMaskBand() not supported for this band.");
9848 :
9849 0 : return CE_Failure;
9850 : }
9851 :
9852 : /************************************************************************/
9853 : /* GDALCreateMaskBand() */
9854 : /************************************************************************/
9855 :
9856 : /**
9857 : * \brief Adds a mask band to the current band
9858 : *
9859 : * @see GDALRasterBand::CreateMaskBand()
9860 : */
9861 :
9862 36 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9863 :
9864 : {
9865 36 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9866 :
9867 36 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9868 36 : return poBand->CreateMaskBand(nFlags);
9869 : }
9870 :
9871 : /************************************************************************/
9872 : /* IsMaskBand() */
9873 : /************************************************************************/
9874 :
9875 : /**
9876 : * \brief Returns whether a band is a mask band.
9877 : *
9878 : * Mask band must be understood in the broad term: it can be a per-dataset
9879 : * mask band, an alpha band, or an implicit mask band.
9880 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9881 : *
9882 : * This method is the same as the C function GDALIsMaskBand().
9883 : *
9884 : * @return true if the band is a mask band.
9885 : *
9886 : * @see GDALDataset::CreateMaskBand()
9887 : *
9888 : * @since GDAL 3.5.0
9889 : *
9890 : */
9891 :
9892 450 : bool GDALRasterBand::IsMaskBand() const
9893 : {
9894 : // The GeoTIFF driver, among others, override this method to
9895 : // also handle external .msk bands.
9896 450 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9897 450 : GCI_AlphaBand;
9898 : }
9899 :
9900 : /************************************************************************/
9901 : /* GDALIsMaskBand() */
9902 : /************************************************************************/
9903 :
9904 : /**
9905 : * \brief Returns whether a band is a mask band.
9906 : *
9907 : * Mask band must be understood in the broad term: it can be a per-dataset
9908 : * mask band, an alpha band, or an implicit mask band.
9909 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9910 : *
9911 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9912 : *
9913 : * @return true if the band is a mask band.
9914 : *
9915 : * @see GDALRasterBand::IsMaskBand()
9916 : *
9917 : * @since GDAL 3.5.0
9918 : *
9919 : */
9920 :
9921 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9922 :
9923 : {
9924 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9925 :
9926 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9927 37 : return poBand->IsMaskBand();
9928 : }
9929 :
9930 : /************************************************************************/
9931 : /* GetMaskValueRange() */
9932 : /************************************************************************/
9933 :
9934 : /**
9935 : * \brief Returns the range of values that a mask band can take.
9936 : *
9937 : * @return the range of values that a mask band can take.
9938 : *
9939 : * @since GDAL 3.5.0
9940 : *
9941 : */
9942 :
9943 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9944 : {
9945 0 : return GMVR_UNKNOWN;
9946 : }
9947 :
9948 : /************************************************************************/
9949 : /* HasConflictingMaskSources() */
9950 : /************************************************************************/
9951 :
9952 : /**
9953 : * \brief Returns whether a raster band has conflicting mask sources.
9954 : *
9955 : * That is, if more than one of the following conditions is met:
9956 : * - it has a binary mask band (that is not an alpha band)
9957 : * - it has an external mask flags (.msk file)
9958 : * - it has a nodata value
9959 : * - it belongs to a dataset with the NODATA_VALUES metadata item set
9960 : * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
9961 : *
9962 : * @param[out] posDetailMessage Pointer to a string that will contain the
9963 : * details of the conflict.
9964 : * @param bMentionPrioritarySource Whether the mask source used should be
9965 : * mentioned in *posDetailMessage.
9966 : * @since GDAL 3.13.0
9967 : */
9968 :
9969 164 : bool GDALRasterBand::HasConflictingMaskSources(
9970 : std::string *posDetailMessage, bool bMentionPrioritarySource) const
9971 : {
9972 164 : const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
9973 : const bool bHasBinaryMaskBand =
9974 164 : ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
9975 186 : (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
9976 22 : (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
9977 164 : const bool bHasNoData = HasNoData();
9978 : const bool bHasNODATA_VALUES =
9979 164 : poDS && poDS->GetMetadataItem("NODATA_VALUES");
9980 : const bool bHasAlphaBand =
9981 324 : poDS &&
9982 160 : poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
9983 164 : GCI_AlphaBand;
9984 : const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
9985 164 : bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
9986 : const size_t nCount =
9987 164 : std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
9988 164 : if (nCount >= 2)
9989 : {
9990 23 : if (posDetailMessage)
9991 : {
9992 17 : *posDetailMessage = "Raster band ";
9993 17 : *posDetailMessage += std::to_string(nBand);
9994 17 : if (poDS && poDS->GetDescription()[0])
9995 : {
9996 11 : *posDetailMessage += " of dataset ";
9997 11 : *posDetailMessage += poDS->GetDescription();
9998 : }
9999 17 : *posDetailMessage += " has several conflicting mask sources:\n";
10000 17 : if (bHasExternalMask)
10001 1 : *posDetailMessage += "- internal binary mask band\n";
10002 17 : if (bHasExternalMask)
10003 1 : *posDetailMessage += "- external mask band (.msk)\n";
10004 17 : if (bHasNoData)
10005 13 : *posDetailMessage += "- nodata value\n";
10006 17 : if (bHasNODATA_VALUES)
10007 9 : *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
10008 17 : if (bHasAlphaBand)
10009 : *posDetailMessage +=
10010 7 : "- related to a raster band that is an alpha band\n";
10011 17 : if (bMentionPrioritarySource)
10012 : *posDetailMessage +=
10013 6 : "Only the first listed one will be taken into account.";
10014 : }
10015 23 : return true;
10016 : }
10017 141 : return false;
10018 : }
10019 :
10020 : /************************************************************************/
10021 : /* GetIndexColorTranslationTo() */
10022 : /************************************************************************/
10023 :
10024 : /**
10025 : * \brief Compute translation table for color tables.
10026 : *
10027 : * When the raster band has a palette index, it may be useful to compute
10028 : * the "translation" of this palette to the palette of another band.
10029 : * The translation tries to do exact matching first, and then approximate
10030 : * matching if no exact matching is possible.
10031 : * This method returns a table such that table[i] = j where i is an index
10032 : * of the 'this' rasterband and j the corresponding index for the reference
10033 : * rasterband.
10034 : *
10035 : * This method is thought as internal to GDAL and is used for drivers
10036 : * like RPFTOC.
10037 : *
10038 : * The implementation only supports 1-byte palette rasterbands.
10039 : *
10040 : * @param poReferenceBand the raster band
10041 : * @param pTranslationTable an already allocated translation table (at least 256
10042 : * bytes), or NULL to let the method allocate it
10043 : * @param pApproximateMatching a pointer to a flag that is set if the matching
10044 : * is approximate. May be NULL.
10045 : *
10046 : * @return a translation table if the two bands are palette index and that they
10047 : * do not match or NULL in other cases. The table must be freed with CPLFree if
10048 : * NULL was passed for pTranslationTable.
10049 : */
10050 :
10051 : unsigned char *
10052 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
10053 : unsigned char *pTranslationTable,
10054 : int *pApproximateMatching)
10055 : {
10056 4 : if (poReferenceBand == nullptr)
10057 0 : return nullptr;
10058 :
10059 : // cppcheck-suppress knownConditionTrueFalse
10060 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
10061 : // cppcheck-suppress knownConditionTrueFalse
10062 4 : GetColorInterpretation() == GCI_PaletteIndex &&
10063 12 : poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
10064 4 : GetRasterDataType() == GDT_UInt8)
10065 : {
10066 4 : const GDALColorTable *srcColorTable = GetColorTable();
10067 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
10068 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
10069 : {
10070 4 : const int nEntries = srcColorTable->GetColorEntryCount();
10071 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
10072 :
10073 4 : int bHasNoDataValueSrc = FALSE;
10074 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
10075 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
10076 4 : dfNoDataValueSrc <= 255 &&
10077 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
10078 0 : bHasNoDataValueSrc = FALSE;
10079 4 : const int noDataValueSrc =
10080 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10081 :
10082 4 : int bHasNoDataValueRef = FALSE;
10083 : const double dfNoDataValueRef =
10084 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10085 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10086 3 : dfNoDataValueRef <= 255 &&
10087 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10088 1 : bHasNoDataValueRef = FALSE;
10089 4 : const int noDataValueRef =
10090 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10091 :
10092 4 : bool samePalette = false;
10093 :
10094 4 : if (pApproximateMatching)
10095 3 : *pApproximateMatching = FALSE;
10096 :
10097 4 : if (nEntries == nRefEntries &&
10098 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
10099 3 : (bHasNoDataValueSrc == FALSE ||
10100 : noDataValueSrc == noDataValueRef))
10101 : {
10102 3 : samePalette = true;
10103 654 : for (int i = 0; i < nEntries; ++i)
10104 : {
10105 651 : if (noDataValueSrc == i)
10106 3 : continue;
10107 : const GDALColorEntry *entry =
10108 648 : srcColorTable->GetColorEntry(i);
10109 : const GDALColorEntry *entryRef =
10110 648 : destColorTable->GetColorEntry(i);
10111 648 : if (entry->c1 != entryRef->c1 ||
10112 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10113 : {
10114 0 : samePalette = false;
10115 : }
10116 : }
10117 : }
10118 :
10119 4 : if (!samePalette)
10120 : {
10121 1 : if (pTranslationTable == nullptr)
10122 : {
10123 : pTranslationTable = static_cast<unsigned char *>(
10124 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10125 1 : if (pTranslationTable == nullptr)
10126 1 : return nullptr;
10127 : }
10128 :
10129 : // Trying to remap the product palette on the subdataset
10130 : // palette.
10131 5 : for (int i = 0; i < nEntries; ++i)
10132 : {
10133 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10134 : noDataValueSrc == i)
10135 0 : continue;
10136 : const GDALColorEntry *entry =
10137 4 : srcColorTable->GetColorEntry(i);
10138 4 : bool bMatchFound = false;
10139 13 : for (int j = 0; j < nRefEntries; ++j)
10140 : {
10141 10 : if (bHasNoDataValueRef && noDataValueRef == j)
10142 0 : continue;
10143 : const GDALColorEntry *entryRef =
10144 10 : destColorTable->GetColorEntry(j);
10145 10 : if (entry->c1 == entryRef->c1 &&
10146 2 : entry->c2 == entryRef->c2 &&
10147 2 : entry->c3 == entryRef->c3)
10148 : {
10149 1 : pTranslationTable[i] =
10150 : static_cast<unsigned char>(j);
10151 1 : bMatchFound = true;
10152 1 : break;
10153 : }
10154 : }
10155 4 : if (!bMatchFound)
10156 : {
10157 : // No exact match. Looking for closest color now.
10158 3 : int best_j = 0;
10159 3 : int best_distance = 0;
10160 3 : if (pApproximateMatching)
10161 0 : *pApproximateMatching = TRUE;
10162 12 : for (int j = 0; j < nRefEntries; ++j)
10163 : {
10164 : const GDALColorEntry *entryRef =
10165 9 : destColorTable->GetColorEntry(j);
10166 9 : int distance = (entry->c1 - entryRef->c1) *
10167 9 : (entry->c1 - entryRef->c1) +
10168 9 : (entry->c2 - entryRef->c2) *
10169 9 : (entry->c2 - entryRef->c2) +
10170 9 : (entry->c3 - entryRef->c3) *
10171 9 : (entry->c3 - entryRef->c3);
10172 9 : if (j == 0 || distance < best_distance)
10173 : {
10174 7 : best_j = j;
10175 7 : best_distance = distance;
10176 : }
10177 : }
10178 3 : pTranslationTable[i] =
10179 : static_cast<unsigned char>(best_j);
10180 : }
10181 : }
10182 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
10183 0 : pTranslationTable[noDataValueSrc] =
10184 : static_cast<unsigned char>(noDataValueRef);
10185 :
10186 1 : return pTranslationTable;
10187 : }
10188 : }
10189 : }
10190 3 : return nullptr;
10191 : }
10192 :
10193 : /************************************************************************/
10194 : /* SetFlushBlockErr() */
10195 : /************************************************************************/
10196 :
10197 : /**
10198 : * \brief Store that an error occurred while writing a dirty block.
10199 : *
10200 : * This function stores the fact that an error occurred while writing a dirty
10201 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10202 : * flushed when the block cache get full, it is not convenient/possible to
10203 : * report that a dirty block could not be written correctly. This function
10204 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10205 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10206 : * places where the user can easily match the error with the relevant dataset.
10207 : */
10208 :
10209 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10210 : {
10211 0 : eFlushBlockErr = eErr;
10212 0 : }
10213 :
10214 : /************************************************************************/
10215 : /* IncDirtyBlocks() */
10216 : /************************************************************************/
10217 :
10218 : /**
10219 : * \brief Increment/decrement the number of dirty blocks
10220 : */
10221 :
10222 816002 : void GDALRasterBand::IncDirtyBlocks(int nInc)
10223 : {
10224 816002 : if (poBandBlockCache)
10225 816002 : poBandBlockCache->IncDirtyBlocks(nInc);
10226 816002 : }
10227 :
10228 : /************************************************************************/
10229 : /* ReportError() */
10230 : /************************************************************************/
10231 :
10232 : #ifndef DOXYGEN_XML
10233 : /**
10234 : * \brief Emits an error related to a raster band.
10235 : *
10236 : * This function is a wrapper for regular CPLError(). The only difference
10237 : * with CPLError() is that it prepends the error message with the dataset
10238 : * name and the band number.
10239 : *
10240 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10241 : * @param err_no the error number (CPLE_*) from cpl_error.h.
10242 : * @param fmt a printf() style format string. Any additional arguments
10243 : * will be treated as arguments to fill in this format in a manner
10244 : * similar to printf().
10245 : *
10246 : */
10247 :
10248 2501 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10249 : const char *fmt, ...) const
10250 : {
10251 : va_list args;
10252 :
10253 2501 : va_start(args, fmt);
10254 :
10255 2501 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
10256 2501 : pszDSName = CPLGetFilename(pszDSName);
10257 2501 : if (pszDSName[0] != '\0')
10258 : {
10259 2408 : CPLError(eErrClass, err_no, "%s",
10260 4816 : CPLString()
10261 2408 : .Printf("%s, band %d: ", pszDSName, GetBand())
10262 4816 : .append(CPLString().vPrintf(fmt, args))
10263 : .c_str());
10264 : }
10265 : else
10266 : {
10267 93 : CPLErrorV(eErrClass, err_no, fmt, args);
10268 : }
10269 :
10270 2501 : va_end(args);
10271 2501 : }
10272 : #endif
10273 :
10274 : /************************************************************************/
10275 : /* GetVirtualMemAuto() */
10276 : /************************************************************************/
10277 :
10278 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10279 : *
10280 : * Only supported on Linux and Unix systems with mmap() for now.
10281 : *
10282 : * This method allows creating a virtual memory object for a GDALRasterBand,
10283 : * that exposes the whole image data as a virtual array.
10284 : *
10285 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10286 : * specialized implementation, such as for raw files, may also directly use
10287 : * mechanisms of the operating system to create a view of the underlying file
10288 : * into virtual memory ( CPLVirtualMemFileMapNew() )
10289 : *
10290 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10291 : * offer a specialized implementation with direct file mapping, provided that
10292 : * some requirements are met :
10293 : * - for all drivers, the dataset must be backed by a "real" file in the file
10294 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10295 : * must match the native ordering of the CPU.
10296 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10297 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10298 : * the file in sequential order, and be equally spaced (which is generally the
10299 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10300 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10301 : *
10302 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
10303 : * CPLVirtualMemFree() must be called before the raster band object is
10304 : * destroyed.
10305 : *
10306 : * If p is such a pointer and base_type the type matching
10307 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10308 : * accessed with
10309 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10310 : *
10311 : * This method is the same as the C GDALGetVirtualMemAuto() function.
10312 : *
10313 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10314 : * read/write the band.
10315 : *
10316 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
10317 : * one pixel value in the buffer to the start of the next pixel value within a
10318 : * scanline.
10319 : *
10320 : * @param pnLineSpace Output parameter giving the byte offset from the start of
10321 : * one scanline in the buffer to the start of the next.
10322 : *
10323 : * @param papszOptions NULL terminated list of options.
10324 : * If a specialized implementation exists, defining
10325 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10326 : * used. On the contrary, defining
10327 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10328 : * being used (thus only allowing efficient implementations to be used). When
10329 : * requiring or falling back to the default implementation, the following
10330 : * options are available : CACHE_SIZE (in bytes, defaults to
10331 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10332 : * to FALSE)
10333 : *
10334 : * @return a virtual memory object that must be unreferenced by
10335 : * CPLVirtualMemFree(), or NULL in case of failure.
10336 : *
10337 : */
10338 :
10339 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10340 : int *pnPixelSpace,
10341 : GIntBig *pnLineSpace,
10342 : CSLConstList papszOptions)
10343 : {
10344 9 : const char *pszImpl = CSLFetchNameValueDef(
10345 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10346 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10347 8 : EQUAL(pszImpl, "FALSE"))
10348 : {
10349 1 : return nullptr;
10350 : }
10351 :
10352 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10353 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10354 8 : if (pnPixelSpace)
10355 8 : *pnPixelSpace = nPixelSpace;
10356 8 : if (pnLineSpace)
10357 8 : *pnLineSpace = nLineSpace;
10358 : const size_t nCacheSize =
10359 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10360 : const size_t nPageSizeHint =
10361 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10362 8 : const bool bSingleThreadUsage = CPLTestBool(
10363 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10364 8 : return GDALRasterBandGetVirtualMem(
10365 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10366 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10367 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10368 8 : papszOptions);
10369 : }
10370 :
10371 : /************************************************************************/
10372 : /* GDALGetVirtualMemAuto() */
10373 : /************************************************************************/
10374 :
10375 : /**
10376 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10377 : *
10378 : * @see GDALRasterBand::GetVirtualMemAuto()
10379 : */
10380 :
10381 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10382 : int *pnPixelSpace, GIntBig *pnLineSpace,
10383 : CSLConstList papszOptions)
10384 : {
10385 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10386 :
10387 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10388 :
10389 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10390 31 : const_cast<char **>(papszOptions));
10391 : }
10392 :
10393 : /************************************************************************/
10394 : /* GDALGetDataCoverageStatus() */
10395 : /************************************************************************/
10396 :
10397 : /**
10398 : * \brief Get the coverage status of a sub-window of the raster.
10399 : *
10400 : * Returns whether a sub-window of the raster contains only data, only empty
10401 : * blocks or a mix of both. This function can be used to determine quickly
10402 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10403 : * be sparse.
10404 : *
10405 : * Empty blocks are blocks that are generally not physically present in the
10406 : * file, and when read through GDAL, contain only pixels whose value is the
10407 : * nodata value when it is set, or whose value is 0 when the nodata value is
10408 : * not set.
10409 : *
10410 : * The query is done in an efficient way without reading the actual pixel
10411 : * values. If not possible, or not implemented at all by the driver,
10412 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10413 : * be returned.
10414 : *
10415 : * The values that can be returned by the function are the following,
10416 : * potentially combined with the binary or operator :
10417 : * <ul>
10418 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10419 : * GetDataCoverageStatus(). This flag should be returned together with
10420 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10421 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10422 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10423 : * the queried window. This is typically identified by the concept of missing
10424 : * block in formats that supports it.
10425 : * </li>
10426 : * </ul>
10427 : *
10428 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10429 : * should be interpreted more as hint of potential presence of data. For example
10430 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10431 : * nodata value), instead of using the missing block mechanism,
10432 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10433 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10434 : *
10435 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10436 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10437 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10438 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10439 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10440 : * the function will exit, so that you can potentially refine the requested area
10441 : * to find which particular region(s) have missing blocks.
10442 : *
10443 : * @see GDALRasterBand::GetDataCoverageStatus()
10444 : *
10445 : * @param hBand raster band
10446 : *
10447 : * @param nXOff The pixel offset to the top left corner of the region
10448 : * of the band to be queried. This would be zero to start from the left side.
10449 : *
10450 : * @param nYOff The line offset to the top left corner of the region
10451 : * of the band to be queried. This would be zero to start from the top.
10452 : *
10453 : * @param nXSize The width of the region of the band to be queried in pixels.
10454 : *
10455 : * @param nYSize The height of the region of the band to be queried in lines.
10456 : *
10457 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10458 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10459 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10460 : * as the computation of the coverage matches the mask, the computation will be
10461 : * stopped. *pdfDataPct will not be valid in that case.
10462 : *
10463 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10464 : * to the (approximate) percentage in [0,100] of pixels in the queried
10465 : * sub-window that have valid values. The implementation might not always be
10466 : * able to compute it, in which case it will be set to a negative value.
10467 : *
10468 : * @return a binary-or'ed combination of possible values
10469 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10470 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10471 : */
10472 :
10473 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10474 : int nYOff, int nXSize, int nYSize,
10475 : int nMaskFlagStop, double *pdfDataPct)
10476 : {
10477 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10478 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10479 :
10480 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10481 :
10482 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10483 29 : nMaskFlagStop, pdfDataPct);
10484 : }
10485 :
10486 : /************************************************************************/
10487 : /* GetDataCoverageStatus() */
10488 : /************************************************************************/
10489 :
10490 : /**
10491 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10492 : * int nYOff,
10493 : * int nXSize,
10494 : * int nYSize,
10495 : * int nMaskFlagStop,
10496 : * double* pdfDataPct)
10497 : * \brief Get the coverage status of a sub-window of the raster.
10498 : *
10499 : * Returns whether a sub-window of the raster contains only data, only empty
10500 : * blocks or a mix of both. This function can be used to determine quickly
10501 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10502 : * be sparse.
10503 : *
10504 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10505 : * value when it is set, or whose value is 0 when the nodata value is not set.
10506 : *
10507 : * The query is done in an efficient way without reading the actual pixel
10508 : * values. If not possible, or not implemented at all by the driver,
10509 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10510 : * be returned.
10511 : *
10512 : * The values that can be returned by the function are the following,
10513 : * potentially combined with the binary or operator :
10514 : * <ul>
10515 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10516 : * GetDataCoverageStatus(). This flag should be returned together with
10517 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10518 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10519 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10520 : * the queried window. This is typically identified by the concept of missing
10521 : * block in formats that supports it.
10522 : * </li>
10523 : * </ul>
10524 : *
10525 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10526 : * should be interpreted more as hint of potential presence of data. For example
10527 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10528 : * nodata value), instead of using the missing block mechanism,
10529 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10530 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10531 : *
10532 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10533 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10534 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10535 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10536 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10537 : * the function will exit, so that you can potentially refine the requested area
10538 : * to find which particular region(s) have missing blocks.
10539 : *
10540 : * @see GDALGetDataCoverageStatus()
10541 : *
10542 : * @param nXOff The pixel offset to the top left corner of the region
10543 : * of the band to be queried. This would be zero to start from the left side.
10544 : *
10545 : * @param nYOff The line offset to the top left corner of the region
10546 : * of the band to be queried. This would be zero to start from the top.
10547 : *
10548 : * @param nXSize The width of the region of the band to be queried in pixels.
10549 : *
10550 : * @param nYSize The height of the region of the band to be queried in lines.
10551 : *
10552 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10553 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10554 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10555 : * as the computation of the coverage matches the mask, the computation will be
10556 : * stopped. *pdfDataPct will not be valid in that case.
10557 : *
10558 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10559 : * to the (approximate) percentage in [0,100] of pixels in the queried
10560 : * sub-window that have valid values. The implementation might not always be
10561 : * able to compute it, in which case it will be set to a negative value.
10562 : *
10563 : * @return a binary-or'ed combination of possible values
10564 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10565 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10566 : */
10567 :
10568 : /**
10569 : * \brief Get the coverage status of a sub-window of the raster.
10570 : *
10571 : * Returns whether a sub-window of the raster contains only data, only empty
10572 : * blocks or a mix of both. This function can be used to determine quickly
10573 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10574 : * be sparse.
10575 : *
10576 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10577 : * value when it is set, or whose value is 0 when the nodata value is not set.
10578 : *
10579 : * The query is done in an efficient way without reading the actual pixel
10580 : * values. If not possible, or not implemented at all by the driver,
10581 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10582 : * be returned.
10583 : *
10584 : * The values that can be returned by the function are the following,
10585 : * potentially combined with the binary or operator :
10586 : * <ul>
10587 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10588 : * GetDataCoverageStatus(). This flag should be returned together with
10589 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10590 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10591 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10592 : * the queried window. This is typically identified by the concept of missing
10593 : * block in formats that supports it.
10594 : * </li>
10595 : * </ul>
10596 : *
10597 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10598 : * should be interpreted more as hint of potential presence of data. For example
10599 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10600 : * nodata value), instead of using the missing block mechanism,
10601 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10602 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10603 : *
10604 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10605 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10606 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10607 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10608 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10609 : * the function will exit, so that you can potentially refine the requested area
10610 : * to find which particular region(s) have missing blocks.
10611 : *
10612 : * @see GDALGetDataCoverageStatus()
10613 : *
10614 : * @param nXOff The pixel offset to the top left corner of the region
10615 : * of the band to be queried. This would be zero to start from the left side.
10616 : *
10617 : * @param nYOff The line offset to the top left corner of the region
10618 : * of the band to be queried. This would be zero to start from the top.
10619 : *
10620 : * @param nXSize The width of the region of the band to be queried in pixels.
10621 : *
10622 : * @param nYSize The height of the region of the band to be queried in lines.
10623 : *
10624 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10625 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10626 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10627 : * as the computation of the coverage matches the mask, the computation will be
10628 : * stopped. *pdfDataPct will not be valid in that case.
10629 : *
10630 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10631 : * to the (approximate) percentage in [0,100] of pixels in the queried
10632 : * sub-window that have valid values. The implementation might not always be
10633 : * able to compute it, in which case it will be set to a negative value.
10634 : *
10635 : * @return a binary-or'ed combination of possible values
10636 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10637 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10638 : */
10639 :
10640 4736 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10641 : int nYSize, int nMaskFlagStop,
10642 : double *pdfDataPct)
10643 : {
10644 4736 : if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10645 4736 : nYSize > nRasterYSize - nYOff)
10646 : {
10647 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10648 0 : if (pdfDataPct)
10649 0 : *pdfDataPct = 0.0;
10650 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10651 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10652 : }
10653 4736 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10654 4736 : pdfDataPct);
10655 : }
10656 :
10657 : /************************************************************************/
10658 : /* IGetDataCoverageStatus() */
10659 : /************************************************************************/
10660 :
10661 692 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10662 : int /*nXSize*/, int /*nYSize*/,
10663 : int /*nMaskFlagStop*/,
10664 : double *pdfDataPct)
10665 : {
10666 692 : if (pdfDataPct != nullptr)
10667 0 : *pdfDataPct = 100.0;
10668 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10669 692 : GDAL_DATA_COVERAGE_STATUS_DATA;
10670 : }
10671 :
10672 : //! @cond Doxygen_Suppress
10673 : /************************************************************************/
10674 : /* EnterReadWrite() */
10675 : /************************************************************************/
10676 :
10677 8074550 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10678 : {
10679 8074550 : if (poDS != nullptr)
10680 7305990 : return poDS->EnterReadWrite(eRWFlag);
10681 768558 : return FALSE;
10682 : }
10683 :
10684 : /************************************************************************/
10685 : /* LeaveReadWrite() */
10686 : /************************************************************************/
10687 :
10688 1144700 : void GDALRasterBand::LeaveReadWrite()
10689 : {
10690 1144700 : if (poDS != nullptr)
10691 1144700 : poDS->LeaveReadWrite();
10692 1144700 : }
10693 :
10694 : /************************************************************************/
10695 : /* InitRWLock() */
10696 : /************************************************************************/
10697 :
10698 3989070 : void GDALRasterBand::InitRWLock()
10699 : {
10700 3989070 : if (poDS != nullptr)
10701 3988660 : poDS->InitRWLock();
10702 3989070 : }
10703 :
10704 : //! @endcond
10705 :
10706 : // clang-format off
10707 :
10708 : /**
10709 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10710 : * \brief Set metadata.
10711 : *
10712 : * CAUTION: depending on the format, older values of the updated information
10713 : * might still be found in the file in a "ghost" state, even if no longer
10714 : * accessible through the GDAL API. This is for example the case of the GTiff
10715 : * format (this is not a exhaustive list)
10716 : *
10717 : * The C function GDALSetMetadata() does the same thing as this method.
10718 : *
10719 : * @param papszMetadata the metadata in name=value string list format to
10720 : * apply.
10721 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10722 : * domain.
10723 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10724 : * metadata has been accepted, but is likely not maintained persistently
10725 : * by the underlying object between sessions.
10726 : */
10727 :
10728 : /**
10729 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10730 : * \brief Set single metadata item.
10731 : *
10732 : * CAUTION: depending on the format, older values of the updated information
10733 : * might still be found in the file in a "ghost" state, even if no longer
10734 : * accessible through the GDAL API. This is for example the case of the GTiff
10735 : * format (this is not a exhaustive list)
10736 : *
10737 : * The C function GDALSetMetadataItem() does the same thing as this method.
10738 : *
10739 : * @param pszName the key for the metadata item to fetch.
10740 : * @param pszValue the value to assign to the key.
10741 : * @param pszDomain the domain to set within, use NULL for the default domain.
10742 : *
10743 : * @return CE_None on success, or an error code on failure.
10744 : */
10745 :
10746 : // clang-format on
10747 :
10748 : //! @cond Doxygen_Suppress
10749 : /************************************************************************/
10750 : /* EnablePixelTypeSignedByteWarning() */
10751 : /************************************************************************/
10752 :
10753 157773 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10754 : {
10755 157773 : m_bEnablePixelTypeSignedByteWarning = b;
10756 157773 : }
10757 :
10758 4920 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10759 : {
10760 4920 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10761 4920 : }
10762 :
10763 : //! @endcond
10764 :
10765 : /************************************************************************/
10766 : /* GetMetadataItem() */
10767 : /************************************************************************/
10768 :
10769 622577 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10770 : const char *pszDomain)
10771 : {
10772 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10773 622577 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10774 463217 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10775 322515 : EQUAL(pszName, "PIXELTYPE"))
10776 : {
10777 2 : CPLError(CE_Warning, CPLE_AppDefined,
10778 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10779 : "used to signal signed 8-bit raster. Change your code to "
10780 : "test for the new GDT_Int8 data type instead.");
10781 : }
10782 622577 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10783 : }
10784 :
10785 : /************************************************************************/
10786 : /* WindowIterator */
10787 : /************************************************************************/
10788 :
10789 : //! @cond Doxygen_Suppress
10790 :
10791 696 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10792 : int nRasterYSize,
10793 : int nBlockXSize, int nBlockYSize,
10794 696 : int nRow, int nCol)
10795 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10796 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10797 696 : m_col(nCol)
10798 : {
10799 696 : }
10800 :
10801 751 : bool GDALRasterBand::WindowIterator::operator==(
10802 : const WindowIterator &other) const
10803 : {
10804 310 : return m_row == other.m_row && m_col == other.m_col &&
10805 310 : m_nRasterXSize == other.m_nRasterXSize &&
10806 310 : m_nRasterYSize == other.m_nRasterYSize &&
10807 1371 : m_nBlockXSize == other.m_nBlockXSize &&
10808 1061 : m_nBlockYSize == other.m_nBlockYSize;
10809 : }
10810 :
10811 727 : bool GDALRasterBand::WindowIterator::operator!=(
10812 : const WindowIterator &other) const
10813 : {
10814 727 : return !(*this == other);
10815 : }
10816 :
10817 : GDALRasterBand::WindowIterator::value_type
10818 440 : GDALRasterBand::WindowIterator::operator*() const
10819 : {
10820 : GDALRasterWindow ret;
10821 440 : ret.nXOff = m_col * m_nBlockXSize;
10822 440 : ret.nYOff = m_row * m_nBlockYSize;
10823 440 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10824 440 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10825 :
10826 440 : return ret;
10827 : }
10828 :
10829 431 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10830 : {
10831 431 : m_col++;
10832 431 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10833 : {
10834 335 : m_col = 0;
10835 335 : m_row++;
10836 : }
10837 431 : return *this;
10838 : }
10839 :
10840 163 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10841 163 : const GDALRasterBand &band, size_t maxSize)
10842 163 : : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10843 163 : band.nBlockYSize, maxSize)
10844 : {
10845 163 : }
10846 :
10847 201 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10848 201 : const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10849 201 : : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10850 201 : std::min(band1.GetYSize(), band2.GetYSize()),
10851 201 : std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10852 201 : std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10853 603 : maxSize)
10854 : {
10855 402 : if (band1.GetXSize() != band2.GetXSize() ||
10856 201 : band1.GetYSize() != band2.GetYSize())
10857 : {
10858 0 : CPLError(CE_Warning, CPLE_AppDefined,
10859 : "WindowIteratorWrapper called on bands of different "
10860 : "dimensions. Selecting smallest one");
10861 : }
10862 201 : }
10863 :
10864 364 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10865 : int nRasterYSize,
10866 : int nBlockXSize,
10867 : int nBlockYSize,
10868 364 : size_t maxSize)
10869 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10870 364 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10871 : {
10872 : #ifdef CSA_BUILD
10873 : assert(this);
10874 : #endif
10875 364 : int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10876 364 : int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10877 :
10878 364 : if (nXSize < 1 || nYSize < 1)
10879 : {
10880 : // If invalid block size is reported, assume scanlines
10881 8 : nXSize = m_nRasterXSize;
10882 8 : nYSize = 1;
10883 : }
10884 :
10885 364 : if (maxSize == 0)
10886 : {
10887 69 : m_nBlockXSize = nXSize;
10888 69 : m_nBlockYSize = nYSize;
10889 69 : return;
10890 : }
10891 :
10892 295 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10893 295 : const double dfBlocksPerChunk =
10894 295 : static_cast<double>(maxSize) /
10895 295 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10896 :
10897 295 : if (dfBlocksPerChunk < dfBlocksPerRow)
10898 : {
10899 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10900 14 : m_nRasterXSize,
10901 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10902 14 : m_nBlockYSize = nYSize;
10903 : }
10904 : else
10905 : {
10906 281 : m_nBlockXSize = m_nRasterXSize;
10907 281 : m_nBlockYSize = static_cast<int>(std::min<double>(
10908 281 : m_nRasterYSize,
10909 281 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10910 : }
10911 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10912 : {
10913 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10914 : {
10915 : m_nBlockXSize = m_nRasterXSize;
10916 : m_nBlockYSize = 1;
10917 : }
10918 : }
10919 : }
10920 :
10921 : GDALRasterBand::WindowIterator
10922 333 : GDALRasterBand::WindowIteratorWrapper::begin() const
10923 : {
10924 333 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10925 333 : m_nBlockYSize, 0, 0);
10926 : }
10927 :
10928 : GDALRasterBand::WindowIterator
10929 333 : GDALRasterBand::WindowIteratorWrapper::end() const
10930 : {
10931 333 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10932 333 : m_nBlockYSize,
10933 333 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10934 : }
10935 :
10936 63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10937 : {
10938 63 : return static_cast<uint64_t>(
10939 63 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10940 63 : static_cast<uint64_t>(
10941 63 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10942 : }
10943 :
10944 : //! @endcond
10945 :
10946 : /** Return an object whose begin() and end() methods can be used to iterate
10947 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10948 : * band. The iteration order is from left to right, then from top to bottom.
10949 : *
10950 : \code{.cpp}
10951 : std::vector<double> pixelValues;
10952 : for (const auto& window : poBand->IterateWindows()) {
10953 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10954 : window.nXSize, window.nYSize);
10955 : // check eErr
10956 : }
10957 : \endcode
10958 : *
10959 : *
10960 : * @param maxSize The maximum number of pixels in each window. If set to
10961 : * zero (the default), or a number smaller than the block size,
10962 : * the window size will be the same as the block size.
10963 : * @since GDAL 3.12
10964 : */
10965 : GDALRasterBand::WindowIteratorWrapper
10966 163 : GDALRasterBand::IterateWindows(size_t maxSize) const
10967 : {
10968 163 : return WindowIteratorWrapper(*this, maxSize);
10969 : }
10970 :
10971 : /************************************************************************/
10972 : /* MayMultiBlockReadingBeMultiThreaded() */
10973 : /************************************************************************/
10974 :
10975 : /** Return whether a RasterIO(GF_Read) request spanning over multiple
10976 : * blocks may be accelerated internally using multi-threading.
10977 : *
10978 : * This can be used to determine the best chunk size to read a raster band.
10979 : *
10980 : * Note that such optimizations may require that the window is perfectly aligned
10981 : * on block boundaries and does not involve resampling or data type translation
10982 : * occurs, etc.
10983 : *
10984 : * @since GDAL 3.13
10985 : */
10986 0 : bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
10987 : {
10988 0 : return false;
10989 : }
10990 :
10991 : /************************************************************************/
10992 : /* GDALMDArrayFromRasterBand */
10993 : /************************************************************************/
10994 :
10995 : class GDALMDArrayFromRasterBand final : public GDALMDArray
10996 : {
10997 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10998 :
10999 : GDALDataset *m_poDS;
11000 : GDALRasterBand *m_poBand;
11001 : GDALExtendedDataType m_dt;
11002 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11003 : std::string m_osUnit;
11004 : std::vector<GByte> m_pabyNoData{};
11005 : std::shared_ptr<GDALMDArray> m_varX{};
11006 : std::shared_ptr<GDALMDArray> m_varY{};
11007 : std::string m_osFilename{};
11008 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11009 :
11010 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11011 : const size_t *count, const GInt64 *arrayStep,
11012 : const GPtrDiff_t *bufferStride,
11013 : const GDALExtendedDataType &bufferDataType,
11014 : void *pBuffer) const;
11015 :
11016 : protected:
11017 36 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
11018 72 : : GDALAbstractMDArray(std::string(),
11019 72 : std::string(poDS->GetDescription()) +
11020 : CPLSPrintf(" band %d", poBand->GetBand())),
11021 72 : GDALMDArray(std::string(),
11022 72 : std::string(poDS->GetDescription()) +
11023 : CPLSPrintf(" band %d", poBand->GetBand())),
11024 : m_poDS(poDS), m_poBand(poBand),
11025 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
11026 180 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
11027 : {
11028 36 : m_poDS->Reference();
11029 :
11030 36 : int bHasNoData = false;
11031 36 : if (m_poBand->GetRasterDataType() == GDT_Int64)
11032 : {
11033 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
11034 0 : if (bHasNoData)
11035 : {
11036 0 : m_pabyNoData.resize(m_dt.GetSize());
11037 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
11038 : m_dt.GetNumericDataType(), 0, 1);
11039 : }
11040 : }
11041 36 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
11042 : {
11043 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
11044 0 : if (bHasNoData)
11045 : {
11046 0 : m_pabyNoData.resize(m_dt.GetSize());
11047 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
11048 : m_dt.GetNumericDataType(), 0, 1);
11049 : }
11050 : }
11051 : else
11052 : {
11053 36 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
11054 36 : if (bHasNoData)
11055 : {
11056 1 : m_pabyNoData.resize(m_dt.GetSize());
11057 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
11058 : m_dt.GetNumericDataType(), 0, 1);
11059 : }
11060 : }
11061 :
11062 36 : const int nXSize = poBand->GetXSize();
11063 36 : const int nYSize = poBand->GetYSize();
11064 :
11065 36 : auto poSRS = m_poDS->GetSpatialRef();
11066 72 : std::string osTypeY;
11067 72 : std::string osTypeX;
11068 72 : std::string osDirectionY;
11069 72 : std::string osDirectionX;
11070 36 : if (poSRS && poSRS->GetAxesCount() == 2)
11071 : {
11072 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11073 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
11074 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11075 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
11076 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11077 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11078 : {
11079 8 : if (mapping == std::vector<int>{1, 2})
11080 : {
11081 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11082 8 : osDirectionY = "NORTH";
11083 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11084 8 : osDirectionX = "EAST";
11085 : }
11086 : }
11087 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11088 : {
11089 16 : if (mapping == std::vector<int>{2, 1})
11090 : {
11091 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11092 16 : osDirectionY = "NORTH";
11093 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11094 16 : osDirectionX = "EAST";
11095 : }
11096 : }
11097 : }
11098 :
11099 180 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11100 : "/", "Y", osTypeY, osDirectionY, nYSize),
11101 72 : std::make_shared<GDALDimensionWeakIndexingVar>(
11102 108 : "/", "X", osTypeX, osDirectionX, nXSize)};
11103 :
11104 36 : GDALGeoTransform gt;
11105 36 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
11106 : {
11107 50 : m_varX = GDALMDArrayRegularlySpaced::Create(
11108 50 : "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
11109 25 : m_dims[1]->SetIndexingVariable(m_varX);
11110 :
11111 50 : m_varY = GDALMDArrayRegularlySpaced::Create(
11112 50 : "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
11113 25 : m_dims[0]->SetIndexingVariable(m_varY);
11114 : }
11115 36 : }
11116 :
11117 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11118 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11119 : const GDALExtendedDataType &bufferDataType,
11120 : void *pDstBuffer) const override;
11121 :
11122 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11123 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11124 : const GDALExtendedDataType &bufferDataType,
11125 : const void *pSrcBuffer) override
11126 : {
11127 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11128 : bufferStride, bufferDataType,
11129 1 : const_cast<void *>(pSrcBuffer));
11130 : }
11131 :
11132 : public:
11133 72 : ~GDALMDArrayFromRasterBand() override
11134 36 : {
11135 36 : m_poDS->ReleaseRef();
11136 72 : }
11137 :
11138 36 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11139 : GDALRasterBand *poBand)
11140 : {
11141 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11142 72 : new GDALMDArrayFromRasterBand(poDS, poBand)));
11143 36 : array->SetSelf(array);
11144 72 : return array;
11145 : }
11146 :
11147 5 : bool IsWritable() const override
11148 : {
11149 5 : return m_poDS->GetAccess() == GA_Update;
11150 : }
11151 :
11152 122 : const std::string &GetFilename() const override
11153 : {
11154 122 : return m_osFilename;
11155 : }
11156 :
11157 : const std::vector<std::shared_ptr<GDALDimension>> &
11158 345 : GetDimensions() const override
11159 : {
11160 345 : return m_dims;
11161 : }
11162 :
11163 158 : const GDALExtendedDataType &GetDataType() const override
11164 : {
11165 158 : return m_dt;
11166 : }
11167 :
11168 5 : const std::string &GetUnit() const override
11169 : {
11170 5 : return m_osUnit;
11171 : }
11172 :
11173 32 : const void *GetRawNoDataValue() const override
11174 : {
11175 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11176 : }
11177 :
11178 4 : double GetOffset(bool *pbHasOffset,
11179 : GDALDataType *peStorageType) const override
11180 : {
11181 4 : int bHasOffset = false;
11182 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
11183 4 : if (pbHasOffset)
11184 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11185 4 : if (peStorageType)
11186 1 : *peStorageType = GDT_Unknown;
11187 4 : return dfRes;
11188 : }
11189 :
11190 4 : double GetScale(bool *pbHasScale,
11191 : GDALDataType *peStorageType) const override
11192 : {
11193 4 : int bHasScale = false;
11194 4 : double dfRes = m_poBand->GetScale(&bHasScale);
11195 4 : if (pbHasScale)
11196 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
11197 4 : if (peStorageType)
11198 1 : *peStorageType = GDT_Unknown;
11199 4 : return dfRes;
11200 : }
11201 :
11202 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11203 : {
11204 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
11205 88 : if (!poSrcSRS)
11206 2 : return nullptr;
11207 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11208 :
11209 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11210 86 : constexpr int iYDim = 0;
11211 86 : constexpr int iXDim = 1;
11212 258 : for (auto &m : axisMapping)
11213 : {
11214 172 : if (m == 1)
11215 86 : m = iXDim + 1;
11216 86 : else if (m == 2)
11217 86 : m = iYDim + 1;
11218 : else
11219 0 : m = 0;
11220 : }
11221 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11222 86 : return poSRS;
11223 : }
11224 :
11225 32 : std::vector<GUInt64> GetBlockSize() const override
11226 : {
11227 32 : int nBlockXSize = 0;
11228 32 : int nBlockYSize = 0;
11229 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11230 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11231 32 : static_cast<GUInt64>(nBlockXSize)};
11232 : }
11233 :
11234 : std::vector<std::shared_ptr<GDALAttribute>>
11235 23 : GetAttributes(CSLConstList) const override
11236 : {
11237 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
11238 23 : auto papszMD = m_poBand->GetMetadata();
11239 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
11240 : {
11241 2 : char *pszKey = nullptr;
11242 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11243 2 : if (pszKey && pszValue)
11244 : {
11245 : res.emplace_back(
11246 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11247 : }
11248 2 : CPLFree(pszKey);
11249 : }
11250 23 : return res;
11251 : }
11252 :
11253 6 : int GetOverviewCount() const override
11254 : {
11255 6 : return m_poBand->GetOverviewCount();
11256 : }
11257 :
11258 4 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11259 : {
11260 4 : const int nOverviews = GetOverviewCount();
11261 4 : if (idx < 0 || idx >= nOverviews)
11262 2 : return nullptr;
11263 2 : m_apoOverviews.resize(nOverviews);
11264 2 : if (!m_apoOverviews[idx])
11265 : {
11266 1 : if (auto poOvrBand = m_poBand->GetOverview(idx))
11267 : {
11268 1 : if (auto poOvrDS = poOvrBand->GetDataset())
11269 : {
11270 1 : m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11271 : }
11272 : }
11273 : }
11274 2 : return m_apoOverviews[idx];
11275 : }
11276 : };
11277 :
11278 39 : bool GDALMDArrayFromRasterBand::IRead(
11279 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11280 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11281 : void *pDstBuffer) const
11282 : {
11283 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11284 39 : bufferDataType, pDstBuffer);
11285 : }
11286 :
11287 : /************************************************************************/
11288 : /* ReadWrite() */
11289 : /************************************************************************/
11290 :
11291 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
11292 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11293 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11294 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11295 : {
11296 40 : constexpr size_t iDimX = 1;
11297 40 : constexpr size_t iDimY = 0;
11298 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11299 : arrayStartIdx, count, arrayStep, bufferStride,
11300 40 : bufferDataType, pBuffer);
11301 : }
11302 :
11303 : /************************************************************************/
11304 : /* GDALMDRasterIOFromBand() */
11305 : /************************************************************************/
11306 :
11307 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11308 : size_t iDimX, size_t iDimY,
11309 : const GUInt64 *arrayStartIdx, const size_t *count,
11310 : const GInt64 *arrayStep,
11311 : const GPtrDiff_t *bufferStride,
11312 : const GDALExtendedDataType &bufferDataType,
11313 : void *pBuffer)
11314 : {
11315 73 : const auto eDT(bufferDataType.GetNumericDataType());
11316 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11317 73 : const int nX =
11318 73 : arrayStep[iDimX] > 0
11319 73 : ? static_cast<int>(arrayStartIdx[iDimX])
11320 2 : : static_cast<int>(arrayStartIdx[iDimX] -
11321 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
11322 73 : const int nY =
11323 73 : arrayStep[iDimY] > 0
11324 73 : ? static_cast<int>(arrayStartIdx[iDimY])
11325 6 : : static_cast<int>(arrayStartIdx[iDimY] -
11326 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
11327 73 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
11328 73 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
11329 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11330 73 : int nStrideXSign = 1;
11331 73 : if (arrayStep[iDimX] < 0)
11332 : {
11333 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11334 2 : nStrideXSign = -1;
11335 : }
11336 73 : int nStrideYSign = 1;
11337 73 : if (arrayStep[iDimY] < 0)
11338 : {
11339 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11340 6 : nStrideYSign = -1;
11341 : }
11342 :
11343 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11344 73 : static_cast<int>(count[iDimX]),
11345 73 : static_cast<int>(count[iDimY]), eDT,
11346 : static_cast<GSpacing>(
11347 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
11348 : static_cast<GSpacing>(
11349 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
11350 73 : nullptr) == CE_None;
11351 : }
11352 :
11353 : /************************************************************************/
11354 : /* AsMDArray() */
11355 : /************************************************************************/
11356 :
11357 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11358 : *
11359 : * The band must be linked to a GDALDataset. If this dataset is not already
11360 : * marked as shared, it will be, so that the returned array holds a reference
11361 : * to it.
11362 : *
11363 : * If the dataset has a geotransform attached, the X and Y dimensions of the
11364 : * returned array will have an associated indexing variable.
11365 : *
11366 : * This is the same as the C function GDALRasterBandAsMDArray().
11367 : *
11368 : * The "reverse" method is GDALMDArray::AsClassicDataset().
11369 : *
11370 : * @return a new array, or nullptr.
11371 : *
11372 : * @since GDAL 3.1
11373 : */
11374 35 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11375 : {
11376 35 : if (!poDS)
11377 : {
11378 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11379 0 : return nullptr;
11380 : }
11381 35 : if (!poDS->GetShared())
11382 : {
11383 33 : poDS->MarkAsShared();
11384 : }
11385 : return GDALMDArrayFromRasterBand::Create(
11386 35 : poDS, const_cast<GDALRasterBand *>(this));
11387 : }
11388 :
11389 : /************************************************************************/
11390 : /* InterpolateAtPoint() */
11391 : /************************************************************************/
11392 :
11393 : /**
11394 : * \brief Interpolates the value between pixels using a resampling algorithm,
11395 : * taking pixel/line coordinates as input.
11396 : *
11397 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11398 : * @param dfLine line coordinate as a double, where interpolation should be done.
11399 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11400 : * @param pdfRealValue pointer to real part of interpolated value
11401 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11402 : *
11403 : * @return CE_None on success, or an error code on failure.
11404 : * @since GDAL 3.10
11405 : */
11406 :
11407 183 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11408 : GDALRIOResampleAlg eInterpolation,
11409 : double *pdfRealValue,
11410 : double *pdfImagValue) const
11411 : {
11412 183 : if (eInterpolation != GRIORA_NearestNeighbour &&
11413 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11414 : eInterpolation != GRIORA_CubicSpline)
11415 : {
11416 2 : CPLError(CE_Failure, CPLE_AppDefined,
11417 : "Only nearest, bilinear, cubic and cubicspline interpolation "
11418 : "methods "
11419 : "allowed");
11420 :
11421 2 : return CE_Failure;
11422 : }
11423 :
11424 181 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11425 181 : if (!m_poPointsCache)
11426 101 : m_poPointsCache = new GDALDoublePointsCache();
11427 :
11428 : const bool res =
11429 181 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11430 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
11431 :
11432 181 : return res ? CE_None : CE_Failure;
11433 : }
11434 :
11435 : /************************************************************************/
11436 : /* GDALRasterInterpolateAtPoint() */
11437 : /************************************************************************/
11438 :
11439 : /**
11440 : * \brief Interpolates the value between pixels using
11441 : * a resampling algorithm
11442 : *
11443 : * @see GDALRasterBand::InterpolateAtPoint()
11444 : * @since GDAL 3.10
11445 : */
11446 :
11447 160 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11448 : double dfLine,
11449 : GDALRIOResampleAlg eInterpolation,
11450 : double *pdfRealValue, double *pdfImagValue)
11451 : {
11452 160 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11453 :
11454 160 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11455 160 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11456 160 : pdfRealValue, pdfImagValue);
11457 : }
11458 :
11459 : /************************************************************************/
11460 : /* InterpolateAtGeolocation() */
11461 : /************************************************************************/
11462 :
11463 : /**
11464 : * \brief Interpolates the value between pixels using a resampling algorithm,
11465 : * taking georeferenced coordinates as input.
11466 : *
11467 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11468 : * must be in the "natural" SRS of the dataset, that is the one returned by
11469 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11470 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11471 : * array (generally WGS 84) if there is a geolocation array.
11472 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11473 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11474 : * be a easting, and dfGeolocY a northing.
11475 : *
11476 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11477 : * expressed in that CRS, and that tuple must be conformant with the
11478 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11479 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11480 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11481 : * before calling this method, and in that case, dfGeolocX must be a longitude
11482 : * or an easting value, and dfGeolocX a latitude or a northing value.
11483 : *
11484 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11485 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11486 : * it for details on how that transformation is done.
11487 : *
11488 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11489 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11490 : * where interpolation should be done.
11491 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11492 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11493 : * where interpolation should be done.
11494 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11495 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11496 : * @param pdfRealValue pointer to real part of interpolated value
11497 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11498 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11499 : *
11500 : * @return CE_None on success, or an error code on failure.
11501 : * @since GDAL 3.11
11502 : */
11503 :
11504 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11505 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11506 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11507 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11508 : {
11509 : double dfPixel;
11510 : double dfLine;
11511 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11512 : &dfLine,
11513 15 : papszTransformerOptions) != CE_None)
11514 : {
11515 1 : return CE_Failure;
11516 : }
11517 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11518 14 : pdfImagValue);
11519 : }
11520 :
11521 : /************************************************************************/
11522 : /* GDALRasterInterpolateAtGeolocation() */
11523 : /************************************************************************/
11524 :
11525 : /**
11526 : * \brief Interpolates the value between pixels using a resampling algorithm,
11527 : * taking georeferenced coordinates as input.
11528 : *
11529 : * @see GDALRasterBand::InterpolateAtGeolocation()
11530 : * @since GDAL 3.11
11531 : */
11532 :
11533 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11534 : double dfGeolocX, double dfGeolocY,
11535 : OGRSpatialReferenceH hSRS,
11536 : GDALRIOResampleAlg eInterpolation,
11537 : double *pdfRealValue,
11538 : double *pdfImagValue,
11539 : CSLConstList papszTransformerOptions)
11540 : {
11541 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11542 :
11543 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11544 15 : return poBand->InterpolateAtGeolocation(
11545 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11546 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11547 : }
11548 :
11549 : /************************************************************************/
11550 : /* GDALRasterBand::SplitRasterIO() */
11551 : /************************************************************************/
11552 :
11553 : //! @cond Doxygen_Suppress
11554 :
11555 : /** Implements IRasterIO() by dividing the request in 2.
11556 : *
11557 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11558 : *
11559 : * Return CE_Warning if the split could not be done, CE_None in case of
11560 : * success and CE_Failure in case of error.
11561 : *
11562 : * @since 3.12
11563 : */
11564 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11565 : [[maybe_unused]] int nXSize,
11566 : [[maybe_unused]] int nYSize, void *pData,
11567 : int nBufXSize, int nBufYSize,
11568 : GDALDataType eBufType,
11569 : GSpacing nPixelSpace, GSpacing nLineSpace,
11570 : GDALRasterIOExtraArg *psExtraArg)
11571 : {
11572 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11573 :
11574 999 : GByte *pabyData = static_cast<GByte *>(pData);
11575 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11576 : {
11577 : GDALRasterIOExtraArg sArg;
11578 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11579 499 : const int nHalfHeight = nBufYSize / 2;
11580 :
11581 499 : sArg.pfnProgress = GDALScaledProgress;
11582 499 : sArg.pProgressData = GDALCreateScaledProgress(
11583 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11584 499 : if (sArg.pProgressData == nullptr)
11585 499 : sArg.pfnProgress = nullptr;
11586 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11587 : pabyData, nBufXSize, nHalfHeight, eBufType,
11588 499 : nPixelSpace, nLineSpace, &sArg);
11589 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11590 :
11591 499 : if (eErr == CE_None)
11592 : {
11593 499 : sArg.pfnProgress = GDALScaledProgress;
11594 499 : sArg.pProgressData = GDALCreateScaledProgress(
11595 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11596 499 : if (sArg.pProgressData == nullptr)
11597 499 : sArg.pfnProgress = nullptr;
11598 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11599 : nBufYSize - nHalfHeight,
11600 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11601 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11602 499 : nLineSpace, &sArg);
11603 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11604 : }
11605 499 : return eErr;
11606 : }
11607 500 : else if (nBufXSize >= 2)
11608 : {
11609 : GDALRasterIOExtraArg sArg;
11610 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11611 500 : const int nHalfWidth = nBufXSize / 2;
11612 :
11613 500 : sArg.pfnProgress = GDALScaledProgress;
11614 500 : sArg.pProgressData = GDALCreateScaledProgress(
11615 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11616 500 : if (sArg.pProgressData == nullptr)
11617 500 : sArg.pfnProgress = nullptr;
11618 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11619 : pabyData, nHalfWidth, nBufYSize, eBufType,
11620 500 : nPixelSpace, nLineSpace, &sArg);
11621 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11622 :
11623 500 : if (eErr == CE_None)
11624 : {
11625 500 : sArg.pfnProgress = GDALScaledProgress;
11626 500 : sArg.pProgressData = GDALCreateScaledProgress(
11627 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11628 500 : if (sArg.pProgressData == nullptr)
11629 500 : sArg.pfnProgress = nullptr;
11630 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11631 : nBufXSize - nHalfWidth, nBufYSize,
11632 500 : pabyData + nHalfWidth * nPixelSpace,
11633 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11634 500 : nPixelSpace, nLineSpace, &sArg);
11635 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11636 : }
11637 500 : return eErr;
11638 : }
11639 :
11640 0 : return CE_Warning;
11641 : }
11642 :
11643 : //! @endcond
11644 :
11645 : /************************************************************************/
11646 : /* ThrowIfNotSameDimensions() */
11647 : /************************************************************************/
11648 :
11649 : //! @cond Doxygen_Suppress
11650 : /* static */
11651 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11652 : const GDALRasterBand &second)
11653 : {
11654 320 : if (first.GetXSize() != second.GetXSize() ||
11655 151 : first.GetYSize() != second.GetYSize())
11656 : {
11657 36 : throw std::runtime_error("Bands do not have the same dimensions");
11658 : }
11659 133 : }
11660 :
11661 : //! @endcond
11662 :
11663 : /************************************************************************/
11664 : /* GDALRasterBandUnaryOp() */
11665 : /************************************************************************/
11666 :
11667 : /** Apply a unary operation on this band.
11668 : *
11669 : * The resulting band is lazy evaluated. A reference is taken on the input
11670 : * dataset.
11671 : *
11672 : * @since 3.12
11673 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11674 : */
11675 : GDALComputedRasterBandH
11676 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11677 : GDALRasterAlgebraUnaryOperation eOp)
11678 : {
11679 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11680 6 : GDALComputedRasterBand::Operation cppOp{};
11681 6 : switch (eOp)
11682 : {
11683 2 : case GRAUO_LOGICAL_NOT:
11684 : return new GDALComputedRasterBand(
11685 : GDALComputedRasterBand::Operation::OP_NE,
11686 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11687 1 : case GRAUO_ABS:
11688 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11689 1 : break;
11690 1 : case GRAUO_SQRT:
11691 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11692 1 : break;
11693 1 : case GRAUO_LOG:
11694 : #ifndef HAVE_MUPARSER
11695 : CPLError(
11696 : CE_Failure, CPLE_NotSupported,
11697 : "log(band) not available on a GDAL build without muparser");
11698 : return nullptr;
11699 : #else
11700 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11701 1 : break;
11702 : #endif
11703 1 : case GRAUO_LOG10:
11704 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11705 1 : break;
11706 : }
11707 : return new GDALComputedRasterBand(cppOp,
11708 4 : *(GDALRasterBand::FromHandle(hBand)));
11709 : }
11710 :
11711 : /************************************************************************/
11712 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11713 : /************************************************************************/
11714 :
11715 : static GDALComputedRasterBand::Operation
11716 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11717 : GDALRasterAlgebraBinaryOperation eOp)
11718 : {
11719 120 : switch (eOp)
11720 : {
11721 26 : case GRABO_ADD:
11722 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11723 2 : case GRABO_SUB:
11724 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11725 24 : case GRABO_MUL:
11726 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11727 3 : case GRABO_DIV:
11728 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11729 6 : case GRABO_GT:
11730 6 : return GDALComputedRasterBand::Operation::OP_GT;
11731 8 : case GRABO_GE:
11732 8 : return GDALComputedRasterBand::Operation::OP_GE;
11733 6 : case GRABO_LT:
11734 6 : return GDALComputedRasterBand::Operation::OP_LT;
11735 6 : case GRABO_LE:
11736 6 : return GDALComputedRasterBand::Operation::OP_LE;
11737 6 : case GRABO_EQ:
11738 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11739 6 : case GRABO_NE:
11740 6 : break;
11741 12 : case GRABO_LOGICAL_AND:
11742 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11743 12 : case GRABO_LOGICAL_OR:
11744 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11745 3 : case GRABO_POW:
11746 3 : return GDALComputedRasterBand::Operation::OP_POW;
11747 : }
11748 6 : return GDALComputedRasterBand::Operation::OP_NE;
11749 : }
11750 :
11751 : /************************************************************************/
11752 : /* GDALRasterBandBinaryOpBand() */
11753 : /************************************************************************/
11754 :
11755 : /** Apply a binary operation on this band with another one.
11756 : *
11757 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11758 : * "hBand1 - hBand2".
11759 : *
11760 : * The resulting band is lazy evaluated. A reference is taken on both input
11761 : * datasets.
11762 : *
11763 : * @since 3.12
11764 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11765 : */
11766 : GDALComputedRasterBandH
11767 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11768 : GDALRasterAlgebraBinaryOperation eOp,
11769 : GDALRasterBandH hOtherBand)
11770 : {
11771 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11772 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11773 : #ifndef HAVE_MUPARSER
11774 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11775 : {
11776 : CPLError(
11777 : CE_Failure, CPLE_NotSupported,
11778 : "Band comparison operators not available on a GDAL build without "
11779 : "muparser");
11780 : return nullptr;
11781 : }
11782 : else if (eOp == GRABO_POW)
11783 : {
11784 : CPLError(
11785 : CE_Failure, CPLE_NotSupported,
11786 : "pow(band, band) not available on a GDAL build without muparser");
11787 : return nullptr;
11788 : }
11789 : #endif
11790 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11791 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11792 : try
11793 : {
11794 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11795 : }
11796 13 : catch (const std::exception &e)
11797 : {
11798 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11799 13 : return nullptr;
11800 : }
11801 : return new GDALComputedRasterBand(
11802 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11803 44 : secondBand);
11804 : }
11805 :
11806 : /************************************************************************/
11807 : /* GDALRasterBandBinaryOpDouble() */
11808 : /************************************************************************/
11809 :
11810 : /** Apply a binary operation on this band with a constant
11811 : *
11812 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11813 : * "hBand - constant".
11814 : *
11815 : * The resulting band is lazy evaluated. A reference is taken on the input
11816 : * dataset.
11817 : *
11818 : * @since 3.12
11819 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11820 : */
11821 : GDALComputedRasterBandH
11822 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11823 : GDALRasterAlgebraBinaryOperation eOp,
11824 : double constant)
11825 : {
11826 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11827 : #ifndef HAVE_MUPARSER
11828 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11829 : {
11830 : CPLError(
11831 : CE_Failure, CPLE_NotSupported,
11832 : "Band comparison operators not available on a GDAL build without "
11833 : "muparser");
11834 : return nullptr;
11835 : }
11836 : #endif
11837 : return new GDALComputedRasterBand(
11838 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11839 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11840 : }
11841 :
11842 : /************************************************************************/
11843 : /* GDALRasterBandBinaryOpDoubleToBand() */
11844 : /************************************************************************/
11845 :
11846 : /** Apply a binary operation on the constant with this band
11847 : *
11848 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11849 : * "constant - hBand".
11850 : *
11851 : * The resulting band is lazy evaluated. A reference is taken on the input
11852 : * dataset.
11853 : *
11854 : * @since 3.12
11855 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11856 : */
11857 : GDALComputedRasterBandH
11858 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11859 : GDALRasterAlgebraBinaryOperation eOp,
11860 : GDALRasterBandH hBand)
11861 : {
11862 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11863 : #ifndef HAVE_MUPARSER
11864 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11865 : {
11866 : CPLError(
11867 : CE_Failure, CPLE_NotSupported,
11868 : "Band comparison operators not available on a GDAL build without "
11869 : "muparser");
11870 : return nullptr;
11871 : }
11872 : #endif
11873 18 : switch (eOp)
11874 : {
11875 15 : case GRABO_ADD:
11876 : case GRABO_MUL:
11877 : {
11878 : return new GDALComputedRasterBand(
11879 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11880 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11881 : }
11882 :
11883 2 : case GRABO_DIV:
11884 : case GRABO_GT:
11885 : case GRABO_GE:
11886 : case GRABO_LT:
11887 : case GRABO_LE:
11888 : case GRABO_EQ:
11889 : case GRABO_NE:
11890 : case GRABO_LOGICAL_AND:
11891 : case GRABO_LOGICAL_OR:
11892 : case GRABO_POW:
11893 : {
11894 : return new GDALComputedRasterBand(
11895 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11896 2 : *(GDALRasterBand::FromHandle(hBand)));
11897 : }
11898 :
11899 1 : case GRABO_SUB:
11900 : {
11901 1 : break;
11902 : }
11903 : }
11904 :
11905 : return new GDALComputedRasterBand(
11906 : GDALComputedRasterBand::Operation::OP_ADD,
11907 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11908 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11909 1 : constant);
11910 : }
11911 :
11912 : /************************************************************************/
11913 : /* operator+() */
11914 : /************************************************************************/
11915 :
11916 : /** Add this band with another one.
11917 : *
11918 : * The resulting band is lazy evaluated. A reference is taken on both input
11919 : * datasets.
11920 : *
11921 : * @since 3.12
11922 : * @throw std::runtime_error if both bands do not have the same dimensions.
11923 : */
11924 : GDALComputedRasterBand
11925 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11926 : {
11927 8 : ThrowIfNotSameDimensions(*this, other);
11928 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11929 7 : *this, other);
11930 : }
11931 :
11932 : /************************************************************************/
11933 : /* operator+() */
11934 : /************************************************************************/
11935 :
11936 : /** Add this band with a constant.
11937 : *
11938 : * The resulting band is lazy evaluated. A reference is taken on the input
11939 : * dataset.
11940 : *
11941 : * @since 3.12
11942 : */
11943 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11944 : {
11945 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11946 13 : *this, constant);
11947 : }
11948 :
11949 : /************************************************************************/
11950 : /* operator+() */
11951 : /************************************************************************/
11952 :
11953 : /** Add a band with a constant.
11954 : *
11955 : * The resulting band is lazy evaluated. A reference is taken on the input
11956 : * dataset.
11957 : *
11958 : * @since 3.12
11959 : */
11960 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11961 : {
11962 1 : return other + constant;
11963 : }
11964 :
11965 : /************************************************************************/
11966 : /* operator-() */
11967 : /************************************************************************/
11968 :
11969 : /** Return a band whose value is the opposite value of the band for each
11970 : * pixel.
11971 : *
11972 : * The resulting band is lazy evaluated. A reference is taken on the input
11973 : * dataset.
11974 : *
11975 : * @since 3.12
11976 : */
11977 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
11978 : {
11979 2 : return 0 - *this;
11980 : }
11981 :
11982 : /************************************************************************/
11983 : /* operator-() */
11984 : /************************************************************************/
11985 :
11986 : /** Subtract this band with another one.
11987 : *
11988 : * The resulting band is lazy evaluated. A reference is taken on both input
11989 : * datasets.
11990 : *
11991 : * @since 3.12
11992 : * @throw std::runtime_error if both bands do not have the same dimensions.
11993 : */
11994 : GDALComputedRasterBand
11995 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
11996 : {
11997 2 : ThrowIfNotSameDimensions(*this, other);
11998 : return GDALComputedRasterBand(
11999 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
12000 : }
12001 :
12002 : /************************************************************************/
12003 : /* operator-() */
12004 : /************************************************************************/
12005 :
12006 : /** Subtract this band with a constant.
12007 : *
12008 : * The resulting band is lazy evaluated. A reference is taken on the input
12009 : * dataset.
12010 : *
12011 : * @since 3.12
12012 : */
12013 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
12014 : {
12015 : return GDALComputedRasterBand(
12016 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
12017 : }
12018 :
12019 : /************************************************************************/
12020 : /* operator-() */
12021 : /************************************************************************/
12022 :
12023 : /** Subtract a constant with a band.
12024 : *
12025 : * The resulting band is lazy evaluated. A reference is taken on the input
12026 : * dataset.
12027 : *
12028 : * @since 3.12
12029 : */
12030 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
12031 : {
12032 6 : return other * (-1.0) + constant;
12033 : }
12034 :
12035 : /************************************************************************/
12036 : /* operator*() */
12037 : /************************************************************************/
12038 :
12039 : /** Multiply this band with another one.
12040 : *
12041 : * The resulting band is lazy evaluated. A reference is taken on both input
12042 : * datasets.
12043 : *
12044 : * @since 3.12
12045 : * @throw std::runtime_error if both bands do not have the same dimensions.
12046 : */
12047 : GDALComputedRasterBand
12048 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
12049 : {
12050 2 : ThrowIfNotSameDimensions(*this, other);
12051 : return GDALComputedRasterBand(
12052 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
12053 : }
12054 :
12055 : /************************************************************************/
12056 : /* operator*() */
12057 : /************************************************************************/
12058 :
12059 : /** Multiply this band by a constant.
12060 : *
12061 : * The resulting band is lazy evaluated. A reference is taken on the input
12062 : * dataset.
12063 : *
12064 : * @since 3.12
12065 : */
12066 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
12067 : {
12068 : return GDALComputedRasterBand(
12069 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
12070 : }
12071 :
12072 : /************************************************************************/
12073 : /* operator*() */
12074 : /************************************************************************/
12075 :
12076 : /** Multiply a band with a constant.
12077 : *
12078 : * The resulting band is lazy evaluated. A reference is taken on the input
12079 : * dataset.
12080 : *
12081 : * @since 3.12
12082 : */
12083 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12084 : {
12085 2 : return other * constant;
12086 : }
12087 :
12088 : /************************************************************************/
12089 : /* operator/() */
12090 : /************************************************************************/
12091 :
12092 : /** Divide this band with another one.
12093 : *
12094 : * The resulting band is lazy evaluated. A reference is taken on both input
12095 : * datasets.
12096 : *
12097 : * @since 3.12
12098 : * @throw std::runtime_error if both bands do not have the same dimensions.
12099 : */
12100 : GDALComputedRasterBand
12101 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
12102 : {
12103 2 : ThrowIfNotSameDimensions(*this, other);
12104 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12105 2 : *this, other);
12106 : }
12107 :
12108 : /************************************************************************/
12109 : /* operator/() */
12110 : /************************************************************************/
12111 :
12112 : /** Divide this band by a constant.
12113 : *
12114 : * The resulting band is lazy evaluated. A reference is taken on the input
12115 : * dataset.
12116 : *
12117 : * @since 3.12
12118 : */
12119 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12120 : {
12121 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12122 0 : *this, constant);
12123 : }
12124 :
12125 : /************************************************************************/
12126 : /* operator/() */
12127 : /************************************************************************/
12128 :
12129 : /** Divide a constant by a band.
12130 : *
12131 : * The resulting band is lazy evaluated. A reference is taken on the input
12132 : * dataset.
12133 : *
12134 : * @since 3.12
12135 : */
12136 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12137 : {
12138 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12139 1 : constant, other);
12140 : }
12141 :
12142 : /************************************************************************/
12143 : /* ThrowIfNotMuparser() */
12144 : /************************************************************************/
12145 :
12146 : #ifndef HAVE_MUPARSER
12147 : static GDALComputedRasterBand ThrowIfNotMuparser()
12148 : {
12149 : throw std::runtime_error("Operator not available on a "
12150 : "GDAL build without muparser");
12151 : }
12152 : #endif
12153 :
12154 : /************************************************************************/
12155 : /* operator>() */
12156 : /************************************************************************/
12157 :
12158 : /** Return a band whose value is 1 if the pixel value of the left operand
12159 : * is greater than the pixel value of the right operand.
12160 : *
12161 : * The resulting band is lazy evaluated. A reference is taken on the input
12162 : * dataset.
12163 : *
12164 : * @since 3.12
12165 : */
12166 : GDALComputedRasterBand
12167 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
12168 : {
12169 : #ifndef HAVE_MUPARSER
12170 : (void)other;
12171 : return ThrowIfNotMuparser();
12172 : #else
12173 3 : ThrowIfNotSameDimensions(*this, other);
12174 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12175 2 : *this, other);
12176 : #endif
12177 : }
12178 :
12179 : /************************************************************************/
12180 : /* operator>() */
12181 : /************************************************************************/
12182 :
12183 : /** Return a band whose value is 1 if the pixel value of the left operand
12184 : * is greater than the constant.
12185 : *
12186 : * The resulting band is lazy evaluated. A reference is taken on the input
12187 : * dataset.
12188 : *
12189 : * @since 3.12
12190 : */
12191 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12192 : {
12193 : #ifndef HAVE_MUPARSER
12194 : (void)constant;
12195 : return ThrowIfNotMuparser();
12196 : #else
12197 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12198 3 : *this, constant);
12199 : #endif
12200 : }
12201 :
12202 : /************************************************************************/
12203 : /* operator>() */
12204 : /************************************************************************/
12205 :
12206 : /** Return a band whose value is 1 if the constant is greater than the pixel
12207 : * value of the right operand.
12208 : *
12209 : * The resulting band is lazy evaluated. A reference is taken on the input
12210 : * dataset.
12211 : *
12212 : * @since 3.12
12213 : */
12214 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12215 : {
12216 : #ifndef HAVE_MUPARSER
12217 : (void)constant;
12218 : (void)other;
12219 : return ThrowIfNotMuparser();
12220 : #else
12221 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12222 2 : constant, other);
12223 : #endif
12224 : }
12225 :
12226 : /************************************************************************/
12227 : /* operator>=() */
12228 : /************************************************************************/
12229 :
12230 : /** Return a band whose value is 1 if the pixel value of the left operand
12231 : * is greater or equal to the pixel value of the right operand.
12232 : *
12233 : * The resulting band is lazy evaluated. A reference is taken on the input
12234 : * dataset.
12235 : *
12236 : * @since 3.12
12237 : */
12238 : GDALComputedRasterBand
12239 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
12240 : {
12241 : #ifndef HAVE_MUPARSER
12242 : (void)other;
12243 : return ThrowIfNotMuparser();
12244 : #else
12245 4 : ThrowIfNotSameDimensions(*this, other);
12246 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12247 3 : *this, other);
12248 : #endif
12249 : }
12250 :
12251 : /************************************************************************/
12252 : /* operator>=() */
12253 : /************************************************************************/
12254 :
12255 : /** Return a band whose value is 1 if the pixel value of the left operand
12256 : * is greater or equal to the constant.
12257 : *
12258 : * The resulting band is lazy evaluated. A reference is taken on the input
12259 : * dataset.
12260 : *
12261 : * @since 3.12
12262 : */
12263 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12264 : {
12265 : #ifndef HAVE_MUPARSER
12266 : (void)constant;
12267 : return ThrowIfNotMuparser();
12268 : #else
12269 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12270 3 : *this, constant);
12271 : #endif
12272 : }
12273 :
12274 : /************************************************************************/
12275 : /* operator>=() */
12276 : /************************************************************************/
12277 :
12278 : /** Return a band whose value is 1 if the constant is greater or equal to
12279 : * the pixel value of the right operand.
12280 : *
12281 : * The resulting band is lazy evaluated. A reference is taken on the input
12282 : * dataset.
12283 : *
12284 : * @since 3.12
12285 : */
12286 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12287 : {
12288 : #ifndef HAVE_MUPARSER
12289 : (void)constant;
12290 : (void)other;
12291 : return ThrowIfNotMuparser();
12292 : #else
12293 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12294 2 : constant, other);
12295 : #endif
12296 : }
12297 :
12298 : /************************************************************************/
12299 : /* operator<() */
12300 : /************************************************************************/
12301 :
12302 : /** Return a band whose value is 1 if the pixel value of the left operand
12303 : * is lesser than the pixel value of the right operand.
12304 : *
12305 : * The resulting band is lazy evaluated. A reference is taken on the input
12306 : * dataset.
12307 : *
12308 : * @since 3.12
12309 : */
12310 : GDALComputedRasterBand
12311 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
12312 : {
12313 : #ifndef HAVE_MUPARSER
12314 : (void)other;
12315 : return ThrowIfNotMuparser();
12316 : #else
12317 3 : ThrowIfNotSameDimensions(*this, other);
12318 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12319 2 : *this, other);
12320 : #endif
12321 : }
12322 :
12323 : /************************************************************************/
12324 : /* operator<() */
12325 : /************************************************************************/
12326 :
12327 : /** Return a band whose value is 1 if the pixel value of the left operand
12328 : * is lesser than the constant.
12329 : *
12330 : * The resulting band is lazy evaluated. A reference is taken on the input
12331 : * dataset.
12332 : *
12333 : * @since 3.12
12334 : */
12335 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12336 : {
12337 : #ifndef HAVE_MUPARSER
12338 : (void)constant;
12339 : return ThrowIfNotMuparser();
12340 : #else
12341 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12342 3 : *this, constant);
12343 : #endif
12344 : }
12345 :
12346 : /************************************************************************/
12347 : /* operator<() */
12348 : /************************************************************************/
12349 :
12350 : /** Return a band whose value is 1 if the constant is lesser than the pixel
12351 : * value of the right operand.
12352 : *
12353 : * The resulting band is lazy evaluated. A reference is taken on the input
12354 : * dataset.
12355 : *
12356 : * @since 3.12
12357 : */
12358 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12359 : {
12360 : #ifndef HAVE_MUPARSER
12361 : (void)constant;
12362 : (void)other;
12363 : return ThrowIfNotMuparser();
12364 : #else
12365 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12366 2 : constant, other);
12367 : #endif
12368 : }
12369 :
12370 : /************************************************************************/
12371 : /* operator<=() */
12372 : /************************************************************************/
12373 :
12374 : /** Return a band whose value is 1 if the pixel value of the left operand
12375 : * is lesser or equal to the pixel value of the right operand.
12376 : *
12377 : * The resulting band is lazy evaluated. A reference is taken on the input
12378 : * dataset.
12379 : *
12380 : * @since 3.12
12381 : */
12382 : GDALComputedRasterBand
12383 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
12384 : {
12385 : #ifndef HAVE_MUPARSER
12386 : (void)other;
12387 : return ThrowIfNotMuparser();
12388 : #else
12389 4 : ThrowIfNotSameDimensions(*this, other);
12390 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12391 3 : *this, other);
12392 : #endif
12393 : }
12394 :
12395 : /************************************************************************/
12396 : /* operator<=() */
12397 : /************************************************************************/
12398 :
12399 : /** Return a band whose value is 1 if the pixel value of the left operand
12400 : * is lesser or equal to the constant.
12401 : *
12402 : * The resulting band is lazy evaluated. A reference is taken on the input
12403 : * dataset.
12404 : *
12405 : * @since 3.12
12406 : */
12407 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12408 : {
12409 : #ifndef HAVE_MUPARSER
12410 : (void)constant;
12411 : return ThrowIfNotMuparser();
12412 : #else
12413 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12414 3 : *this, constant);
12415 : #endif
12416 : }
12417 :
12418 : /************************************************************************/
12419 : /* operator<=() */
12420 : /************************************************************************/
12421 :
12422 : /** Return a band whose value is 1 if the constant is lesser or equal to
12423 : * the pixel value of the right operand.
12424 : *
12425 : * The resulting band is lazy evaluated. A reference is taken on the input
12426 : * dataset.
12427 : *
12428 : * @since 3.12
12429 : */
12430 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12431 : {
12432 : #ifndef HAVE_MUPARSER
12433 : (void)constant;
12434 : (void)other;
12435 : return ThrowIfNotMuparser();
12436 : #else
12437 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12438 2 : constant, other);
12439 : #endif
12440 : }
12441 :
12442 : /************************************************************************/
12443 : /* operator==() */
12444 : /************************************************************************/
12445 :
12446 : /** Return a band whose value is 1 if the pixel value of the left operand
12447 : * is equal to the pixel value of the right operand.
12448 : *
12449 : * The resulting band is lazy evaluated. A reference is taken on the input
12450 : * dataset.
12451 : *
12452 : * @since 3.12
12453 : */
12454 : GDALComputedRasterBand
12455 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
12456 : {
12457 : #ifndef HAVE_MUPARSER
12458 : (void)other;
12459 : return ThrowIfNotMuparser();
12460 : #else
12461 3 : ThrowIfNotSameDimensions(*this, other);
12462 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12463 2 : *this, other);
12464 : #endif
12465 : }
12466 :
12467 : /************************************************************************/
12468 : /* operator==() */
12469 : /************************************************************************/
12470 :
12471 : /** Return a band whose value is 1 if the pixel value of the left operand
12472 : * is equal to the constant.
12473 : *
12474 : * The resulting band is lazy evaluated. A reference is taken on the input
12475 : * dataset.
12476 : *
12477 : * @since 3.12
12478 : */
12479 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12480 : {
12481 : #ifndef HAVE_MUPARSER
12482 : (void)constant;
12483 : return ThrowIfNotMuparser();
12484 : #else
12485 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12486 8 : *this, constant);
12487 : #endif
12488 : }
12489 :
12490 : /************************************************************************/
12491 : /* operator==() */
12492 : /************************************************************************/
12493 :
12494 : /** Return a band whose value is 1 if the constant is equal to
12495 : * the pixel value of the right operand.
12496 : *
12497 : * The resulting band is lazy evaluated. A reference is taken on the input
12498 : * dataset.
12499 : *
12500 : * @since 3.12
12501 : */
12502 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12503 : {
12504 : #ifndef HAVE_MUPARSER
12505 : (void)constant;
12506 : (void)other;
12507 : return ThrowIfNotMuparser();
12508 : #else
12509 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12510 2 : constant, other);
12511 : #endif
12512 : }
12513 :
12514 : /************************************************************************/
12515 : /* operator!=() */
12516 : /************************************************************************/
12517 :
12518 : /** Return a band whose value is 1 if the pixel value of the left operand
12519 : * is different from the pixel value of the right operand.
12520 : *
12521 : * The resulting band is lazy evaluated. A reference is taken on the input
12522 : * dataset.
12523 : *
12524 : * @since 3.12
12525 : */
12526 : GDALComputedRasterBand
12527 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12528 : {
12529 : #ifndef HAVE_MUPARSER
12530 : (void)other;
12531 : return ThrowIfNotMuparser();
12532 : #else
12533 3 : ThrowIfNotSameDimensions(*this, other);
12534 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12535 2 : *this, other);
12536 : #endif
12537 : }
12538 :
12539 : /************************************************************************/
12540 : /* operator!=() */
12541 : /************************************************************************/
12542 :
12543 : /** Return a band whose value is 1 if the pixel value of the left operand
12544 : * is different from the constant.
12545 : *
12546 : * The resulting band is lazy evaluated. A reference is taken on the input
12547 : * dataset.
12548 : *
12549 : * @since 3.12
12550 : */
12551 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12552 : {
12553 : #ifndef HAVE_MUPARSER
12554 : (void)constant;
12555 : return ThrowIfNotMuparser();
12556 : #else
12557 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12558 6 : *this, constant);
12559 : #endif
12560 : }
12561 :
12562 : /************************************************************************/
12563 : /* operator!=() */
12564 : /************************************************************************/
12565 :
12566 : /** Return a band whose value is 1 if the constant is different from
12567 : * the pixel value of the right operand.
12568 : *
12569 : * The resulting band is lazy evaluated. A reference is taken on the input
12570 : * dataset.
12571 : *
12572 : * @since 3.12
12573 : */
12574 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12575 : {
12576 : #ifndef HAVE_MUPARSER
12577 : (void)constant;
12578 : (void)other;
12579 : return ThrowIfNotMuparser();
12580 : #else
12581 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12582 2 : constant, other);
12583 : #endif
12584 : }
12585 :
12586 : #if defined(__GNUC__)
12587 : #pragma GCC diagnostic push
12588 : #pragma GCC diagnostic ignored "-Weffc++"
12589 : #endif
12590 :
12591 : /************************************************************************/
12592 : /* operator&&() */
12593 : /************************************************************************/
12594 :
12595 : /** Return a band whose value is 1 if the pixel value of the left and right
12596 : * operands is true.
12597 : *
12598 : * The resulting band is lazy evaluated. A reference is taken on the input
12599 : * dataset.
12600 : *
12601 : * @since 3.12
12602 : */
12603 : GDALComputedRasterBand
12604 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12605 : {
12606 : #ifndef HAVE_MUPARSER
12607 : (void)other;
12608 : return ThrowIfNotMuparser();
12609 : #else
12610 3 : ThrowIfNotSameDimensions(*this, other);
12611 : return GDALComputedRasterBand(
12612 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12613 : #endif
12614 : }
12615 :
12616 : /************************************************************************/
12617 : /* operator&&() */
12618 : /************************************************************************/
12619 :
12620 : /** Return a band whose value is 1 if the pixel value of the left operand
12621 : * is true, as well as the constant
12622 : *
12623 : * The resulting band is lazy evaluated. A reference is taken on the input
12624 : * dataset.
12625 : *
12626 : * @since 3.12
12627 : */
12628 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12629 : {
12630 : #ifndef HAVE_MUPARSER
12631 : (void)constant;
12632 : return ThrowIfNotMuparser();
12633 : #else
12634 : return GDALComputedRasterBand(
12635 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12636 : #endif
12637 : }
12638 :
12639 : /************************************************************************/
12640 : /* operator&&() */
12641 : /************************************************************************/
12642 :
12643 : /** Return a band whose value is 1 if the constant is true, as well as
12644 : * the pixel value of the right operand.
12645 : *
12646 : * The resulting band is lazy evaluated. A reference is taken on the input
12647 : * dataset.
12648 : *
12649 : * @since 3.12
12650 : */
12651 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12652 : {
12653 : #ifndef HAVE_MUPARSER
12654 : (void)constant;
12655 : (void)other;
12656 : return ThrowIfNotMuparser();
12657 : #else
12658 : return GDALComputedRasterBand(
12659 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12660 : #endif
12661 : }
12662 :
12663 : /************************************************************************/
12664 : /* operator||() */
12665 : /************************************************************************/
12666 :
12667 : /** Return a band whose value is 1 if the pixel value of the left or right
12668 : * operands is true.
12669 : *
12670 : * The resulting band is lazy evaluated. A reference is taken on the input
12671 : * dataset.
12672 : *
12673 : * @since 3.12
12674 : */
12675 : GDALComputedRasterBand
12676 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12677 : {
12678 : #ifndef HAVE_MUPARSER
12679 : (void)other;
12680 : return ThrowIfNotMuparser();
12681 : #else
12682 4 : ThrowIfNotSameDimensions(*this, other);
12683 : return GDALComputedRasterBand(
12684 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12685 : #endif
12686 : }
12687 :
12688 : /************************************************************************/
12689 : /* operator||() */
12690 : /************************************************************************/
12691 :
12692 : /** Return a band whose value is 1 if the pixel value of the left operand
12693 : * is true, or if the constant is true
12694 : *
12695 : * The resulting band is lazy evaluated. A reference is taken on the input
12696 : * dataset.
12697 : *
12698 : * @since 3.12
12699 : */
12700 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12701 : {
12702 : #ifndef HAVE_MUPARSER
12703 : (void)constant;
12704 : return ThrowIfNotMuparser();
12705 : #else
12706 : return GDALComputedRasterBand(
12707 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12708 : #endif
12709 : }
12710 :
12711 : /************************************************************************/
12712 : /* operator||() */
12713 : /************************************************************************/
12714 :
12715 : /** Return a band whose value is 1 if the constant is true, or
12716 : * the pixel value of the right operand is true
12717 : *
12718 : * The resulting band is lazy evaluated. A reference is taken on the input
12719 : * dataset.
12720 : *
12721 : * @since 3.12
12722 : */
12723 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12724 : {
12725 : #ifndef HAVE_MUPARSER
12726 : (void)constant;
12727 : (void)other;
12728 : return ThrowIfNotMuparser();
12729 : #else
12730 : return GDALComputedRasterBand(
12731 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12732 : #endif
12733 : }
12734 :
12735 : #if defined(__GNUC__)
12736 : #pragma GCC diagnostic pop
12737 : #endif
12738 :
12739 : /************************************************************************/
12740 : /* operator!() */
12741 : /************************************************************************/
12742 :
12743 : /** Return a band whose value is the logical negation of the pixel value
12744 : *
12745 : * The resulting band is lazy evaluated. A reference is taken on the input
12746 : * dataset.
12747 : *
12748 : * @since 3.12
12749 : */
12750 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12751 : {
12752 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12753 2 : *this, true);
12754 : }
12755 :
12756 : namespace gdal
12757 : {
12758 :
12759 : /************************************************************************/
12760 : /* IfThenElse() */
12761 : /************************************************************************/
12762 :
12763 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12764 : * is not zero, or the one from elseBand otherwise.
12765 : *
12766 : * Variants of this method exits where thenBand and/or elseBand can be double
12767 : * values.
12768 : *
12769 : * The resulting band is lazy evaluated. A reference is taken on the input
12770 : * datasets.
12771 : *
12772 : * This method is the same as the C function GDALRasterBandIfThenElse()
12773 : *
12774 : * @since 3.12
12775 : */
12776 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12777 : const GDALRasterBand &thenBand,
12778 : const GDALRasterBand &elseBand)
12779 : {
12780 : #ifndef HAVE_MUPARSER
12781 : (void)condBand;
12782 : (void)thenBand;
12783 : (void)elseBand;
12784 : return ThrowIfNotMuparser();
12785 : #else
12786 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12787 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12788 : return GDALComputedRasterBand(
12789 : GDALComputedRasterBand::Operation::OP_TERNARY,
12790 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12791 : #endif
12792 : }
12793 :
12794 : //! @cond Doxygen_Suppress
12795 :
12796 : /************************************************************************/
12797 : /* IfThenElse() */
12798 : /************************************************************************/
12799 :
12800 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12801 : * is not zero, or the one from elseBand otherwise.
12802 : *
12803 : * The resulting band is lazy evaluated. A reference is taken on the input
12804 : * datasets.
12805 : *
12806 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12807 : * with thenBand = (condBand * 0) + thenValue
12808 : *
12809 : * @since 3.12
12810 : */
12811 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12812 : double thenValue,
12813 : const GDALRasterBand &elseBand)
12814 : {
12815 : #ifndef HAVE_MUPARSER
12816 : (void)condBand;
12817 : (void)thenValue;
12818 : (void)elseBand;
12819 : return ThrowIfNotMuparser();
12820 : #else
12821 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12822 : auto thenBand =
12823 1 : (condBand * 0)
12824 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12825 1 : thenValue;
12826 : return GDALComputedRasterBand(
12827 : GDALComputedRasterBand::Operation::OP_TERNARY,
12828 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12829 : #endif
12830 : }
12831 :
12832 : /************************************************************************/
12833 : /* IfThenElse() */
12834 : /************************************************************************/
12835 :
12836 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12837 : * is not zero, or the one from elseValue otherwise.
12838 : *
12839 : * The resulting band is lazy evaluated. A reference is taken on the input
12840 : * datasets.
12841 : *
12842 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12843 : * with elseBand = (condBand * 0) + elseValue
12844 :
12845 : * @since 3.12
12846 : */
12847 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12848 : const GDALRasterBand &thenBand,
12849 : double elseValue)
12850 : {
12851 : #ifndef HAVE_MUPARSER
12852 : (void)condBand;
12853 : (void)thenBand;
12854 : (void)elseValue;
12855 : return ThrowIfNotMuparser();
12856 : #else
12857 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12858 : auto elseBand =
12859 1 : (condBand * 0)
12860 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12861 1 : elseValue;
12862 : return GDALComputedRasterBand(
12863 : GDALComputedRasterBand::Operation::OP_TERNARY,
12864 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12865 : #endif
12866 : }
12867 :
12868 : /************************************************************************/
12869 : /* IfThenElse() */
12870 : /************************************************************************/
12871 :
12872 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12873 : * is not zero, or the one from elseValue otherwise.
12874 : *
12875 : * The resulting band is lazy evaluated. A reference is taken on the input
12876 : * datasets.
12877 : *
12878 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12879 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12880 : *
12881 : * @since 3.12
12882 : */
12883 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12884 : double thenValue, double elseValue)
12885 : {
12886 : #ifndef HAVE_MUPARSER
12887 : (void)condBand;
12888 : (void)thenValue;
12889 : (void)elseValue;
12890 : return ThrowIfNotMuparser();
12891 : #else
12892 : auto thenBand =
12893 3 : (condBand * 0)
12894 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12895 6 : thenValue;
12896 : auto elseBand =
12897 3 : (condBand * 0)
12898 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12899 3 : elseValue;
12900 : return GDALComputedRasterBand(
12901 : GDALComputedRasterBand::Operation::OP_TERNARY,
12902 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12903 : #endif
12904 : }
12905 :
12906 : //! @endcond
12907 :
12908 : } // namespace gdal
12909 :
12910 : /************************************************************************/
12911 : /* GDALRasterBandIfThenElse() */
12912 : /************************************************************************/
12913 :
12914 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12915 : * is not zero, or the one from hElseBand otherwise.
12916 : *
12917 : * The resulting band is lazy evaluated. A reference is taken on the input
12918 : * datasets.
12919 : *
12920 : * This function is the same as the C++ method gdal::IfThenElse()
12921 : *
12922 : * @since 3.12
12923 : */
12924 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12925 : GDALRasterBandH hThenBand,
12926 : GDALRasterBandH hElseBand)
12927 : {
12928 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12929 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12930 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12931 : #ifndef HAVE_MUPARSER
12932 : CPLError(CE_Failure, CPLE_NotSupported,
12933 : "Band comparison operators not available on a GDAL build without "
12934 : "muparser");
12935 : return nullptr;
12936 : #else
12937 :
12938 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12939 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12940 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12941 : try
12942 : {
12943 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12944 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12945 : }
12946 2 : catch (const std::exception &e)
12947 : {
12948 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12949 2 : return nullptr;
12950 : }
12951 : return new GDALComputedRasterBand(
12952 : GDALComputedRasterBand::Operation::OP_TERNARY,
12953 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12954 : #endif
12955 : }
12956 :
12957 : /************************************************************************/
12958 : /* GDALRasterBand::AsType() */
12959 : /************************************************************************/
12960 :
12961 : /** Cast this band to another type.
12962 : *
12963 : * The resulting band is lazy evaluated. A reference is taken on the input
12964 : * dataset.
12965 : *
12966 : * This method is the same as the C function GDALRasterBandAsDataType()
12967 : *
12968 : * @since 3.12
12969 : */
12970 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12971 : {
12972 10 : if (dt == GDT_Unknown)
12973 : {
12974 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12975 : }
12976 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12977 9 : *this, dt);
12978 : }
12979 :
12980 : /************************************************************************/
12981 : /* GDALRasterBandAsDataType() */
12982 : /************************************************************************/
12983 :
12984 : /** Cast this band to another type.
12985 : *
12986 : * The resulting band is lazy evaluated. A reference is taken on the input
12987 : * dataset.
12988 : *
12989 : * This function is the same as the C++ method GDALRasterBand::AsType()
12990 : *
12991 : * @since 3.12
12992 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12993 : */
12994 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12995 : GDALDataType eDT)
12996 : {
12997 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
12998 16 : if (eDT == GDT_Unknown)
12999 : {
13000 1 : CPLError(CE_Failure, CPLE_NotSupported,
13001 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
13002 1 : return nullptr;
13003 : }
13004 : return new GDALComputedRasterBand(
13005 : GDALComputedRasterBand::Operation::OP_CAST,
13006 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
13007 : }
13008 :
13009 : /************************************************************************/
13010 : /* GetBandVector() */
13011 : /************************************************************************/
13012 :
13013 : static std::vector<const GDALRasterBand *>
13014 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
13015 : {
13016 10 : std::vector<const GDALRasterBand *> bands;
13017 27 : for (size_t i = 0; i < nBandCount; ++i)
13018 : {
13019 20 : if (i > 0)
13020 : {
13021 10 : GDALRasterBand::ThrowIfNotSameDimensions(
13022 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
13023 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
13024 : }
13025 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
13026 : }
13027 7 : return bands;
13028 : }
13029 :
13030 : /************************************************************************/
13031 : /* GDALOperationOnNBands() */
13032 : /************************************************************************/
13033 :
13034 : static GDALComputedRasterBandH
13035 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
13036 : GDALRasterBandH *pahBands)
13037 : {
13038 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
13039 11 : if (nBandCount == 0)
13040 : {
13041 1 : CPLError(CE_Failure, CPLE_AppDefined,
13042 : "At least one band should be passed");
13043 1 : return nullptr;
13044 : }
13045 :
13046 20 : std::vector<const GDALRasterBand *> bands;
13047 : try
13048 : {
13049 10 : bands = GetBandVector(nBandCount, pahBands);
13050 : }
13051 3 : catch (const std::exception &e)
13052 : {
13053 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
13054 3 : return nullptr;
13055 : }
13056 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
13057 : }
13058 :
13059 : /************************************************************************/
13060 : /* GDALMaximumOfNBands() */
13061 : /************************************************************************/
13062 :
13063 : /** Return a band whose each pixel value is the maximum of the corresponding
13064 : * pixel values in the input bands.
13065 : *
13066 : * The resulting band is lazy evaluated. A reference is taken on input
13067 : * datasets.
13068 : *
13069 : * This function is the same as the C ++ method gdal::max()
13070 : *
13071 : * @since 3.12
13072 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13073 : */
13074 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
13075 : GDALRasterBandH *pahBands)
13076 : {
13077 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
13078 4 : nBandCount, pahBands);
13079 : }
13080 :
13081 : /************************************************************************/
13082 : /* gdal::max() */
13083 : /************************************************************************/
13084 :
13085 : namespace gdal
13086 : {
13087 : /** Return a band whose each pixel value is the maximum of the corresponding
13088 : * pixel values in the inputs (bands or constants)
13089 : *
13090 : * The resulting band is lazy evaluated. A reference is taken on input
13091 : * datasets.
13092 : *
13093 : * Two or more bands can be passed.
13094 : *
13095 : * This method is the same as the C function GDALMaximumOfNBands()
13096 : *
13097 : * @since 3.12
13098 : * @throw std::runtime_error if bands do not have the same dimensions.
13099 : */
13100 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
13101 : const GDALRasterBand &second)
13102 : {
13103 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13104 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13105 1 : first, second);
13106 : }
13107 : } // namespace gdal
13108 :
13109 : /************************************************************************/
13110 : /* GDALRasterBandMaxConstant() */
13111 : /************************************************************************/
13112 :
13113 : /** Return a band whose each pixel value is the maximum of the corresponding
13114 : * pixel values in the input band and the constant.
13115 : *
13116 : * The resulting band is lazy evaluated. A reference is taken on the input
13117 : * dataset.
13118 : *
13119 : * This function is the same as the C ++ method gdal::max()
13120 : *
13121 : * @since 3.12
13122 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13123 : */
13124 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13125 : double dfConstant)
13126 : {
13127 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13128 : GDALComputedRasterBand::Operation::OP_MAX,
13129 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13130 6 : dfConstant));
13131 : }
13132 :
13133 : /************************************************************************/
13134 : /* GDALMinimumOfNBands() */
13135 : /************************************************************************/
13136 :
13137 : /** Return a band whose each pixel value is the minimum of the corresponding
13138 : * pixel values in the input bands.
13139 : *
13140 : * The resulting band is lazy evaluated. A reference is taken on input
13141 : * datasets.
13142 : *
13143 : * This function is the same as the C ++ method gdal::min()
13144 : *
13145 : * @since 3.12
13146 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13147 : */
13148 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13149 : GDALRasterBandH *pahBands)
13150 : {
13151 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13152 4 : nBandCount, pahBands);
13153 : }
13154 :
13155 : /************************************************************************/
13156 : /* gdal::min() */
13157 : /************************************************************************/
13158 :
13159 : namespace gdal
13160 : {
13161 : /** Return a band whose each pixel value is the minimum of the corresponding
13162 : * pixel values in the inputs (bands or constants)
13163 : *
13164 : * The resulting band is lazy evaluated. A reference is taken on input
13165 : * datasets.
13166 : *
13167 : * Two or more bands can be passed.
13168 : *
13169 : * This method is the same as the C function GDALMinimumOfNBands()
13170 : *
13171 : * @since 3.12
13172 : * @throw std::runtime_error if bands do not have the same dimensions.
13173 : */
13174 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
13175 : const GDALRasterBand &second)
13176 : {
13177 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13178 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13179 0 : first, second);
13180 : }
13181 : } // namespace gdal
13182 :
13183 : /************************************************************************/
13184 : /* GDALRasterBandMinConstant() */
13185 : /************************************************************************/
13186 :
13187 : /** Return a band whose each pixel value is the minimum of the corresponding
13188 : * pixel values in the input band and the constant.
13189 : *
13190 : * The resulting band is lazy evaluated. A reference is taken on the input
13191 : * dataset.
13192 : *
13193 : * This function is the same as the C ++ method gdal::min()
13194 : *
13195 : * @since 3.12
13196 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13197 : */
13198 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13199 : double dfConstant)
13200 : {
13201 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13202 : GDALComputedRasterBand::Operation::OP_MIN,
13203 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13204 6 : dfConstant));
13205 : }
13206 :
13207 : /************************************************************************/
13208 : /* GDALMeanOfNBands() */
13209 : /************************************************************************/
13210 :
13211 : /** Return a band whose each pixel value is the arithmetic mean of the
13212 : * corresponding pixel values in the input bands.
13213 : *
13214 : * The resulting band is lazy evaluated. A reference is taken on input
13215 : * datasets.
13216 : *
13217 : * This function is the same as the C ++ method gdal::mean()
13218 : *
13219 : * @since 3.12
13220 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13221 : */
13222 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13223 : GDALRasterBandH *pahBands)
13224 : {
13225 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13226 3 : nBandCount, pahBands);
13227 : }
13228 :
13229 : /************************************************************************/
13230 : /* gdal::mean() */
13231 : /************************************************************************/
13232 :
13233 : namespace gdal
13234 : {
13235 :
13236 : /** Return a band whose each pixel value is the arithmetic mean of the
13237 : * corresponding pixel values in the input bands.
13238 : *
13239 : * The resulting band is lazy evaluated. A reference is taken on input
13240 : * datasets.
13241 : *
13242 : * Two or more bands can be passed.
13243 : *
13244 : * This method is the same as the C function GDALMeanOfNBands()
13245 : *
13246 : * @since 3.12
13247 : * @throw std::runtime_error if bands do not have the same dimensions.
13248 : */
13249 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
13250 : const GDALRasterBand &second)
13251 : {
13252 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13253 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13254 0 : first, second);
13255 : }
13256 : } // namespace gdal
13257 :
13258 : /************************************************************************/
13259 : /* gdal::abs() */
13260 : /************************************************************************/
13261 :
13262 : namespace gdal
13263 : {
13264 :
13265 : /** Return a band whose each pixel value is the absolute value (or module
13266 : * for complex data type) of the corresponding pixel value in the input band.
13267 : *
13268 : * The resulting band is lazy evaluated. A reference is taken on input
13269 : * datasets.
13270 : *
13271 : * @since 3.12
13272 : */
13273 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
13274 : {
13275 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13276 1 : band);
13277 : }
13278 : } // namespace gdal
13279 :
13280 : /************************************************************************/
13281 : /* gdal::fabs() */
13282 : /************************************************************************/
13283 :
13284 : namespace gdal
13285 : {
13286 :
13287 : /** Return a band whose each pixel value is the absolute value (or module
13288 : * for complex data type) of the corresponding pixel value in the input band.
13289 : *
13290 : * The resulting band is lazy evaluated. A reference is taken on input
13291 : * datasets.
13292 : *
13293 : * @since 3.12
13294 : */
13295 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
13296 : {
13297 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13298 1 : band);
13299 : }
13300 : } // namespace gdal
13301 :
13302 : /************************************************************************/
13303 : /* gdal::sqrt() */
13304 : /************************************************************************/
13305 :
13306 : namespace gdal
13307 : {
13308 :
13309 : /** Return a band whose each pixel value is the square root of the
13310 : * corresponding pixel value in the input band.
13311 : *
13312 : * The resulting band is lazy evaluated. A reference is taken on input
13313 : * datasets.
13314 : *
13315 : * @since 3.12
13316 : */
13317 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13318 : {
13319 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13320 1 : band);
13321 : }
13322 : } // namespace gdal
13323 :
13324 : /************************************************************************/
13325 : /* gdal::log() */
13326 : /************************************************************************/
13327 :
13328 : namespace gdal
13329 : {
13330 :
13331 : /** Return a band whose each pixel value is the natural logarithm of the
13332 : * corresponding pixel value in the input band.
13333 : *
13334 : * The resulting band is lazy evaluated. A reference is taken on input
13335 : * datasets.
13336 : *
13337 : * @since 3.12
13338 : */
13339 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
13340 : {
13341 : #ifndef HAVE_MUPARSER
13342 : (void)band;
13343 : return ThrowIfNotMuparser();
13344 : #else
13345 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13346 1 : band);
13347 : #endif
13348 : }
13349 : } // namespace gdal
13350 :
13351 : /************************************************************************/
13352 : /* gdal::log10() */
13353 : /************************************************************************/
13354 :
13355 : namespace gdal
13356 : {
13357 :
13358 : /** Return a band whose each pixel value is the logarithm base 10 of the
13359 : * corresponding pixel value in the input band.
13360 : *
13361 : * The resulting band is lazy evaluated. A reference is taken on input
13362 : * datasets.
13363 : *
13364 : * @since 3.12
13365 : */
13366 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
13367 : {
13368 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13369 1 : band);
13370 : }
13371 : } // namespace gdal
13372 :
13373 : /************************************************************************/
13374 : /* gdal::pow() */
13375 : /************************************************************************/
13376 :
13377 : namespace gdal
13378 : {
13379 :
13380 : #ifndef DOXYGEN_SKIP
13381 : /** Return a band whose each pixel value is the constant raised to the power of
13382 : * the corresponding pixel value in the input band.
13383 : *
13384 : * The resulting band is lazy evaluated. A reference is taken on input
13385 : * datasets.
13386 : *
13387 : * @since 3.12
13388 : */
13389 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13390 : {
13391 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13392 1 : constant, band);
13393 : }
13394 : #endif
13395 :
13396 : } // namespace gdal
13397 :
13398 : /************************************************************************/
13399 : /* gdal::pow() */
13400 : /************************************************************************/
13401 :
13402 : namespace gdal
13403 : {
13404 :
13405 : /** Return a band whose each pixel value is the the corresponding pixel value
13406 : * in the input band raised to the power of the constant.
13407 : *
13408 : * The resulting band is lazy evaluated. A reference is taken on input
13409 : * datasets.
13410 : *
13411 : * @since 3.12
13412 : */
13413 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13414 : {
13415 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13416 1 : band, constant);
13417 : }
13418 : } // namespace gdal
13419 :
13420 : /************************************************************************/
13421 : /* gdal::pow() */
13422 : /************************************************************************/
13423 :
13424 : namespace gdal
13425 : {
13426 :
13427 : #ifndef DOXYGEN_SKIP
13428 : /** Return a band whose each pixel value is the the corresponding pixel value
13429 : * in the input band1 raised to the power of the corresponding pixel value
13430 : * in the input band2
13431 : *
13432 : * The resulting band is lazy evaluated. A reference is taken on input
13433 : * datasets.
13434 : *
13435 : * @since 3.12
13436 : * @throw std::runtime_error if bands do not have the same dimensions.
13437 : */
13438 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
13439 : const GDALRasterBand &band2)
13440 : {
13441 : #ifndef HAVE_MUPARSER
13442 : (void)band1;
13443 : (void)band2;
13444 : return ThrowIfNotMuparser();
13445 : #else
13446 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13447 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13448 1 : band1, band2);
13449 : #endif
13450 : }
13451 : #endif
13452 : } // namespace gdal
|