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 "gdal.h"
42 : #include "gdal_abstractbandblockcache.h"
43 : #include "gdalantirecursion.h"
44 : #include "gdal_rat.h"
45 : #include "gdal_rasterband.h"
46 : #include "gdal_priv_templates.hpp"
47 : #include "gdal_interpolateatpoint.h"
48 : #include "gdal_minmax_element.hpp"
49 : #include "gdalmultidim_priv.h"
50 : #include "gdal_thread_pool.h"
51 :
52 : #ifdef USE_NEON_OPTIMIZATIONS
53 : #include "include_sse2neon.h"
54 : #endif
55 :
56 : #if defined(__AVX2__) || defined(__FMA__)
57 : #include <immintrin.h>
58 : #endif
59 :
60 : /************************************************************************/
61 : /* GDALRasterBand() */
62 : /************************************************************************/
63 :
64 : /*! Constructor. Applications should never create GDALRasterBands directly. */
65 :
66 1577630 : GDALRasterBand::GDALRasterBand()
67 : : GDALRasterBand(
68 1577630 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
69 : {
70 1577630 : }
71 :
72 : /** Constructor. Applications should never create GDALRasterBands directly.
73 : * @param bForceCachedIOIn Whether cached IO should be forced.
74 : */
75 1858830 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
76 1858830 : : bForceCachedIO(bForceCachedIOIn)
77 :
78 : {
79 1858830 : }
80 :
81 : /************************************************************************/
82 : /* ~GDALRasterBand() */
83 : /************************************************************************/
84 :
85 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
86 : instead destroy the GDALDataset. */
87 :
88 1858820 : GDALRasterBand::~GDALRasterBand()
89 :
90 : {
91 1858820 : if (poDS && poDS->IsMarkedSuppressOnClose())
92 : {
93 574 : if (poBandBlockCache)
94 511 : poBandBlockCache->DisableDirtyBlockWriting();
95 : }
96 1858820 : GDALRasterBand::FlushCache(true);
97 :
98 1858820 : delete poBandBlockCache;
99 :
100 1858820 : if (static_cast<GIntBig>(nBlockReads) >
101 1858820 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
102 228 : nBand == 1 && poDS != nullptr)
103 : {
104 336 : CPLDebug(
105 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
106 168 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
107 168 : poDS->GetDescription());
108 : }
109 :
110 1858820 : InvalidateMaskBand();
111 1858820 : nBand = -nBand;
112 :
113 1858820 : delete m_poPointsCache;
114 1858820 : }
115 :
116 : /************************************************************************/
117 : /* RasterIO() */
118 : /************************************************************************/
119 :
120 : /**
121 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
122 : * int nXOff, int nYOff, int nXSize, int nYSize,
123 : * void * pData, int nBufXSize, int nBufYSize,
124 : * GDALDataType eBufType,
125 : * GSpacing nPixelSpace,
126 : * GSpacing nLineSpace,
127 : * GDALRasterIOExtraArg* psExtraArg )
128 : * \brief Read/write a region of image data for this band.
129 : *
130 : * This method allows reading a region of a GDALRasterBand into a buffer,
131 : * or writing data from a buffer into a region of a GDALRasterBand. It
132 : * automatically takes care of data type translation if the data type
133 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
134 : * The method also takes care of image decimation / replication if the
135 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
136 : * region being accessed (nXSize x nYSize).
137 : *
138 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
139 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
140 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
141 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
142 : * Or use nLineSpace and a possibly shifted pData value.
143 : *
144 : * The nPixelSpace and nLineSpace parameters allow reading into or
145 : * writing from unusually organized buffers. This is primarily used
146 : * for buffers containing more than one bands raster data in interleaved
147 : * format.
148 : *
149 : * Some formats may efficiently implement decimation into a buffer by
150 : * reading from lower resolution overview images. The logic of the default
151 : * implementation in the base class GDALRasterBand is the following one. It
152 : * computes a target_downscaling_factor from the window of interest and buffer
153 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
154 : * It then walks through overviews and will select the first one whose
155 : * downscaling factor is greater than target_downscaling_factor / 1.2.
156 : *
157 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
158 : * The relationship between target_downscaling_factor and the select overview
159 : * level is the following one:
160 : *
161 : * target_downscaling_factor | selected_overview
162 : * ------------------------- | -----------------
163 : * ]0, 2 / 1.2] | full resolution band
164 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
165 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
166 : * ]8 / 1.2, infinity[ | 8x downsampled band
167 : *
168 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
169 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
170 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
171 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
172 : * this oversampling threshold defaults to 1. Consequently if there are overviews
173 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
174 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
175 : *
176 : * For highest performance full resolution data access, read and write
177 : * on "block boundaries" as returned by GetBlockSize(), or use the
178 : * ReadBlock() and WriteBlock() methods.
179 : *
180 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
181 : * functions.
182 : *
183 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
184 : * write a region of data.
185 : *
186 : * @param nXOff The pixel offset to the top left corner of the region
187 : * of the band to be accessed. This would be zero to start from the left side.
188 : *
189 : * @param nYOff The line offset to the top left corner of the region
190 : * of the band to be accessed. This would be zero to start from the top.
191 : *
192 : * @param nXSize The width of the region of the band to be accessed in pixels.
193 : *
194 : * @param nYSize The height of the region of the band to be accessed in lines.
195 : *
196 : * @param pData The buffer into which the data should be read, or from which
197 : * it should be written. This buffer must contain at least nBufXSize *
198 : * nBufYSize words of type eBufType. It is organized in left to right,
199 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
200 : * and nLineSpace parameters.
201 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
202 : * temporarily modified during the execution of this method (and eventually
203 : * restored back to its original content), so it is not safe to use a buffer
204 : * stored in a read-only section of the calling program.
205 : *
206 : * @param nBufXSize the width of the buffer image into which the desired region
207 : * is to be read, or from which it is to be written.
208 : *
209 : * @param nBufYSize the height of the buffer image into which the desired region
210 : * is to be read, or from which it is to be written.
211 : *
212 : * @param eBufType the type of the pixel values in the pData data buffer. The
213 : * pixel values will automatically be translated to/from the GDALRasterBand
214 : * data type as needed. Most driver implementations will use GDALCopyWords64()
215 : * to perform data type translation.
216 : *
217 : * @param nPixelSpace The byte offset from the start of one pixel value in
218 : * pData to the start of the next pixel value within a scanline. If defaulted
219 : * (0) the size of the datatype eBufType is used.
220 : *
221 : * @param nLineSpace The byte offset from the start of one scanline in
222 : * pData to the start of the next. If defaulted (0) the size of the datatype
223 : * eBufType * nBufXSize is used.
224 : *
225 : * @param psExtraArg Pointer to a GDALRasterIOExtraArg
226 : * structure with additional arguments to specify resampling and progress
227 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
228 : * configuration option can also be defined to override the default resampling
229 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
230 : *
231 : * @return CE_Failure if the access fails, otherwise CE_None.
232 : */
233 :
234 : /**
235 : * \brief Read/write a region of image data for this band.
236 : *
237 : * This method allows reading a region of a GDALRasterBand into a buffer,
238 : * or writing data from a buffer into a region of a GDALRasterBand. It
239 : * automatically takes care of data type translation if the data type
240 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
241 : * The method also takes care of image decimation / replication if the
242 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
243 : * region being accessed (nXSize x nYSize).
244 : *
245 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
246 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
247 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
248 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
249 : * Or use nLineSpace and a possibly shifted pData value.
250 : *
251 : * The nPixelSpace and nLineSpace parameters allow reading into or
252 : * writing from unusually organized buffers. This is primarily used
253 : * for buffers containing more than one bands raster data in interleaved
254 : * format.
255 : *
256 : * Some formats may efficiently implement decimation into a buffer by
257 : * reading from lower resolution overview images. The logic of the default
258 : * implementation in the base class GDALRasterBand is the following one. It
259 : * computes a target_downscaling_factor from the window of interest and buffer
260 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
261 : * It then walks through overviews and will select the first one whose
262 : * downscaling factor is greater than target_downscaling_factor / 1.2.
263 : *
264 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
265 : * The relationship between target_downscaling_factor and the select overview
266 : * level is the following one:
267 : *
268 : * target_downscaling_factor | selected_overview
269 : * ------------------------- | -----------------
270 : * ]0, 2 / 1.2] | full resolution band
271 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
272 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
273 : * ]8 / 1.2, infinity[ | 8x downsampled band
274 : *
275 : * For highest performance full resolution data access, read and write
276 : * on "block boundaries" as returned by GetBlockSize(), or use the
277 : * ReadBlock() and WriteBlock() methods.
278 : *
279 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
280 : * functions.
281 : *
282 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
283 : * more convenient to use for most common use cases.
284 : *
285 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
286 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
287 : * instance of this dataset) concurrently from several threads.
288 : *
289 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
290 : * write a region of data.
291 : *
292 : * @param nXOff The pixel offset to the top left corner of the region
293 : * of the band to be accessed. This would be zero to start from the left side.
294 : *
295 : * @param nYOff The line offset to the top left corner of the region
296 : * of the band to be accessed. This would be zero to start from the top.
297 : *
298 : * @param nXSize The width of the region of the band to be accessed in pixels.
299 : *
300 : * @param nYSize The height of the region of the band to be accessed in lines.
301 : *
302 : * @param[in,out] pData The buffer into which the data should be read, or from
303 : * which it should be written. This buffer must contain at least nBufXSize *
304 : * nBufYSize words of type eBufType. It is organized in left to right,
305 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
306 : * and nLineSpace parameters.
307 : *
308 : * @param nBufXSize the width of the buffer image into which the desired region
309 : * is to be read, or from which it is to be written.
310 : *
311 : * @param nBufYSize the height of the buffer image into which the desired region
312 : * is to be read, or from which it is to be written.
313 : *
314 : * @param eBufType the type of the pixel values in the pData data buffer. The
315 : * pixel values will automatically be translated to/from the GDALRasterBand
316 : * data type as needed.
317 : *
318 : * @param nPixelSpace The byte offset from the start of one pixel value in
319 : * pData to the start of the next pixel value within a scanline. If defaulted
320 : * (0) the size of the datatype eBufType is used.
321 : *
322 : * @param nLineSpace The byte offset from the start of one scanline in
323 : * pData to the start of the next. If defaulted (0) the size of the datatype
324 : * eBufType * nBufXSize is used.
325 : *
326 : * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
327 : * structure with additional arguments to specify resampling and progress
328 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
329 : * configuration option can also be defined to override the default resampling
330 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
331 : *
332 : * @return CE_Failure if the access fails, otherwise CE_None.
333 : *
334 : * @see GDALRasterBand::ReadRaster()
335 : */
336 :
337 4422020 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
338 : int nXSize, int nYSize, void *pData,
339 : int nBufXSize, int nBufYSize,
340 : GDALDataType eBufType, GSpacing nPixelSpace,
341 : GSpacing nLineSpace,
342 : GDALRasterIOExtraArg *psExtraArg)
343 :
344 : {
345 : GDALRasterIOExtraArg sExtraArg;
346 4422020 : if (psExtraArg == nullptr)
347 : {
348 3823730 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
349 3823730 : psExtraArg = &sExtraArg;
350 : }
351 598291 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
352 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
353 : {
354 0 : ReportError(CE_Failure, CPLE_AppDefined,
355 : "Unhandled version of GDALRasterIOExtraArg");
356 0 : return CE_Failure;
357 : }
358 :
359 4422020 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
360 : nBufYSize);
361 :
362 4422020 : if (CPL_UNLIKELY(nullptr == pData))
363 : {
364 0 : ReportError(CE_Failure, CPLE_AppDefined,
365 : "The buffer into which the data should be read is null");
366 0 : return CE_Failure;
367 : }
368 :
369 : /* -------------------------------------------------------------------- */
370 : /* Some size values are "noop". Lets just return to avoid */
371 : /* stressing lower level functions. */
372 : /* -------------------------------------------------------------------- */
373 4422020 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
374 : nBufYSize < 1))
375 : {
376 2 : CPLDebug("GDAL",
377 : "RasterIO() skipped for odd window or buffer size.\n"
378 : " Window = (%d,%d)x%dx%d\n"
379 : " Buffer = %dx%d\n",
380 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
381 :
382 2 : return CE_None;
383 : }
384 :
385 4422020 : if (eRWFlag == GF_Write)
386 : {
387 366961 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
388 : {
389 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
390 : "An error occurred while writing a dirty block "
391 : "from GDALRasterBand::RasterIO");
392 0 : CPLErr eErr = eFlushBlockErr;
393 0 : eFlushBlockErr = CE_None;
394 0 : return eErr;
395 : }
396 366961 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
397 : {
398 7 : return CE_Failure;
399 : }
400 : }
401 :
402 : /* -------------------------------------------------------------------- */
403 : /* If pixel and line spacing are defaulted assign reasonable */
404 : /* value assuming a packed buffer. */
405 : /* -------------------------------------------------------------------- */
406 4422020 : if (nPixelSpace == 0)
407 : {
408 4023690 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
409 : }
410 :
411 4422020 : if (nLineSpace == 0)
412 : {
413 4011340 : nLineSpace = nPixelSpace * nBufXSize;
414 : }
415 :
416 : /* -------------------------------------------------------------------- */
417 : /* Do some validation of parameters. */
418 : /* -------------------------------------------------------------------- */
419 4422020 : if (CPL_UNLIKELY(nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
420 : nYSize > nRasterYSize - nYOff))
421 : {
422 15 : ReportError(CE_Failure, CPLE_IllegalArg,
423 : "Access window out of range in RasterIO(). Requested\n"
424 : "(%d,%d) of size %dx%d on raster of %dx%d.",
425 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
426 15 : return CE_Failure;
427 : }
428 :
429 4422000 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
430 : {
431 0 : ReportError(
432 : CE_Failure, CPLE_IllegalArg,
433 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
434 : eRWFlag);
435 0 : return CE_Failure;
436 : }
437 4422000 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
438 : {
439 2 : ReportError(CE_Failure, CPLE_IllegalArg,
440 : "Illegal GDT_Unknown/GDT_TypeCount argument");
441 2 : return CE_Failure;
442 : }
443 :
444 4422000 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
445 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
446 4422000 : nLineSpace, psExtraArg);
447 : }
448 :
449 : /************************************************************************/
450 : /* RasterIOInternal() */
451 : /************************************************************************/
452 :
453 4422030 : CPLErr GDALRasterBand::RasterIOInternal(
454 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
455 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
456 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
457 : {
458 : /* -------------------------------------------------------------------- */
459 : /* Call the format specific function. */
460 : /* -------------------------------------------------------------------- */
461 :
462 4422030 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
463 :
464 : CPLErr eErr;
465 4422030 : if (bForceCachedIO)
466 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
467 : pData, nBufXSize, nBufYSize, eBufType,
468 : nPixelSpace, nLineSpace, psExtraArg);
469 : else
470 : eErr =
471 4422010 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
472 4422010 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
473 :
474 4422030 : if (bCallLeaveReadWrite)
475 603484 : LeaveReadWrite();
476 :
477 4422030 : return eErr;
478 : }
479 :
480 : /************************************************************************/
481 : /* GDALRasterIO() */
482 : /************************************************************************/
483 :
484 : /**
485 : * \brief Read/write a region of image data for this band.
486 : *
487 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
488 : * resolution, progress callback, etc. are needed)
489 : *
490 : * @see GDALRasterBand::RasterIO()
491 : */
492 :
493 3407950 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
494 : int nXOff, int nYOff, int nXSize, int nYSize,
495 : void *pData, int nBufXSize, int nBufYSize,
496 : GDALDataType eBufType, int nPixelSpace,
497 : int nLineSpace)
498 :
499 : {
500 3407950 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
501 :
502 3407950 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
503 :
504 3407950 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
505 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
506 3407950 : nLineSpace, nullptr));
507 : }
508 :
509 : /************************************************************************/
510 : /* GDALRasterIOEx() */
511 : /************************************************************************/
512 :
513 : /**
514 : * \brief Read/write a region of image data for this band.
515 : *
516 : * @see GDALRasterBand::RasterIO()
517 : */
518 :
519 41332 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
520 : int nXOff, int nYOff, int nXSize, int nYSize,
521 : void *pData, int nBufXSize, int nBufYSize,
522 : GDALDataType eBufType, GSpacing nPixelSpace,
523 : GSpacing nLineSpace,
524 : GDALRasterIOExtraArg *psExtraArg)
525 :
526 : {
527 41332 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
528 :
529 41332 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
530 :
531 41332 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
532 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
533 41332 : nLineSpace, psExtraArg));
534 : }
535 :
536 : /************************************************************************/
537 : /* GetGDTFromCppType() */
538 : /************************************************************************/
539 :
540 : namespace
541 : {
542 : template <class T> struct GetGDTFromCppType;
543 :
544 : #define DEFINE_GetGDTFromCppType(T, eDT) \
545 : template <> struct GetGDTFromCppType<T> \
546 : { \
547 : static constexpr GDALDataType GDT = eDT; \
548 : }
549 :
550 : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
551 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
552 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
553 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
554 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
555 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
556 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
557 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
558 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
559 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
560 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
561 : // Not allowed by C++ standard
562 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
563 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
564 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
565 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
566 : } // namespace
567 :
568 : /************************************************************************/
569 : /* ReadRaster() */
570 : /************************************************************************/
571 :
572 : // clang-format off
573 : /** Read a region of image data for this band.
574 : *
575 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
576 : * for common use cases, like reading a whole band.
577 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
578 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
579 : * float, double, std::complex<float|double>.
580 : *
581 : * 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>&,
582 : * and can allocate memory automatically.
583 : *
584 : * To read a whole band (assuming it fits into memory), as an array of double:
585 : *
586 : \code{.cpp}
587 : double* myArray = static_cast<double*>(
588 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
589 : // TODO: check here that myArray != nullptr
590 : const size_t nArrayEltCount =
591 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
592 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
593 : {
594 : // do something
595 : }
596 : VSIFree(myArray)
597 : \endcode
598 : *
599 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
600 : *
601 : \code{.cpp}
602 : double* myArray = static_cast<double*>(
603 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
604 : // TODO: check here that myArray != nullptr
605 : const size_t nArrayEltCount = 128 * 128;
606 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
607 : {
608 : // do something
609 : }
610 : VSIFree(myArray)
611 : \endcode
612 : *
613 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
614 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
615 : * instance of this dataset) concurrently from several threads.
616 : *
617 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
618 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
619 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
620 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
621 : * Or use nLineSpace and a possibly shifted pData value.
622 : *
623 : * @param[out] pData The buffer into which the data should be written.
624 : * This buffer must contain at least nBufXSize *
625 : * nBufYSize words of type T. It is organized in left to right,
626 : * top to bottom pixel order, and fully packed.
627 : * The type of the buffer does not need to be the one of GetDataType(). The
628 : * method will perform data type translation (with potential rounding, clamping)
629 : * if needed.
630 : *
631 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
632 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
633 : * return in error if it is not. If set to zero, then pData is trusted to be
634 : * large enough.
635 : *
636 : * @param dfXOff The pixel offset to the top left corner of the region
637 : * of the band to be accessed. This would be zero to start from the left side.
638 : * Defaults to 0.
639 : *
640 : * @param dfYOff The line offset to the top left corner of the region
641 : * of the band to be accessed. This would be zero to start from the top.
642 : * Defaults to 0.
643 : *
644 : * @param dfXSize The width of the region of the band to be accessed in pixels.
645 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
646 : * dfXSize is set to the band width.
647 : *
648 : * @param dfYSize The height of the region of the band to be accessed in lines.
649 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
650 : * dfYSize is set to the band height.
651 : *
652 : * @param nBufXSize the width of the buffer image into which the desired region
653 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
654 : * then nBufXSize is initialized with dfXSize.
655 : *
656 : * @param nBufYSize the height of the buffer image into which the desired region
657 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
658 : * then nBufYSize is initialized with dfYSize.
659 : *
660 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
661 : *
662 : * @param pfnProgress Progress function. May be nullptr.
663 : *
664 : * @param pProgressData User data of pfnProgress. May be nullptr.
665 : *
666 : * @return CE_Failure if the access fails, otherwise CE_None.
667 : *
668 : * @see GDALRasterBand::RasterIO()
669 : * @since GDAL 3.10
670 : */
671 : // clang-format on
672 :
673 : template <class T>
674 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
675 : double dfXOff, double dfYOff, double dfXSize,
676 : double dfYSize, size_t nBufXSize,
677 : size_t nBufYSize,
678 : GDALRIOResampleAlg eResampleAlg,
679 : GDALProgressFunc pfnProgress,
680 : void *pProgressData) const
681 : {
682 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
683 : {
684 2 : return CE_Failure;
685 : }
686 :
687 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
688 : {
689 16 : dfXSize = nRasterXSize;
690 16 : dfYSize = nRasterYSize;
691 : }
692 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
693 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
694 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
695 2 : dfYOff + dfYSize > INT_MAX)
696 : {
697 0 : return CE_Failure;
698 : }
699 :
700 : GDALRasterIOExtraArg sExtraArg;
701 18 : sExtraArg.nVersion = 1;
702 18 : sExtraArg.eResampleAlg = eResampleAlg;
703 18 : sExtraArg.pfnProgress = pfnProgress;
704 18 : sExtraArg.pProgressData = pProgressData;
705 18 : sExtraArg.bFloatingPointWindowValidity = true;
706 18 : sExtraArg.dfXOff = dfXOff;
707 18 : sExtraArg.dfYOff = dfYOff;
708 18 : sExtraArg.dfXSize = dfXSize;
709 18 : sExtraArg.dfYSize = dfYSize;
710 18 : const int nXOff = static_cast<int>(dfXOff);
711 18 : const int nYOff = static_cast<int>(dfYOff);
712 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
713 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
714 18 : if (nBufXSize == 0 && nBufYSize == 0)
715 : {
716 17 : if (static_cast<int>(dfXSize) == dfXSize &&
717 17 : static_cast<int>(dfYSize) == dfYSize)
718 : {
719 17 : nBufXSize = static_cast<int>(dfXSize);
720 17 : nBufYSize = static_cast<int>(dfYSize);
721 : }
722 : else
723 : {
724 0 : CPLError(CE_Failure, CPLE_AppDefined,
725 : "nBufXSize and nBufYSize must be provided if dfXSize or "
726 : "dfYSize is not an integer value");
727 0 : return CE_Failure;
728 : }
729 : }
730 18 : if (nBufXSize == 0 || nBufYSize == 0)
731 : {
732 0 : CPLDebug("GDAL",
733 : "RasterIO() skipped for odd window or buffer size.\n"
734 : " Window = (%d,%d)x%dx%d\n"
735 : " Buffer = %dx%d\n",
736 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
737 : static_cast<int>(nBufYSize));
738 :
739 0 : return CE_None;
740 : }
741 :
742 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
743 : {
744 1 : CPLError(CE_Failure, CPLE_AppDefined,
745 : "Provided array is not large enough");
746 1 : return CE_Failure;
747 : }
748 :
749 17 : constexpr GSpacing nPixelSpace = sizeof(T);
750 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
751 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
752 :
753 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
754 :
755 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
756 : static_cast<int>(nBufXSize),
757 : static_cast<int>(nBufYSize), eBufType,
758 17 : nPixelSpace, nLineSpace, &sExtraArg);
759 : }
760 :
761 : //! @cond Doxygen_Suppress
762 :
763 : #define INSTANTIATE_READ_RASTER(T) \
764 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
765 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
766 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
767 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
768 : void *pProgressData) const;
769 :
770 : INSTANTIATE_READ_RASTER(uint8_t)
771 : INSTANTIATE_READ_RASTER(int8_t)
772 : INSTANTIATE_READ_RASTER(uint16_t)
773 : INSTANTIATE_READ_RASTER(int16_t)
774 : INSTANTIATE_READ_RASTER(uint32_t)
775 : INSTANTIATE_READ_RASTER(int32_t)
776 : INSTANTIATE_READ_RASTER(uint64_t)
777 : INSTANTIATE_READ_RASTER(int64_t)
778 : INSTANTIATE_READ_RASTER(GFloat16)
779 : INSTANTIATE_READ_RASTER(float)
780 : INSTANTIATE_READ_RASTER(double)
781 : // Not allowed by C++ standard
782 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
783 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
784 : INSTANTIATE_READ_RASTER(std::complex<float>)
785 : INSTANTIATE_READ_RASTER(std::complex<double>)
786 :
787 : //! @endcond
788 :
789 : /************************************************************************/
790 : /* ReadRaster() */
791 : /************************************************************************/
792 :
793 : /** Read a region of image data for this band.
794 : *
795 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
796 : * for common use cases, like reading a whole band.
797 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
798 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
799 : * float, double, std::complex<float|double>.
800 : *
801 : * To read a whole band (assuming it fits into memory), as a vector of double:
802 : *
803 : \code
804 : std::vector<double> myArray;
805 : if (poBand->ReadRaster(myArray) == CE_None)
806 : {
807 : // do something
808 : }
809 : \endcode
810 : *
811 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
812 : *
813 : \code{.cpp}
814 : std::vector<double> myArray;
815 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
816 : {
817 : // do something
818 : }
819 : \endcode
820 : *
821 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
822 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
823 : * instance of this dataset) concurrently from several threads.
824 : *
825 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
826 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
827 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
828 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
829 : * Or use nLineSpace and a possibly shifted pData value.
830 : *
831 : * @param[out] vData The vector into which the data should be written.
832 : * The vector will be resized, if needed, to contain at least nBufXSize *
833 : * nBufYSize values. The values in the vector are organized in left to right,
834 : * top to bottom pixel order, and fully packed.
835 : * The type of the vector does not need to be the one of GetDataType(). The
836 : * method will perform data type translation (with potential rounding, clamping)
837 : * if needed.
838 : *
839 : * @param dfXOff The pixel offset to the top left corner of the region
840 : * of the band to be accessed. This would be zero to start from the left side.
841 : * Defaults to 0.
842 : *
843 : * @param dfYOff The line offset to the top left corner of the region
844 : * of the band to be accessed. This would be zero to start from the top.
845 : * Defaults to 0.
846 : *
847 : * @param dfXSize The width of the region of the band to be accessed in pixels.
848 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
849 : * dfXSize is set to the band width.
850 : *
851 : * @param dfYSize The height of the region of the band to be accessed in lines.
852 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
853 : * dfYSize is set to the band height.
854 : *
855 : * @param nBufXSize the width of the buffer image into which the desired region
856 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
857 : * then nBufXSize is initialized with dfXSize.
858 : *
859 : * @param nBufYSize the height of the buffer image into which the desired region
860 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
861 : * then nBufYSize is initialized with dfYSize.
862 : *
863 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
864 : *
865 : * @param pfnProgress Progress function. May be nullptr.
866 : *
867 : * @param pProgressData User data of pfnProgress. May be nullptr.
868 : *
869 : * @return CE_Failure if the access fails, otherwise CE_None.
870 : *
871 : * @see GDALRasterBand::RasterIO()
872 : * @since GDAL 3.10
873 : */
874 : template <class T>
875 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
876 : double dfYOff, double dfXSize, double dfYSize,
877 : size_t nBufXSize, size_t nBufYSize,
878 : GDALRIOResampleAlg eResampleAlg,
879 : GDALProgressFunc pfnProgress,
880 : void *pProgressData) const
881 : {
882 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
883 : {
884 2 : return CE_Failure;
885 : }
886 :
887 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
888 : {
889 13 : dfXSize = nRasterXSize;
890 13 : dfYSize = nRasterYSize;
891 : }
892 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
893 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
894 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
895 7 : dfYOff + dfYSize > INT_MAX)
896 : {
897 0 : return CE_Failure;
898 : }
899 :
900 : GDALRasterIOExtraArg sExtraArg;
901 20 : sExtraArg.nVersion = 1;
902 20 : sExtraArg.eResampleAlg = eResampleAlg;
903 20 : sExtraArg.pfnProgress = pfnProgress;
904 20 : sExtraArg.pProgressData = pProgressData;
905 20 : sExtraArg.bFloatingPointWindowValidity = true;
906 20 : sExtraArg.dfXOff = dfXOff;
907 20 : sExtraArg.dfYOff = dfYOff;
908 20 : sExtraArg.dfXSize = dfXSize;
909 20 : sExtraArg.dfYSize = dfYSize;
910 20 : const int nXOff = static_cast<int>(dfXOff);
911 20 : const int nYOff = static_cast<int>(dfYOff);
912 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
913 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
914 20 : if (nBufXSize == 0 && nBufYSize == 0)
915 : {
916 16 : if (static_cast<int>(dfXSize) == dfXSize &&
917 15 : static_cast<int>(dfYSize) == dfYSize)
918 : {
919 15 : nBufXSize = static_cast<int>(dfXSize);
920 15 : nBufYSize = static_cast<int>(dfYSize);
921 : }
922 : else
923 : {
924 1 : CPLError(CE_Failure, CPLE_AppDefined,
925 : "nBufXSize and nBufYSize must be provided if "
926 : "dfXSize or dfYSize is not an integer value");
927 1 : return CE_Failure;
928 : }
929 : }
930 19 : if (nBufXSize == 0 || nBufYSize == 0)
931 : {
932 0 : CPLDebug("GDAL",
933 : "RasterIO() skipped for odd window or buffer size.\n"
934 : " Window = (%d,%d)x%dx%d\n"
935 : " Buffer = %dx%d\n",
936 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
937 : static_cast<int>(nBufYSize));
938 :
939 0 : return CE_None;
940 : }
941 :
942 : if constexpr (SIZEOF_VOIDP < 8)
943 : {
944 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
945 : {
946 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
947 : return CE_Failure;
948 : }
949 : }
950 :
951 19 : if (vData.size() < nBufXSize * nBufYSize)
952 : {
953 : try
954 : {
955 17 : vData.resize(nBufXSize * nBufYSize);
956 : }
957 1 : catch (const std::exception &)
958 : {
959 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
960 1 : return CE_Failure;
961 : }
962 : }
963 :
964 18 : constexpr GSpacing nPixelSpace = sizeof(T);
965 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
966 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
967 :
968 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
969 :
970 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
971 : vData.data(), static_cast<int>(nBufXSize),
972 : static_cast<int>(nBufYSize), eBufType,
973 18 : nPixelSpace, nLineSpace, &sExtraArg);
974 : }
975 :
976 : //! @cond Doxygen_Suppress
977 :
978 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
979 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
980 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
981 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
982 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
983 : void *pProgressData) const;
984 :
985 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
986 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
988 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
989 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
990 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
991 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
992 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
993 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
994 : INSTANTIATE_READ_RASTER_VECTOR(float)
995 : INSTANTIATE_READ_RASTER_VECTOR(double)
996 : // Not allowed by C++ standard
997 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
998 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
999 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1000 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1001 :
1002 : //! @endcond
1003 :
1004 : /************************************************************************/
1005 : /* ReadBlock() */
1006 : /************************************************************************/
1007 :
1008 : /**
1009 : * \brief Read a block of image data efficiently.
1010 : *
1011 : * This method accesses a "natural" block from the raster band without
1012 : * resampling, or data type conversion. For a more generalized, but
1013 : * potentially less efficient access use RasterIO().
1014 : *
1015 : * This method is the same as the C GDALReadBlock() function.
1016 : *
1017 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1018 : * block oriented data without an extra copy into an application buffer.
1019 : *
1020 : * The following code would efficiently compute a histogram of eight bit
1021 : * raster data. Note that the final block may be partial ... data beyond
1022 : * the edge of the underlying raster band in these edge blocks is of an
1023 : * undetermined value.
1024 : *
1025 : \code{.cpp}
1026 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1027 :
1028 : {
1029 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1030 :
1031 : CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1032 :
1033 : int nXBlockSize, nYBlockSize;
1034 :
1035 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1036 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1037 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1038 :
1039 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1040 :
1041 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1042 : {
1043 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1044 : {
1045 : int nXValid, nYValid;
1046 :
1047 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1048 :
1049 : // Compute the portion of the block that is valid
1050 : // for partial edge blocks.
1051 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1052 :
1053 : // Collect the histogram counts.
1054 : for( int iY = 0; iY < nYValid; iY++ )
1055 : {
1056 : for( int iX = 0; iX < nXValid; iX++ )
1057 : {
1058 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1059 : }
1060 : }
1061 : }
1062 : }
1063 : }
1064 : \endcode
1065 : *
1066 : * @param nXBlockOff the horizontal block offset, with zero indicating
1067 : * the left most block, 1 the next block and so forth.
1068 : *
1069 : * @param nYBlockOff the vertical block offset, with zero indicating
1070 : * the top most block, 1 the next block and so forth.
1071 : *
1072 : * @param pImage the buffer into which the data will be read. The buffer
1073 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1074 : * of type GetRasterDataType().
1075 : *
1076 : * @return CE_None on success or CE_Failure on an error.
1077 : */
1078 :
1079 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1080 :
1081 : {
1082 : /* -------------------------------------------------------------------- */
1083 : /* Validate arguments. */
1084 : /* -------------------------------------------------------------------- */
1085 894 : CPLAssert(pImage != nullptr);
1086 :
1087 894 : if (!InitBlockInfo())
1088 0 : return CE_Failure;
1089 :
1090 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1091 : {
1092 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1093 : "Illegal nXBlockOff value (%d) in "
1094 : "GDALRasterBand::ReadBlock()\n",
1095 : nXBlockOff);
1096 :
1097 0 : return (CE_Failure);
1098 : }
1099 :
1100 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1101 : {
1102 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1103 : "Illegal nYBlockOff value (%d) in "
1104 : "GDALRasterBand::ReadBlock()\n",
1105 : nYBlockOff);
1106 :
1107 0 : return (CE_Failure);
1108 : }
1109 :
1110 : /* -------------------------------------------------------------------- */
1111 : /* Invoke underlying implementation method. */
1112 : /* -------------------------------------------------------------------- */
1113 :
1114 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1115 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1116 894 : if (bCallLeaveReadWrite)
1117 4 : LeaveReadWrite();
1118 894 : return eErr;
1119 : }
1120 :
1121 : /************************************************************************/
1122 : /* GDALReadBlock() */
1123 : /************************************************************************/
1124 :
1125 : /**
1126 : * \brief Read a block of image data efficiently.
1127 : *
1128 : * @see GDALRasterBand::ReadBlock()
1129 : */
1130 :
1131 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1132 : void *pData)
1133 :
1134 : {
1135 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1136 :
1137 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1138 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1139 : }
1140 :
1141 : /************************************************************************/
1142 : /* IReadBlock() */
1143 : /************************************************************************/
1144 :
1145 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1146 : * ) \brief Read a block of data.
1147 : *
1148 : * Default internal implementation ... to be overridden by
1149 : * subclasses that support reading.
1150 : * @param nBlockXOff Block X Offset
1151 : * @param nBlockYOff Block Y Offset
1152 : * @param pData Pixel buffer into which to place read data.
1153 : * @return CE_None on success or CE_Failure on an error.
1154 : */
1155 :
1156 : /************************************************************************/
1157 : /* IWriteBlock() */
1158 : /************************************************************************/
1159 :
1160 : /**
1161 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1162 : * Write a block of data.
1163 : *
1164 : * Default internal implementation ... to be overridden by
1165 : * subclasses that support writing.
1166 : * @param nBlockXOff Block X Offset
1167 : * @param nBlockYOff Block Y Offset
1168 : * @param pData Pixel buffer to write
1169 : * @return CE_None on success or CE_Failure on an error.
1170 : */
1171 :
1172 : /**/
1173 : /**/
1174 :
1175 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1176 : void * /*pData*/)
1177 :
1178 : {
1179 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1180 0 : ReportError(CE_Failure, CPLE_NotSupported,
1181 : "WriteBlock() not supported for this dataset.");
1182 :
1183 0 : return (CE_Failure);
1184 : }
1185 :
1186 : /************************************************************************/
1187 : /* WriteBlock() */
1188 : /************************************************************************/
1189 :
1190 : /**
1191 : * \brief Write a block of image data efficiently.
1192 : *
1193 : * This method accesses a "natural" block from the raster band without
1194 : * resampling, or data type conversion. For a more generalized, but
1195 : * potentially less efficient access use RasterIO().
1196 : *
1197 : * This method is the same as the C GDALWriteBlock() function.
1198 : *
1199 : * See ReadBlock() for an example of block oriented data access.
1200 : *
1201 : * @param nXBlockOff the horizontal block offset, with zero indicating
1202 : * the left most block, 1 the next block and so forth.
1203 : *
1204 : * @param nYBlockOff the vertical block offset, with zero indicating
1205 : * the left most block, 1 the next block and so forth.
1206 : *
1207 : * @param pImage the buffer from which the data will be written. The buffer
1208 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1209 : * of type GetRasterDataType(). Note that the content of the buffer might be
1210 : * temporarily modified during the execution of this method (and eventually
1211 : * restored back to its original content), so it is not safe to use a buffer
1212 : * stored in a read-only section of the calling program.
1213 : *
1214 : * @return CE_None on success or CE_Failure on an error.
1215 : */
1216 :
1217 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1218 :
1219 : {
1220 : /* -------------------------------------------------------------------- */
1221 : /* Validate arguments. */
1222 : /* -------------------------------------------------------------------- */
1223 4883 : CPLAssert(pImage != nullptr);
1224 :
1225 4883 : if (!InitBlockInfo())
1226 0 : return CE_Failure;
1227 :
1228 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1229 : {
1230 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1231 : "Illegal nXBlockOff value (%d) in "
1232 : "GDALRasterBand::WriteBlock()\n",
1233 : nXBlockOff);
1234 :
1235 0 : return (CE_Failure);
1236 : }
1237 :
1238 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1239 : {
1240 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1241 : "Illegal nYBlockOff value (%d) in "
1242 : "GDALRasterBand::WriteBlock()\n",
1243 : nYBlockOff);
1244 :
1245 0 : return (CE_Failure);
1246 : }
1247 :
1248 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1249 : {
1250 0 : return CE_Failure;
1251 : }
1252 :
1253 4883 : if (eFlushBlockErr != CE_None)
1254 : {
1255 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1256 : "An error occurred while writing a dirty block "
1257 : "from GDALRasterBand::WriteBlock");
1258 0 : CPLErr eErr = eFlushBlockErr;
1259 0 : eFlushBlockErr = CE_None;
1260 0 : return eErr;
1261 : }
1262 :
1263 : /* -------------------------------------------------------------------- */
1264 : /* Invoke underlying implementation method. */
1265 : /* -------------------------------------------------------------------- */
1266 :
1267 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1268 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1269 4883 : if (bCallLeaveReadWrite)
1270 4883 : LeaveReadWrite();
1271 :
1272 4883 : return eErr;
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALWriteBlock() */
1277 : /************************************************************************/
1278 :
1279 : /**
1280 : * \brief Write a block of image data efficiently.
1281 : *
1282 : * @see GDALRasterBand::WriteBlock()
1283 : */
1284 :
1285 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1286 : void *pData)
1287 :
1288 : {
1289 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1290 :
1291 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1292 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1293 : }
1294 :
1295 : /************************************************************************/
1296 : /* EmitErrorMessageIfWriteNotSupported() */
1297 : /************************************************************************/
1298 :
1299 : /**
1300 : * Emit an error message if a write operation to this band is not supported.
1301 : *
1302 : * The base implementation will emit an error message if the access mode is
1303 : * read-only. Derived classes may implement it to provide a custom message.
1304 : *
1305 : * @param pszCaller Calling function.
1306 : * @return true if an error message has been emitted.
1307 : */
1308 641553 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1309 : const char *pszCaller) const
1310 : {
1311 641553 : if (eAccess == GA_ReadOnly)
1312 : {
1313 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1314 : "%s: attempt to write to dataset opened in read-only mode.",
1315 : pszCaller);
1316 :
1317 4 : return true;
1318 : }
1319 641549 : return false;
1320 : }
1321 :
1322 : /************************************************************************/
1323 : /* GetActualBlockSize() */
1324 : /************************************************************************/
1325 : /**
1326 : * \brief Fetch the actual block size for a given block offset.
1327 : *
1328 : * Handles partial blocks at the edges of the raster and returns the true
1329 : * number of pixels
1330 : *
1331 : * @param nXBlockOff the horizontal block offset for which to calculate the
1332 : * number of valid pixels, with zero indicating the left most block, 1 the next
1333 : * block and so forth.
1334 : *
1335 : * @param nYBlockOff the vertical block offset, with zero indicating
1336 : * the top most block, 1 the next block and so forth.
1337 : *
1338 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1339 : * the x direction will be stored
1340 : *
1341 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1342 : * the y direction will be stored
1343 : *
1344 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1345 : *
1346 : */
1347 46538 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1348 : int *pnXValid, int *pnYValid) const
1349 : {
1350 93075 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1351 93072 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1352 93068 : nYBlockOff < 0 || nBlockYSize == 0 ||
1353 46534 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1354 : {
1355 6 : return CE_Failure;
1356 : }
1357 :
1358 46532 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1359 46532 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1360 :
1361 46532 : *pnXValid = nBlockXSize;
1362 46532 : *pnYValid = nBlockYSize;
1363 :
1364 46532 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1365 : {
1366 44913 : *pnXValid = nRasterXSize - nXPixelOff;
1367 : }
1368 :
1369 46532 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1370 : {
1371 3566 : *pnYValid = nRasterYSize - nYPixelOff;
1372 : }
1373 :
1374 46532 : return CE_None;
1375 : }
1376 :
1377 : /************************************************************************/
1378 : /* GDALGetActualBlockSize() */
1379 : /************************************************************************/
1380 :
1381 : /**
1382 : * \brief Retrieve the actual block size for a given block offset.
1383 : *
1384 : * @see GDALRasterBand::GetActualBlockSize()
1385 : */
1386 :
1387 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1388 : int nYBlockOff, int *pnXValid,
1389 : int *pnYValid)
1390 :
1391 : {
1392 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1393 :
1394 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1395 : return (
1396 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1397 : }
1398 :
1399 : /************************************************************************/
1400 : /* GetSuggestedBlockAccessPattern() */
1401 : /************************************************************************/
1402 :
1403 : /**
1404 : * \brief Return the suggested/most efficient access pattern to blocks
1405 : * (for read operations).
1406 : *
1407 : * While all GDAL drivers have to expose a block size, not all can guarantee
1408 : * efficient random access (GSBAP_RANDOM) to any block.
1409 : * Some drivers for example decompress sequentially a compressed stream from
1410 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1411 : * case best performance will be achieved while reading blocks in that order.
1412 : * (accessing blocks in random access in such rasters typically causes the
1413 : * decoding to be re-initialized from the start if accessing blocks in
1414 : * a non-sequential order)
1415 : *
1416 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1417 : * returned by drivers that expose a somewhat artificial block size, because
1418 : * they can extract any part of a raster, but in a rather inefficient way.
1419 : *
1420 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1421 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1422 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1423 : * most efficient strategy is to read as many pixels as possible in the less
1424 : * RasterIO() operations.
1425 : *
1426 : * The return of this method is for example used to determine the swath size
1427 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1428 : *
1429 : * @since GDAL 3.6
1430 : */
1431 :
1432 : GDALSuggestedBlockAccessPattern
1433 2437 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1434 : {
1435 2437 : return GSBAP_UNKNOWN;
1436 : }
1437 :
1438 : /************************************************************************/
1439 : /* GetRasterDataType() */
1440 : /************************************************************************/
1441 :
1442 : /**
1443 : * \brief Fetch the pixel data type for this band.
1444 : *
1445 : * This method is the same as the C function GDALGetRasterDataType().
1446 : *
1447 : * @return the data type of pixels for this band.
1448 : */
1449 :
1450 8985920 : GDALDataType GDALRasterBand::GetRasterDataType() const
1451 :
1452 : {
1453 8985920 : return eDataType;
1454 : }
1455 :
1456 : /************************************************************************/
1457 : /* GDALGetRasterDataType() */
1458 : /************************************************************************/
1459 :
1460 : /**
1461 : * \brief Fetch the pixel data type for this band.
1462 : *
1463 : * @see GDALRasterBand::GetRasterDataType()
1464 : */
1465 :
1466 910062 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1467 :
1468 : {
1469 910062 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1470 :
1471 910062 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1472 910062 : return poBand->GetRasterDataType();
1473 : }
1474 :
1475 : /************************************************************************/
1476 : /* GetBlockSize() */
1477 : /************************************************************************/
1478 :
1479 : /**
1480 : * \brief Fetch the "natural" block size of this band.
1481 : *
1482 : * GDAL contains a concept of the natural block size of rasters so that
1483 : * applications can organized data access efficiently for some file formats.
1484 : * The natural block size is the block size that is most efficient for
1485 : * accessing the format. For many formats this is simple a whole scanline
1486 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1487 : *
1488 : * However, for tiled images this will typically be the tile size.
1489 : *
1490 : * Note that the X and Y block sizes don't have to divide the image size
1491 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1492 : * See ReadBlock() for an example of code dealing with these issues.
1493 : *
1494 : * This method is the same as the C function GDALGetBlockSize().
1495 : *
1496 : * @param pnXSize integer to put the X block size into or NULL.
1497 : *
1498 : * @param pnYSize integer to put the Y block size into or NULL.
1499 : */
1500 :
1501 5559770 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1502 :
1503 : {
1504 5559770 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1505 : {
1506 0 : ReportError(CE_Failure, CPLE_AppDefined,
1507 0 : "Invalid block dimension : %d * %d", nBlockXSize,
1508 0 : nBlockYSize);
1509 0 : if (pnXSize != nullptr)
1510 0 : *pnXSize = 0;
1511 0 : if (pnYSize != nullptr)
1512 0 : *pnYSize = 0;
1513 : }
1514 : else
1515 : {
1516 5559770 : if (pnXSize != nullptr)
1517 5559770 : *pnXSize = nBlockXSize;
1518 5559770 : if (pnYSize != nullptr)
1519 5559770 : *pnYSize = nBlockYSize;
1520 : }
1521 5559770 : }
1522 :
1523 : /************************************************************************/
1524 : /* GDALGetBlockSize() */
1525 : /************************************************************************/
1526 :
1527 : /**
1528 : * \brief Fetch the "natural" block size of this band.
1529 : *
1530 : * @see GDALRasterBand::GetBlockSize()
1531 : */
1532 :
1533 41261 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1534 : int *pnYSize)
1535 :
1536 : {
1537 41261 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1538 :
1539 41261 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1540 41261 : poBand->GetBlockSize(pnXSize, pnYSize);
1541 : }
1542 :
1543 : /************************************************************************/
1544 : /* InitBlockInfo() */
1545 : /************************************************************************/
1546 :
1547 : //! @cond Doxygen_Suppress
1548 3656100 : int GDALRasterBand::InitBlockInfo()
1549 :
1550 : {
1551 3656100 : if (poBandBlockCache != nullptr)
1552 3415860 : return poBandBlockCache->IsInitOK();
1553 :
1554 : /* Do some validation of raster and block dimensions in case the driver */
1555 : /* would have neglected to do it itself */
1556 240241 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1557 : {
1558 0 : ReportError(CE_Failure, CPLE_AppDefined,
1559 : "Invalid block dimension : %d * %d", nBlockXSize,
1560 : nBlockYSize);
1561 0 : return FALSE;
1562 : }
1563 :
1564 240241 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1565 : {
1566 0 : ReportError(CE_Failure, CPLE_AppDefined,
1567 : "Invalid raster dimension : %d * %d", nRasterXSize,
1568 : nRasterYSize);
1569 0 : return FALSE;
1570 : }
1571 :
1572 240241 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1573 240241 : if (nDataTypeSize == 0)
1574 : {
1575 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1576 0 : return FALSE;
1577 : }
1578 :
1579 : #if SIZEOF_VOIDP == 4
1580 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1581 : {
1582 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1583 : * multiplication in other cases */
1584 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1585 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1586 : {
1587 : ReportError(CE_Failure, CPLE_NotSupported,
1588 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1589 : nBlockYSize);
1590 : return FALSE;
1591 : }
1592 : }
1593 : #endif
1594 :
1595 240241 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1596 240241 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1597 :
1598 : const char *pszBlockStrategy =
1599 240241 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1600 240241 : bool bUseArray = true;
1601 240241 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1602 : {
1603 240201 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1604 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1605 : {
1606 240182 : GUIntBig nBlockCount =
1607 240182 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1608 240182 : if (poDS != nullptr)
1609 239978 : nBlockCount *= poDS->GetRasterCount();
1610 240182 : bUseArray = (nBlockCount < 1024 * 1024);
1611 : }
1612 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1613 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1614 : {
1615 0 : bUseArray = false;
1616 240201 : }
1617 : }
1618 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1619 40 : bUseArray = false;
1620 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1621 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1622 : pszBlockStrategy);
1623 :
1624 240241 : if (bUseArray)
1625 240170 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1626 : else
1627 : {
1628 71 : if (nBand == 1)
1629 26 : CPLDebug("GDAL", "Use hashset band block cache");
1630 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1631 : }
1632 240241 : if (poBandBlockCache == nullptr)
1633 0 : return FALSE;
1634 240241 : return poBandBlockCache->Init();
1635 : }
1636 :
1637 : //! @endcond
1638 :
1639 : /************************************************************************/
1640 : /* FlushCache() */
1641 : /************************************************************************/
1642 :
1643 : /**
1644 : * \brief Flush raster data cache.
1645 : *
1646 : * This call will recover memory used to cache data blocks for this raster
1647 : * band, and ensure that new requests are referred to the underlying driver.
1648 : *
1649 : * This method is the same as the C function GDALFlushRasterCache().
1650 : *
1651 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1652 : * @return CE_None on success.
1653 : */
1654 :
1655 5673890 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1656 :
1657 : {
1658 5793550 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1659 119661 : poBandBlockCache)
1660 4256 : poBandBlockCache->DisableDirtyBlockWriting();
1661 :
1662 5673890 : CPLErr eGlobalErr = eFlushBlockErr;
1663 :
1664 5673890 : if (eFlushBlockErr != CE_None)
1665 : {
1666 0 : ReportError(
1667 : eFlushBlockErr, CPLE_AppDefined,
1668 : "An error occurred while writing a dirty block from FlushCache");
1669 0 : eFlushBlockErr = CE_None;
1670 : }
1671 :
1672 5673890 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1673 4904220 : return eGlobalErr;
1674 :
1675 769667 : return poBandBlockCache->FlushCache();
1676 : }
1677 :
1678 : /************************************************************************/
1679 : /* GDALFlushRasterCache() */
1680 : /************************************************************************/
1681 :
1682 : /**
1683 : * \brief Flush raster data cache.
1684 : *
1685 : * @see GDALRasterBand::FlushCache()
1686 : */
1687 :
1688 487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1689 :
1690 : {
1691 487 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1692 :
1693 487 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1694 : }
1695 :
1696 : /************************************************************************/
1697 : /* DropCache() */
1698 : /************************************************************************/
1699 :
1700 : /**
1701 : * \brief Drop raster data cache : data in cache will be lost.
1702 : *
1703 : * This call will recover memory used to cache data blocks for this raster
1704 : * band, and ensure that new requests are referred to the underlying driver.
1705 : *
1706 : * This method is the same as the C function GDALDropRasterCache().
1707 : *
1708 : * @return CE_None on success.
1709 : * @since 3.9
1710 : */
1711 :
1712 1 : CPLErr GDALRasterBand::DropCache()
1713 :
1714 : {
1715 1 : CPLErr result = CE_None;
1716 :
1717 1 : if (poBandBlockCache)
1718 1 : poBandBlockCache->DisableDirtyBlockWriting();
1719 :
1720 1 : CPLErr eGlobalErr = eFlushBlockErr;
1721 :
1722 1 : if (eFlushBlockErr != CE_None)
1723 : {
1724 0 : ReportError(
1725 : eFlushBlockErr, CPLE_AppDefined,
1726 : "An error occurred while writing a dirty block from DropCache");
1727 0 : eFlushBlockErr = CE_None;
1728 : }
1729 :
1730 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1731 0 : result = eGlobalErr;
1732 : else
1733 1 : result = poBandBlockCache->FlushCache();
1734 :
1735 1 : if (poBandBlockCache)
1736 1 : poBandBlockCache->EnableDirtyBlockWriting();
1737 :
1738 1 : return result;
1739 : }
1740 :
1741 : /************************************************************************/
1742 : /* GDALDropRasterCache() */
1743 : /************************************************************************/
1744 :
1745 : /**
1746 : * \brief Drop raster data cache.
1747 : *
1748 : * @see GDALRasterBand::DropCache()
1749 : * @since 3.9
1750 : */
1751 :
1752 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1753 :
1754 : {
1755 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1756 :
1757 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1758 : }
1759 :
1760 : /************************************************************************/
1761 : /* UnreferenceBlock() */
1762 : /* */
1763 : /* Unreference the block from our array of blocks */
1764 : /* This method should only be called by */
1765 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1766 : /* the block cache mutex) */
1767 : /************************************************************************/
1768 :
1769 29366 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1770 : {
1771 : #ifdef notdef
1772 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1773 : {
1774 : if (poBandBlockCache == nullptr)
1775 : printf("poBandBlockCache == NULL\n"); /*ok*/
1776 : else
1777 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1778 : printf("caller = %s\n", pszCaller); /*ok*/
1779 : printf("GDALRasterBand: %p\n", this); /*ok*/
1780 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1781 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1782 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1783 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1784 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1785 : poBlock->DumpBlock();
1786 : if (GetDataset() != nullptr)
1787 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1788 : GDALRasterBlock::Verify();
1789 : abort();
1790 : }
1791 : #endif
1792 29366 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1793 29366 : return poBandBlockCache->UnreferenceBlock(poBlock);
1794 : }
1795 :
1796 : /************************************************************************/
1797 : /* AddBlockToFreeList() */
1798 : /* */
1799 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1800 : /* finished with a block about to be free'd, they pass it to that */
1801 : /* method. */
1802 : /************************************************************************/
1803 :
1804 : //! @cond Doxygen_Suppress
1805 29366 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1806 : {
1807 29366 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1808 29366 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1809 : }
1810 :
1811 : //! @endcond
1812 :
1813 : /************************************************************************/
1814 : /* HasDirtyBlocks() */
1815 : /************************************************************************/
1816 :
1817 : //! @cond Doxygen_Suppress
1818 17 : bool GDALRasterBand::HasDirtyBlocks() const
1819 : {
1820 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1821 : }
1822 :
1823 : //! @endcond
1824 :
1825 : /************************************************************************/
1826 : /* FlushBlock() */
1827 : /************************************************************************/
1828 :
1829 : /** Flush a block out of the block cache.
1830 : * @param nXBlockOff block x offset
1831 : * @param nYBlockOff blocky offset
1832 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1833 : * @return CE_None in case of success, an error code otherwise.
1834 : */
1835 2313 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1836 : int bWriteDirtyBlock)
1837 :
1838 : {
1839 2313 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1840 0 : return (CE_Failure);
1841 :
1842 : /* -------------------------------------------------------------------- */
1843 : /* Validate the request */
1844 : /* -------------------------------------------------------------------- */
1845 2313 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1846 : {
1847 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1848 : "Illegal nBlockXOff value (%d) in "
1849 : "GDALRasterBand::FlushBlock()\n",
1850 : nXBlockOff);
1851 :
1852 0 : return (CE_Failure);
1853 : }
1854 :
1855 2313 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1856 : {
1857 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1858 : "Illegal nBlockYOff value (%d) in "
1859 : "GDALRasterBand::FlushBlock()\n",
1860 : nYBlockOff);
1861 :
1862 0 : return (CE_Failure);
1863 : }
1864 :
1865 2313 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1866 2313 : bWriteDirtyBlock);
1867 : }
1868 :
1869 : /************************************************************************/
1870 : /* TryGetLockedBlockRef() */
1871 : /************************************************************************/
1872 :
1873 : /**
1874 : * \brief Try fetching block ref.
1875 : *
1876 : * This method will returned the requested block (locked) if it is already
1877 : * in the block cache for the layer. If not, nullptr is returned.
1878 : *
1879 : * If a non-NULL value is returned, then a lock for the block will have been
1880 : * acquired on behalf of the caller. It is absolutely imperative that the
1881 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1882 : * severe problems may result.
1883 : *
1884 : * @param nXBlockOff the horizontal block offset, with zero indicating
1885 : * the left most block, 1 the next block and so forth.
1886 : *
1887 : * @param nYBlockOff the vertical block offset, with zero indicating
1888 : * the top most block, 1 the next block and so forth.
1889 : *
1890 : * @return NULL if block not available, or locked block pointer.
1891 : */
1892 :
1893 10655000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1894 : int nYBlockOff)
1895 :
1896 : {
1897 10655000 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1898 173225 : return nullptr;
1899 :
1900 : /* -------------------------------------------------------------------- */
1901 : /* Validate the request */
1902 : /* -------------------------------------------------------------------- */
1903 10481800 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1904 : {
1905 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1906 : "Illegal nBlockXOff value (%d) in "
1907 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1908 : nXBlockOff);
1909 :
1910 0 : return (nullptr);
1911 : }
1912 :
1913 10481800 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1914 : {
1915 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1916 : "Illegal nBlockYOff value (%d) in "
1917 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1918 : nYBlockOff);
1919 :
1920 0 : return (nullptr);
1921 : }
1922 :
1923 10481800 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1924 : }
1925 :
1926 : /************************************************************************/
1927 : /* GetLockedBlockRef() */
1928 : /************************************************************************/
1929 :
1930 : /**
1931 : * \brief Fetch a pointer to an internally cached raster block.
1932 : *
1933 : * This method will returned the requested block (locked) if it is already
1934 : * in the block cache for the layer. If not, the block will be read from
1935 : * the driver, and placed in the layer block cached, then returned. If an
1936 : * error occurs reading the block from the driver, a NULL value will be
1937 : * returned.
1938 : *
1939 : * If a non-NULL value is returned, then a lock for the block will have been
1940 : * acquired on behalf of the caller. It is absolutely imperative that the
1941 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1942 : * severe problems may result.
1943 : *
1944 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1945 : * enable caching.
1946 : *
1947 : * @param nXBlockOff the horizontal block offset, with zero indicating
1948 : * the left most block, 1 the next block and so forth.
1949 : *
1950 : * @param nYBlockOff the vertical block offset, with zero indicating
1951 : * the top most block, 1 the next block and so forth.
1952 : *
1953 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1954 : * but not actually read from the source. This is useful when it will just
1955 : * be completely set and written back.
1956 : *
1957 : * @return pointer to the block object, or NULL on failure.
1958 : */
1959 :
1960 10344800 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1961 : int nYBlockOff,
1962 : int bJustInitialize)
1963 :
1964 : {
1965 : /* -------------------------------------------------------------------- */
1966 : /* Try and fetch from cache. */
1967 : /* -------------------------------------------------------------------- */
1968 10344800 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1969 :
1970 : /* -------------------------------------------------------------------- */
1971 : /* If we didn't find it in our memory cache, instantiate a */
1972 : /* block (potentially load from disk) and "adopt" it into the */
1973 : /* cache. */
1974 : /* -------------------------------------------------------------------- */
1975 10344800 : if (poBlock == nullptr)
1976 : {
1977 3378080 : if (!InitBlockInfo())
1978 0 : return (nullptr);
1979 :
1980 : /* --------------------------------------------------------------------
1981 : */
1982 : /* Validate the request */
1983 : /* --------------------------------------------------------------------
1984 : */
1985 3378080 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1986 : {
1987 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1988 : "Illegal nBlockXOff value (%d) in "
1989 : "GDALRasterBand::GetLockedBlockRef()\n",
1990 : nXBlockOff);
1991 :
1992 0 : return (nullptr);
1993 : }
1994 :
1995 3378080 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1996 : {
1997 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1998 : "Illegal nBlockYOff value (%d) in "
1999 : "GDALRasterBand::GetLockedBlockRef()\n",
2000 : nYBlockOff);
2001 :
2002 0 : return (nullptr);
2003 : }
2004 :
2005 3378080 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2006 3378080 : if (poBlock == nullptr)
2007 0 : return nullptr;
2008 :
2009 3378080 : poBlock->AddLock();
2010 :
2011 : /* We need to temporarily drop the read-write lock in the following */
2012 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2013 : */
2014 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2015 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2016 : */
2017 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2018 : */
2019 : /* called and attempt at taking the lock on T2 (already taken).
2020 : * Similarly */
2021 : /* for T2 with D1, hence a deadlock situation (#6163) */
2022 : /* But this may open the door to other problems... */
2023 3378080 : if (poDS)
2024 3377340 : poDS->TemporarilyDropReadWriteLock();
2025 : /* allocate data space */
2026 3378080 : CPLErr eErr = poBlock->Internalize();
2027 3378080 : if (poDS)
2028 3377340 : poDS->ReacquireReadWriteLock();
2029 3378080 : if (eErr != CE_None)
2030 : {
2031 0 : poBlock->DropLock();
2032 0 : delete poBlock;
2033 0 : return nullptr;
2034 : }
2035 :
2036 3378080 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2037 : {
2038 0 : poBlock->DropLock();
2039 0 : delete poBlock;
2040 0 : return nullptr;
2041 : }
2042 :
2043 3378080 : if (!bJustInitialize)
2044 : {
2045 2889760 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2046 2889760 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2047 2889760 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2048 2889760 : if (bCallLeaveReadWrite)
2049 133342 : LeaveReadWrite();
2050 2889760 : if (eErr != CE_None)
2051 : {
2052 1163 : poBlock->DropLock();
2053 1163 : FlushBlock(nXBlockOff, nYBlockOff);
2054 1163 : ReportError(CE_Failure, CPLE_AppDefined,
2055 : "IReadBlock failed at X offset %d, Y offset %d%s",
2056 : nXBlockOff, nYBlockOff,
2057 1163 : (nErrorCounter != CPLGetErrorCounter())
2058 1161 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2059 : : "");
2060 1163 : return nullptr;
2061 : }
2062 :
2063 2888590 : nBlockReads++;
2064 2888590 : if (static_cast<GIntBig>(nBlockReads) ==
2065 2888590 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2066 228 : 1 &&
2067 228 : nBand == 1 && poDS != nullptr)
2068 : {
2069 168 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2070 168 : poDS->GetDescription());
2071 : }
2072 : }
2073 : }
2074 :
2075 10343600 : return poBlock;
2076 : }
2077 :
2078 : /************************************************************************/
2079 : /* Fill() */
2080 : /************************************************************************/
2081 :
2082 : /**
2083 : * \brief Fill this band with a constant value.
2084 : *
2085 : * GDAL makes no guarantees
2086 : * about what values pixels in newly created files are set to, so this
2087 : * method can be used to clear a band to a specified "default" value.
2088 : * The fill value is passed in as a double but this will be converted
2089 : * to the underlying type before writing to the file. An optional
2090 : * second argument allows the imaginary component of a complex
2091 : * constant value to be specified.
2092 : *
2093 : * This method is the same as the C function GDALFillRaster().
2094 : *
2095 : * @param dfRealValue Real component of fill value
2096 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2097 : *
2098 : * @return CE_Failure if the write fails, otherwise CE_None
2099 : */
2100 269807 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2101 : {
2102 :
2103 : // General approach is to construct a source block of the file's
2104 : // native type containing the appropriate value and then copy this
2105 : // to each block in the image via the RasterBlock cache. Using
2106 : // the cache means we avoid file I/O if it is not necessary, at the
2107 : // expense of some extra memcpy's (since we write to the
2108 : // RasterBlock cache, which is then at some point written to the
2109 : // underlying file, rather than simply directly to the underlying
2110 : // file.)
2111 :
2112 : // Check we can write to the file.
2113 269807 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2114 : {
2115 6 : return CE_Failure;
2116 : }
2117 :
2118 : // Make sure block parameters are set.
2119 269801 : if (!InitBlockInfo())
2120 0 : return CE_Failure;
2121 :
2122 : // Allocate the source block.
2123 269801 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2124 269801 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2125 269801 : auto blockByteSize = blockSize * elementSize;
2126 : unsigned char *srcBlock =
2127 269801 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2128 269801 : if (srcBlock == nullptr)
2129 : {
2130 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2131 : "GDALRasterBand::Fill(): Out of memory "
2132 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2133 : static_cast<GUIntBig>(blockByteSize));
2134 0 : return CE_Failure;
2135 : }
2136 :
2137 : // Initialize the source block.
2138 269801 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2139 269801 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2140 : elementSize, blockSize);
2141 :
2142 269801 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2143 :
2144 : // Write block to block cache
2145 875197 : for (int j = 0; j < nBlocksPerColumn; ++j)
2146 : {
2147 1505170 : for (int i = 0; i < nBlocksPerRow; ++i)
2148 : {
2149 899770 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2150 899770 : if (destBlock == nullptr)
2151 : {
2152 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2153 : "GDALRasterBand::Fill(): Error "
2154 : "while retrieving cache block.");
2155 0 : VSIFree(srcBlock);
2156 0 : return CE_Failure;
2157 : }
2158 899770 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2159 899770 : destBlock->MarkDirty();
2160 899770 : destBlock->DropLock();
2161 : }
2162 : }
2163 :
2164 269801 : if (bCallLeaveReadWrite)
2165 267753 : LeaveReadWrite();
2166 :
2167 : // Free up the source block
2168 269801 : VSIFree(srcBlock);
2169 :
2170 269801 : return CE_None;
2171 : }
2172 :
2173 : /************************************************************************/
2174 : /* GDALFillRaster() */
2175 : /************************************************************************/
2176 :
2177 : /**
2178 : * \brief Fill this band with a constant value.
2179 : *
2180 : * @see GDALRasterBand::Fill()
2181 : */
2182 269587 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2183 : double dfImaginaryValue)
2184 : {
2185 269587 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2186 :
2187 269587 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2188 269587 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2189 : }
2190 :
2191 : /************************************************************************/
2192 : /* GetAccess() */
2193 : /************************************************************************/
2194 :
2195 : /**
2196 : * \brief Find out if we have update permission for this band.
2197 : *
2198 : * This method is the same as the C function GDALGetRasterAccess().
2199 : *
2200 : * @return Either GA_Update or GA_ReadOnly.
2201 : */
2202 :
2203 3211 : GDALAccess GDALRasterBand::GetAccess()
2204 :
2205 : {
2206 3211 : return eAccess;
2207 : }
2208 :
2209 : /************************************************************************/
2210 : /* GDALGetRasterAccess() */
2211 : /************************************************************************/
2212 :
2213 : /**
2214 : * \brief Find out if we have update permission for this band.
2215 : *
2216 : * @see GDALRasterBand::GetAccess()
2217 : */
2218 :
2219 2553 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2220 :
2221 : {
2222 2553 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2223 :
2224 2553 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2225 2553 : return poBand->GetAccess();
2226 : }
2227 :
2228 : /************************************************************************/
2229 : /* GetCategoryNames() */
2230 : /************************************************************************/
2231 :
2232 : /**
2233 : * \brief Fetch the list of category names for this raster.
2234 : *
2235 : * The return list is a "StringList" in the sense of the CPL functions.
2236 : * That is a NULL terminated array of strings. Raster values without
2237 : * associated names will have an empty string in the returned list. The
2238 : * first entry in the list is for raster values of zero, and so on.
2239 : *
2240 : * The returned stringlist should not be altered or freed by the application.
2241 : * It may change on the next GDAL call, so please copy it if it is needed
2242 : * for any period of time.
2243 : *
2244 : * This method is the same as the C function GDALGetRasterCategoryNames().
2245 : *
2246 : * @return list of names, or NULL if none.
2247 : */
2248 :
2249 262 : char **GDALRasterBand::GetCategoryNames()
2250 :
2251 : {
2252 262 : return nullptr;
2253 : }
2254 :
2255 : /************************************************************************/
2256 : /* GDALGetRasterCategoryNames() */
2257 : /************************************************************************/
2258 :
2259 : /**
2260 : * \brief Fetch the list of category names for this raster.
2261 : *
2262 : * @see GDALRasterBand::GetCategoryNames()
2263 : */
2264 :
2265 207 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2266 :
2267 : {
2268 207 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2269 :
2270 207 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2271 207 : return poBand->GetCategoryNames();
2272 : }
2273 :
2274 : /************************************************************************/
2275 : /* SetCategoryNames() */
2276 : /************************************************************************/
2277 :
2278 : /**
2279 : * \fn GDALRasterBand::SetCategoryNames(char**)
2280 : * \brief Set the category names for this band.
2281 : *
2282 : * See the GetCategoryNames() method for more on the interpretation of
2283 : * category names.
2284 : *
2285 : * This method is the same as the C function GDALSetRasterCategoryNames().
2286 : *
2287 : * @param papszNames the NULL terminated StringList of category names. May
2288 : * be NULL to just clear the existing list.
2289 : *
2290 : * @return CE_None on success of CE_Failure on failure. If unsupported
2291 : * by the driver CE_Failure is returned, but no error message is reported.
2292 : */
2293 :
2294 : /**/
2295 : /**/
2296 :
2297 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2298 : {
2299 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2300 0 : ReportError(CE_Failure, CPLE_NotSupported,
2301 : "SetCategoryNames() not supported for this dataset.");
2302 :
2303 0 : return CE_Failure;
2304 : }
2305 :
2306 : /************************************************************************/
2307 : /* GDALSetCategoryNames() */
2308 : /************************************************************************/
2309 :
2310 : /**
2311 : * \brief Set the category names for this band.
2312 : *
2313 : * @see GDALRasterBand::SetCategoryNames()
2314 : */
2315 :
2316 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2317 : CSLConstList papszNames)
2318 :
2319 : {
2320 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2321 :
2322 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2323 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2324 : }
2325 :
2326 : /************************************************************************/
2327 : /* GetNoDataValue() */
2328 : /************************************************************************/
2329 :
2330 : /**
2331 : * \brief Fetch the no data value for this band.
2332 : *
2333 : * If there is no out of data value, an out of range value will generally
2334 : * be returned. The no data value for a band is generally a special marker
2335 : * value used to mark pixels that are not valid data. Such pixels should
2336 : * generally not be displayed, nor contribute to analysis operations.
2337 : *
2338 : * The no data value returned is 'raw', meaning that it has no offset and
2339 : * scale applied.
2340 : *
2341 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2342 : * lossy if the nodata value cannot exactly been represented by a double.
2343 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2344 : *
2345 : * This method is the same as the C function GDALGetRasterNoDataValue().
2346 : *
2347 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2348 : * is actually associated with this layer. May be NULL (default).
2349 : *
2350 : * @return the nodata value for this band.
2351 : */
2352 :
2353 13170 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2354 :
2355 : {
2356 13170 : if (pbSuccess != nullptr)
2357 13170 : *pbSuccess = FALSE;
2358 :
2359 13170 : return -1e10;
2360 : }
2361 :
2362 : /************************************************************************/
2363 : /* GDALGetRasterNoDataValue() */
2364 : /************************************************************************/
2365 :
2366 : /**
2367 : * \brief Fetch the no data value for this band.
2368 : *
2369 : * @see GDALRasterBand::GetNoDataValue()
2370 : */
2371 :
2372 414938 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2373 : int *pbSuccess)
2374 :
2375 : {
2376 414938 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2377 :
2378 414938 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2379 414938 : return poBand->GetNoDataValue(pbSuccess);
2380 : }
2381 :
2382 : /************************************************************************/
2383 : /* GetNoDataValueAsInt64() */
2384 : /************************************************************************/
2385 :
2386 : /**
2387 : * \brief Fetch the no data value for this band.
2388 : *
2389 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2390 : *
2391 : * If there is no out of data value, an out of range value will generally
2392 : * be returned. The no data value for a band is generally a special marker
2393 : * value used to mark pixels that are not valid data. Such pixels should
2394 : * generally not be displayed, nor contribute to analysis operations.
2395 : *
2396 : * The no data value returned is 'raw', meaning that it has no offset and
2397 : * scale applied.
2398 : *
2399 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2400 : *
2401 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2402 : * is actually associated with this layer. May be NULL (default).
2403 : *
2404 : * @return the nodata value for this band.
2405 : *
2406 : * @since GDAL 3.5
2407 : */
2408 :
2409 5 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2410 :
2411 : {
2412 5 : if (pbSuccess != nullptr)
2413 5 : *pbSuccess = FALSE;
2414 :
2415 5 : return std::numeric_limits<int64_t>::min();
2416 : }
2417 :
2418 : /************************************************************************/
2419 : /* GDALGetRasterNoDataValueAsInt64() */
2420 : /************************************************************************/
2421 :
2422 : /**
2423 : * \brief Fetch the no data value for this band.
2424 : *
2425 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2426 : *
2427 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2428 : *
2429 : * @since GDAL 3.5
2430 : */
2431 :
2432 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2433 : int *pbSuccess)
2434 :
2435 : {
2436 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2437 : std::numeric_limits<int64_t>::min());
2438 :
2439 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2440 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2441 : }
2442 :
2443 : /************************************************************************/
2444 : /* GetNoDataValueAsUInt64() */
2445 : /************************************************************************/
2446 :
2447 : /**
2448 : * \brief Fetch the no data value for this band.
2449 : *
2450 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2451 : *
2452 : * If there is no out of data value, an out of range value will generally
2453 : * be returned. The no data value for a band is generally a special marker
2454 : * value used to mark pixels that are not valid data. Such pixels should
2455 : * generally not be displayed, nor contribute to analysis operations.
2456 : *
2457 : * The no data value returned is 'raw', meaning that it has no offset and
2458 : * scale applied.
2459 : *
2460 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2461 : *
2462 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2463 : * is actually associated with this layer. May be NULL (default).
2464 : *
2465 : * @return the nodata value for this band.
2466 : *
2467 : * @since GDAL 3.5
2468 : */
2469 :
2470 4 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2471 :
2472 : {
2473 4 : if (pbSuccess != nullptr)
2474 4 : *pbSuccess = FALSE;
2475 :
2476 4 : return std::numeric_limits<uint64_t>::max();
2477 : }
2478 :
2479 : /************************************************************************/
2480 : /* GDALGetRasterNoDataValueAsUInt64() */
2481 : /************************************************************************/
2482 :
2483 : /**
2484 : * \brief Fetch the no data value for this band.
2485 : *
2486 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2487 : *
2488 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2489 : *
2490 : * @since GDAL 3.5
2491 : */
2492 :
2493 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2494 : int *pbSuccess)
2495 :
2496 : {
2497 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2498 : std::numeric_limits<uint64_t>::max());
2499 :
2500 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2501 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2502 : }
2503 :
2504 : /************************************************************************/
2505 : /* SetNoDataValueAsString() */
2506 : /************************************************************************/
2507 :
2508 : /**
2509 : * \brief Set the no data value for this band.
2510 : *
2511 : * Depending on drivers, changing the no data value may or may not have an
2512 : * effect on the pixel values of a raster that has just been created. It is
2513 : * thus advised to explicitly called Fill() if the intent is to initialize
2514 : * the raster to the nodata value.
2515 : * In any case, changing an existing no data value, when one already exists and
2516 : * the dataset exists or has been initialized, has no effect on the pixel whose
2517 : * value matched the previous nodata value.
2518 : *
2519 : * To clear the nodata value, use DeleteNoDataValue().
2520 : *
2521 : * @param pszNoData the value to set.
2522 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2523 : * If the value cannot be exactly represented on the output data
2524 : * type, *pbCannotBeExactlyRepresented will be set to true.
2525 : *
2526 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2527 : * by the driver, CE_Failure is returned but no error message will have
2528 : * been emitted.
2529 : *
2530 : * @since 3.11
2531 : */
2532 :
2533 : CPLErr
2534 126 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2535 : bool *pbCannotBeExactlyRepresented)
2536 : {
2537 126 : if (pbCannotBeExactlyRepresented)
2538 126 : *pbCannotBeExactlyRepresented = false;
2539 126 : if (eDataType == GDT_Int64)
2540 : {
2541 8 : if (strchr(pszNoData, '.') ||
2542 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2543 : {
2544 2 : char *endptr = nullptr;
2545 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2546 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2547 2 : GDALIsValueExactAs<int64_t>(dfVal))
2548 : {
2549 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2550 : }
2551 : }
2552 : else
2553 : {
2554 : try
2555 : {
2556 7 : const auto val = std::stoll(pszNoData);
2557 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2558 : }
2559 2 : catch (const std::exception &)
2560 : {
2561 : }
2562 : }
2563 : }
2564 121 : else if (eDataType == GDT_UInt64)
2565 : {
2566 2 : if (strchr(pszNoData, '.') ||
2567 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2568 : {
2569 0 : char *endptr = nullptr;
2570 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2571 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2572 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2573 : {
2574 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2575 : }
2576 : }
2577 : else
2578 : {
2579 : try
2580 : {
2581 1 : const auto val = std::stoull(pszNoData);
2582 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2583 : }
2584 0 : catch (const std::exception &)
2585 : {
2586 : }
2587 : }
2588 : }
2589 120 : else if (eDataType == GDT_Float32)
2590 : {
2591 10 : char *endptr = nullptr;
2592 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2593 10 : if (endptr == pszNoData + strlen(pszNoData))
2594 : {
2595 10 : return SetNoDataValue(double(fVal));
2596 : }
2597 : }
2598 : else
2599 : {
2600 110 : char *endptr = nullptr;
2601 110 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2602 220 : if (endptr == pszNoData + strlen(pszNoData) &&
2603 110 : GDALIsValueExactAs(dfVal, eDataType))
2604 : {
2605 109 : return SetNoDataValue(dfVal);
2606 : }
2607 : }
2608 5 : if (pbCannotBeExactlyRepresented)
2609 5 : *pbCannotBeExactlyRepresented = true;
2610 5 : return CE_Failure;
2611 : }
2612 :
2613 : /************************************************************************/
2614 : /* SetNoDataValue() */
2615 : /************************************************************************/
2616 :
2617 : /**
2618 : * \fn GDALRasterBand::SetNoDataValue(double)
2619 : * \brief Set the no data value for this band.
2620 : *
2621 : * Depending on drivers, changing the no data value may or may not have an
2622 : * effect on the pixel values of a raster that has just been created. It is
2623 : * thus advised to explicitly called Fill() if the intent is to initialize
2624 : * the raster to the nodata value.
2625 : * In any case, changing an existing no data value, when one already exists and
2626 : * the dataset exists or has been initialized, has no effect on the pixel whose
2627 : * value matched the previous nodata value.
2628 : *
2629 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2630 : * be represented by a double, use SetNoDataValueAsInt64() or
2631 : * SetNoDataValueAsUInt64() instead.
2632 : *
2633 : * To clear the nodata value, use DeleteNoDataValue().
2634 : *
2635 : * This method is the same as the C function GDALSetRasterNoDataValue().
2636 : *
2637 : * @param dfNoData the value to set.
2638 : *
2639 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2640 : * by the driver, CE_Failure is returned but no error message will have
2641 : * been emitted.
2642 : */
2643 :
2644 : /**/
2645 : /**/
2646 :
2647 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2648 :
2649 : {
2650 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2651 0 : ReportError(CE_Failure, CPLE_NotSupported,
2652 : "SetNoDataValue() not supported for this dataset.");
2653 :
2654 0 : return CE_Failure;
2655 : }
2656 :
2657 : /************************************************************************/
2658 : /* GDALSetRasterNoDataValue() */
2659 : /************************************************************************/
2660 :
2661 : /**
2662 : * \brief Set the no data value for this band.
2663 : *
2664 : * Depending on drivers, changing the no data value may or may not have an
2665 : * effect on the pixel values of a raster that has just been created. It is
2666 : * thus advised to explicitly called Fill() if the intent is to initialize
2667 : * the raster to the nodata value.
2668 : * In any case, changing an existing no data value, when one already exists and
2669 : * the dataset exists or has been initialized, has no effect on the pixel whose
2670 : * value matched the previous nodata value.
2671 : *
2672 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2673 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2674 : * GDALSetRasterNoDataValueAsUInt64() instead.
2675 : *
2676 : * @see GDALRasterBand::SetNoDataValue()
2677 : */
2678 :
2679 1146 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2680 : double dfValue)
2681 :
2682 : {
2683 1146 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2684 :
2685 1146 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2686 1146 : return poBand->SetNoDataValue(dfValue);
2687 : }
2688 :
2689 : /************************************************************************/
2690 : /* SetNoDataValueAsInt64() */
2691 : /************************************************************************/
2692 :
2693 : /**
2694 : * \brief Set the no data value for this band.
2695 : *
2696 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2697 : *
2698 : * Depending on drivers, changing the no data value may or may not have an
2699 : * effect on the pixel values of a raster that has just been created. It is
2700 : * thus advised to explicitly called Fill() if the intent is to initialize
2701 : * the raster to the nodata value.
2702 : * In ay case, changing an existing no data value, when one already exists and
2703 : * the dataset exists or has been initialized, has no effect on the pixel whose
2704 : * value matched the previous nodata value.
2705 : *
2706 : * To clear the nodata value, use DeleteNoDataValue().
2707 : *
2708 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2709 : *
2710 : * @param nNoDataValue the value to set.
2711 : *
2712 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2713 : * by the driver, CE_Failure is returned but no error message will have
2714 : * been emitted.
2715 : *
2716 : * @since GDAL 3.5
2717 : */
2718 :
2719 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2720 :
2721 : {
2722 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2723 0 : ReportError(CE_Failure, CPLE_NotSupported,
2724 : "SetNoDataValueAsInt64() not supported for this dataset.");
2725 :
2726 0 : return CE_Failure;
2727 : }
2728 :
2729 : /************************************************************************/
2730 : /* GDALSetRasterNoDataValueAsInt64() */
2731 : /************************************************************************/
2732 :
2733 : /**
2734 : * \brief Set the no data value for this band.
2735 : *
2736 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2737 : *
2738 : * Depending on drivers, changing the no data value may or may not have an
2739 : * effect on the pixel values of a raster that has just been created. It is
2740 : * thus advised to explicitly called Fill() if the intent is to initialize
2741 : * the raster to the nodata value.
2742 : * In ay case, changing an existing no data value, when one already exists and
2743 : * the dataset exists or has been initialized, has no effect on the pixel whose
2744 : * value matched the previous nodata value.
2745 : *
2746 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2747 : *
2748 : * @since GDAL 3.5
2749 : */
2750 :
2751 24 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2752 : int64_t nValue)
2753 :
2754 : {
2755 24 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2756 :
2757 24 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2758 24 : return poBand->SetNoDataValueAsInt64(nValue);
2759 : }
2760 :
2761 : /************************************************************************/
2762 : /* SetNoDataValueAsUInt64() */
2763 : /************************************************************************/
2764 :
2765 : /**
2766 : * \brief Set the no data value for this band.
2767 : *
2768 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2769 : *
2770 : * Depending on drivers, changing the no data value may or may not have an
2771 : * effect on the pixel values of a raster that has just been created. It is
2772 : * thus advised to explicitly called Fill() if the intent is to initialize
2773 : * the raster to the nodata value.
2774 : * In ay case, changing an existing no data value, when one already exists and
2775 : * the dataset exists or has been initialized, has no effect on the pixel whose
2776 : * value matched the previous nodata value.
2777 : *
2778 : * To clear the nodata value, use DeleteNoDataValue().
2779 : *
2780 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2781 : *
2782 : * @param nNoDataValue the value to set.
2783 : *
2784 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2785 : * by the driver, CE_Failure is returned but no error message will have
2786 : * been emitted.
2787 : *
2788 : * @since GDAL 3.5
2789 : */
2790 :
2791 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2792 :
2793 : {
2794 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2795 0 : ReportError(CE_Failure, CPLE_NotSupported,
2796 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2797 :
2798 0 : return CE_Failure;
2799 : }
2800 :
2801 : /************************************************************************/
2802 : /* GDALSetRasterNoDataValueAsUInt64() */
2803 : /************************************************************************/
2804 :
2805 : /**
2806 : * \brief Set the no data value for this band.
2807 : *
2808 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2809 : *
2810 : * Depending on drivers, changing the no data value may or may not have an
2811 : * effect on the pixel values of a raster that has just been created. It is
2812 : * thus advised to explicitly called Fill() if the intent is to initialize
2813 : * the raster to the nodata value.
2814 : * In ay case, changing an existing no data value, when one already exists and
2815 : * the dataset exists or has been initialized, has no effect on the pixel whose
2816 : * value matched the previous nodata value.
2817 : *
2818 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2819 : *
2820 : * @since GDAL 3.5
2821 : */
2822 :
2823 23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2824 : uint64_t nValue)
2825 :
2826 : {
2827 23 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2828 :
2829 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2830 23 : return poBand->SetNoDataValueAsUInt64(nValue);
2831 : }
2832 :
2833 : /************************************************************************/
2834 : /* DeleteNoDataValue() */
2835 : /************************************************************************/
2836 :
2837 : /**
2838 : * \brief Remove the no data value for this band.
2839 : *
2840 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2841 : *
2842 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2843 : * by the driver, CE_Failure is returned but no error message will have
2844 : * been emitted.
2845 : *
2846 : */
2847 :
2848 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2849 :
2850 : {
2851 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2852 0 : ReportError(CE_Failure, CPLE_NotSupported,
2853 : "DeleteNoDataValue() not supported for this dataset.");
2854 :
2855 0 : return CE_Failure;
2856 : }
2857 :
2858 : /************************************************************************/
2859 : /* GDALDeleteRasterNoDataValue() */
2860 : /************************************************************************/
2861 :
2862 : /**
2863 : * \brief Remove the no data value for this band.
2864 : *
2865 : * @see GDALRasterBand::DeleteNoDataValue()
2866 : *
2867 : */
2868 :
2869 56 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2870 :
2871 : {
2872 56 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2873 :
2874 56 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2875 56 : return poBand->DeleteNoDataValue();
2876 : }
2877 :
2878 : /************************************************************************/
2879 : /* GetMaximum() */
2880 : /************************************************************************/
2881 :
2882 : /**
2883 : * \brief Fetch the maximum value for this band.
2884 : *
2885 : * For file formats that don't know this intrinsically, the maximum supported
2886 : * value for the data type will generally be returned.
2887 : *
2888 : * This method is the same as the C function GDALGetRasterMaximum().
2889 : *
2890 : * @param pbSuccess pointer to a boolean to use to indicate if the
2891 : * returned value is a tight maximum or not. May be NULL (default).
2892 : *
2893 : * @return the maximum raster value (excluding no data pixels)
2894 : */
2895 :
2896 544 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2897 :
2898 : {
2899 544 : const char *pszValue = nullptr;
2900 :
2901 544 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2902 : {
2903 47 : if (pbSuccess != nullptr)
2904 42 : *pbSuccess = TRUE;
2905 :
2906 47 : return CPLAtofM(pszValue);
2907 : }
2908 :
2909 497 : if (pbSuccess != nullptr)
2910 493 : *pbSuccess = FALSE;
2911 :
2912 497 : switch (eDataType)
2913 : {
2914 341 : case GDT_UInt8:
2915 : {
2916 341 : EnablePixelTypeSignedByteWarning(false);
2917 : const char *pszPixelType =
2918 341 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2919 341 : EnablePixelTypeSignedByteWarning(true);
2920 341 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2921 0 : return 127;
2922 :
2923 341 : return 255;
2924 : }
2925 :
2926 1 : case GDT_Int8:
2927 1 : return 127;
2928 :
2929 21 : case GDT_UInt16:
2930 21 : return 65535;
2931 :
2932 24 : case GDT_Int16:
2933 : case GDT_CInt16:
2934 24 : return 32767;
2935 :
2936 39 : case GDT_Int32:
2937 : case GDT_CInt32:
2938 39 : return 2147483647.0;
2939 :
2940 14 : case GDT_UInt32:
2941 14 : return 4294967295.0;
2942 :
2943 1 : case GDT_Int64:
2944 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2945 :
2946 1 : case GDT_UInt64:
2947 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2948 :
2949 0 : case GDT_Float16:
2950 : case GDT_CFloat16:
2951 0 : return 65504.0;
2952 :
2953 33 : case GDT_Float32:
2954 : case GDT_CFloat32:
2955 33 : return 4294967295.0; // Not actually accurate.
2956 :
2957 22 : case GDT_Float64:
2958 : case GDT_CFloat64:
2959 22 : return 4294967295.0; // Not actually accurate.
2960 :
2961 0 : case GDT_Unknown:
2962 : case GDT_TypeCount:
2963 0 : break;
2964 : }
2965 0 : return 4294967295.0; // Not actually accurate.
2966 : }
2967 :
2968 : /************************************************************************/
2969 : /* GDALGetRasterMaximum() */
2970 : /************************************************************************/
2971 :
2972 : /**
2973 : * \brief Fetch the maximum value for this band.
2974 : *
2975 : * @see GDALRasterBand::GetMaximum()
2976 : */
2977 :
2978 346 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2979 :
2980 : {
2981 346 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2982 :
2983 346 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2984 346 : return poBand->GetMaximum(pbSuccess);
2985 : }
2986 :
2987 : /************************************************************************/
2988 : /* GetMinimum() */
2989 : /************************************************************************/
2990 :
2991 : /**
2992 : * \brief Fetch the minimum value for this band.
2993 : *
2994 : * For file formats that don't know this intrinsically, the minimum supported
2995 : * value for the data type will generally be returned.
2996 : *
2997 : * This method is the same as the C function GDALGetRasterMinimum().
2998 : *
2999 : * @param pbSuccess pointer to a boolean to use to indicate if the
3000 : * returned value is a tight minimum or not. May be NULL (default).
3001 : *
3002 : * @return the minimum raster value (excluding no data pixels)
3003 : */
3004 :
3005 552 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3006 :
3007 : {
3008 552 : const char *pszValue = nullptr;
3009 :
3010 552 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3011 : {
3012 52 : if (pbSuccess != nullptr)
3013 47 : *pbSuccess = TRUE;
3014 :
3015 52 : return CPLAtofM(pszValue);
3016 : }
3017 :
3018 500 : if (pbSuccess != nullptr)
3019 496 : *pbSuccess = FALSE;
3020 :
3021 500 : switch (eDataType)
3022 : {
3023 344 : case GDT_UInt8:
3024 : {
3025 344 : EnablePixelTypeSignedByteWarning(false);
3026 : const char *pszPixelType =
3027 344 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3028 344 : EnablePixelTypeSignedByteWarning(true);
3029 344 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3030 0 : return -128;
3031 :
3032 344 : return 0;
3033 : }
3034 :
3035 1 : case GDT_Int8:
3036 1 : return -128;
3037 :
3038 21 : case GDT_UInt16:
3039 21 : return 0;
3040 :
3041 24 : case GDT_Int16:
3042 : case GDT_CInt16:
3043 24 : return -32768;
3044 :
3045 39 : case GDT_Int32:
3046 : case GDT_CInt32:
3047 39 : return -2147483648.0;
3048 :
3049 14 : case GDT_UInt32:
3050 14 : return 0;
3051 :
3052 1 : case GDT_Int64:
3053 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3054 :
3055 1 : case GDT_UInt64:
3056 1 : return 0;
3057 :
3058 0 : case GDT_Float16:
3059 : case GDT_CFloat16:
3060 0 : return -65504.0;
3061 :
3062 33 : case GDT_Float32:
3063 : case GDT_CFloat32:
3064 33 : return -4294967295.0; // Not actually accurate.
3065 :
3066 22 : case GDT_Float64:
3067 : case GDT_CFloat64:
3068 22 : return -4294967295.0; // Not actually accurate.
3069 :
3070 0 : case GDT_Unknown:
3071 : case GDT_TypeCount:
3072 0 : break;
3073 : }
3074 0 : return -4294967295.0; // Not actually accurate.
3075 : }
3076 :
3077 : /************************************************************************/
3078 : /* GDALGetRasterMinimum() */
3079 : /************************************************************************/
3080 :
3081 : /**
3082 : * \brief Fetch the minimum value for this band.
3083 : *
3084 : * @see GDALRasterBand::GetMinimum()
3085 : */
3086 :
3087 356 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3088 :
3089 : {
3090 356 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3091 :
3092 356 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3093 356 : return poBand->GetMinimum(pbSuccess);
3094 : }
3095 :
3096 : /************************************************************************/
3097 : /* GetColorInterpretation() */
3098 : /************************************************************************/
3099 :
3100 : /**
3101 : * \brief How should this band be interpreted as color?
3102 : *
3103 : * GCI_Undefined is returned when the format doesn't know anything
3104 : * about the color interpretation.
3105 : *
3106 : * This method is the same as the C function
3107 : * GDALGetRasterColorInterpretation().
3108 : *
3109 : * @return color interpretation value for band.
3110 : */
3111 :
3112 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3113 :
3114 : {
3115 163 : return GCI_Undefined;
3116 : }
3117 :
3118 : /************************************************************************/
3119 : /* GDALGetRasterColorInterpretation() */
3120 : /************************************************************************/
3121 :
3122 : /**
3123 : * \brief How should this band be interpreted as color?
3124 : *
3125 : * @see GDALRasterBand::GetColorInterpretation()
3126 : */
3127 :
3128 : GDALColorInterp CPL_STDCALL
3129 6172 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3130 :
3131 : {
3132 6172 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3133 :
3134 6172 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3135 6172 : return poBand->GetColorInterpretation();
3136 : }
3137 :
3138 : /************************************************************************/
3139 : /* SetColorInterpretation() */
3140 : /************************************************************************/
3141 :
3142 : /**
3143 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3144 : * \brief Set color interpretation of a band.
3145 : *
3146 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3147 : *
3148 : * @param eColorInterp the new color interpretation to apply to this band.
3149 : *
3150 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3151 : */
3152 :
3153 : /**/
3154 : /**/
3155 :
3156 1 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3157 :
3158 : {
3159 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3160 1 : ReportError(CE_Failure, CPLE_NotSupported,
3161 : "SetColorInterpretation() not supported for this dataset.");
3162 1 : return CE_Failure;
3163 : }
3164 :
3165 : /************************************************************************/
3166 : /* GDALSetRasterColorInterpretation() */
3167 : /************************************************************************/
3168 :
3169 : /**
3170 : * \brief Set color interpretation of a band.
3171 : *
3172 : * @see GDALRasterBand::SetColorInterpretation()
3173 : */
3174 :
3175 1864 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3176 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3177 :
3178 : {
3179 1864 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3180 :
3181 1864 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3182 1864 : return poBand->SetColorInterpretation(eColorInterp);
3183 : }
3184 :
3185 : /************************************************************************/
3186 : /* GetColorTable() */
3187 : /************************************************************************/
3188 :
3189 : /**
3190 : * \brief Fetch the color table associated with band.
3191 : *
3192 : * If there is no associated color table, the return result is NULL. The
3193 : * returned color table remains owned by the GDALRasterBand, and can't
3194 : * be depended on for long, nor should it ever be modified by the caller.
3195 : *
3196 : * This method is the same as the C function GDALGetRasterColorTable().
3197 : *
3198 : * @return internal color table, or NULL.
3199 : */
3200 :
3201 215 : GDALColorTable *GDALRasterBand::GetColorTable()
3202 :
3203 : {
3204 215 : return nullptr;
3205 : }
3206 :
3207 : /************************************************************************/
3208 : /* GDALGetRasterColorTable() */
3209 : /************************************************************************/
3210 :
3211 : /**
3212 : * \brief Fetch the color table associated with band.
3213 : *
3214 : * @see GDALRasterBand::GetColorTable()
3215 : */
3216 :
3217 2119 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3218 :
3219 : {
3220 2119 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3221 :
3222 2119 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3223 2119 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3224 : }
3225 :
3226 : /************************************************************************/
3227 : /* SetColorTable() */
3228 : /************************************************************************/
3229 :
3230 : /**
3231 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3232 : * \brief Set the raster color table.
3233 : *
3234 : * The driver will make a copy of all desired data in the colortable. It
3235 : * remains owned by the caller after the call.
3236 : *
3237 : * This method is the same as the C function GDALSetRasterColorTable().
3238 : *
3239 : * @param poCT the color table to apply. This may be NULL to clear the color
3240 : * table (where supported).
3241 : *
3242 : * @return CE_None on success, or CE_Failure on failure. If the action is
3243 : * unsupported by the driver, a value of CE_Failure is returned, but no
3244 : * error is issued.
3245 : */
3246 :
3247 : /**/
3248 : /**/
3249 :
3250 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3251 :
3252 : {
3253 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3254 0 : ReportError(CE_Failure, CPLE_NotSupported,
3255 : "SetColorTable() not supported for this dataset.");
3256 0 : return CE_Failure;
3257 : }
3258 :
3259 : /************************************************************************/
3260 : /* GDALSetRasterColorTable() */
3261 : /************************************************************************/
3262 :
3263 : /**
3264 : * \brief Set the raster color table.
3265 : *
3266 : * @see GDALRasterBand::SetColorTable()
3267 : */
3268 :
3269 84 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3270 : GDALColorTableH hCT)
3271 :
3272 : {
3273 84 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3274 :
3275 84 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3276 84 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3277 : }
3278 :
3279 : /************************************************************************/
3280 : /* HasArbitraryOverviews() */
3281 : /************************************************************************/
3282 :
3283 : /**
3284 : * \brief Check for arbitrary overviews.
3285 : *
3286 : * This returns TRUE if the underlying datastore can compute arbitrary
3287 : * overviews efficiently, such as is the case with OGDI over a network.
3288 : * Datastores with arbitrary overviews don't generally have any fixed
3289 : * overviews, but the RasterIO() method can be used in downsampling mode
3290 : * to get overview data efficiently.
3291 : *
3292 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3293 : *
3294 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3295 : * FALSE.
3296 : */
3297 :
3298 276 : int GDALRasterBand::HasArbitraryOverviews()
3299 :
3300 : {
3301 276 : return FALSE;
3302 : }
3303 :
3304 : /************************************************************************/
3305 : /* GDALHasArbitraryOverviews() */
3306 : /************************************************************************/
3307 :
3308 : /**
3309 : * \brief Check for arbitrary overviews.
3310 : *
3311 : * @see GDALRasterBand::HasArbitraryOverviews()
3312 : */
3313 :
3314 197 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3315 :
3316 : {
3317 197 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3318 :
3319 197 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3320 197 : return poBand->HasArbitraryOverviews();
3321 : }
3322 :
3323 : /************************************************************************/
3324 : /* GetOverviewCount() */
3325 : /************************************************************************/
3326 :
3327 : /**
3328 : * \brief Return the number of overview layers available.
3329 : *
3330 : * This method is the same as the C function GDALGetOverviewCount().
3331 : *
3332 : * @return overview count, zero if none.
3333 : */
3334 :
3335 1066710 : int GDALRasterBand::GetOverviewCount()
3336 :
3337 : {
3338 1723640 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3339 656924 : poDS->AreOverviewsEnabled())
3340 656924 : return poDS->oOvManager.GetOverviewCount(nBand);
3341 :
3342 409790 : return 0;
3343 : }
3344 :
3345 : /************************************************************************/
3346 : /* GDALGetOverviewCount() */
3347 : /************************************************************************/
3348 :
3349 : /**
3350 : * \brief Return the number of overview layers available.
3351 : *
3352 : * @see GDALRasterBand::GetOverviewCount()
3353 : */
3354 :
3355 3316 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3356 :
3357 : {
3358 3316 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3359 :
3360 3316 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3361 3316 : return poBand->GetOverviewCount();
3362 : }
3363 :
3364 : /************************************************************************/
3365 : /* GetOverview() */
3366 : /************************************************************************/
3367 :
3368 : /**
3369 : * \brief Fetch overview raster band object.
3370 : *
3371 : * This method is the same as the C function GDALGetOverview().
3372 : *
3373 : * @param i overview index between 0 and GetOverviewCount()-1.
3374 : *
3375 : * @return overview GDALRasterBand.
3376 : */
3377 :
3378 943 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3379 :
3380 : {
3381 1734 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3382 791 : poDS->AreOverviewsEnabled())
3383 791 : return poDS->oOvManager.GetOverview(nBand, i);
3384 :
3385 152 : return nullptr;
3386 : }
3387 :
3388 : /************************************************************************/
3389 : /* GDALGetOverview() */
3390 : /************************************************************************/
3391 :
3392 : /**
3393 : * \brief Fetch overview raster band object.
3394 : *
3395 : * @see GDALRasterBand::GetOverview()
3396 : */
3397 :
3398 5666 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3399 :
3400 : {
3401 5666 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3402 :
3403 5666 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3404 5666 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3405 : }
3406 :
3407 : /************************************************************************/
3408 : /* GetRasterSampleOverview() */
3409 : /************************************************************************/
3410 :
3411 : /**
3412 : * \brief Fetch best sampling overview.
3413 : *
3414 : * Returns the most reduced overview of the given band that still satisfies
3415 : * the desired number of samples. This function can be used with zero
3416 : * as the number of desired samples to fetch the most reduced overview.
3417 : * The same band as was passed in will be returned if it has not overviews,
3418 : * or if none of the overviews have enough samples.
3419 : *
3420 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3421 : * and GDALGetRasterSampleOverviewEx().
3422 : *
3423 : * @param nDesiredSamples the returned band will have at least this many
3424 : * pixels.
3425 : *
3426 : * @return optimal overview or the band itself.
3427 : */
3428 :
3429 : GDALRasterBand *
3430 2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3431 :
3432 : {
3433 2009 : GDALRasterBand *poBestBand = this;
3434 :
3435 2009 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3436 :
3437 4029 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3438 : {
3439 2020 : GDALRasterBand *poOBand = GetOverview(iOverview);
3440 :
3441 2020 : if (poOBand == nullptr)
3442 0 : continue;
3443 :
3444 : const double dfOSamples =
3445 2020 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3446 :
3447 2020 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3448 : {
3449 2017 : dfBestSamples = dfOSamples;
3450 2017 : poBestBand = poOBand;
3451 : }
3452 : }
3453 :
3454 2009 : return poBestBand;
3455 : }
3456 :
3457 : /************************************************************************/
3458 : /* GDALGetRasterSampleOverview() */
3459 : /************************************************************************/
3460 :
3461 : /**
3462 : * \brief Fetch best sampling overview.
3463 : *
3464 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3465 : * billion samples.
3466 : *
3467 : * @see GDALRasterBand::GetRasterSampleOverview()
3468 : * @see GDALGetRasterSampleOverviewEx()
3469 : */
3470 :
3471 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3472 : int nDesiredSamples)
3473 :
3474 : {
3475 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3476 :
3477 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3478 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3479 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3480 : }
3481 :
3482 : /************************************************************************/
3483 : /* GDALGetRasterSampleOverviewEx() */
3484 : /************************************************************************/
3485 :
3486 : /**
3487 : * \brief Fetch best sampling overview.
3488 : *
3489 : * @see GDALRasterBand::GetRasterSampleOverview()
3490 : */
3491 :
3492 : GDALRasterBandH CPL_STDCALL
3493 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3494 :
3495 : {
3496 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3497 :
3498 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3499 2000 : return GDALRasterBand::ToHandle(
3500 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3501 : }
3502 :
3503 : /************************************************************************/
3504 : /* BuildOverviews() */
3505 : /************************************************************************/
3506 :
3507 : /**
3508 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3509 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3510 : *
3511 : * If the operation is unsupported for the indicated dataset, then
3512 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3513 : * CPLE_NotSupported.
3514 : *
3515 : * WARNING: Most formats don't support per-band overview computation, but
3516 : * require that overviews are computed for all bands of a dataset, using
3517 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3518 : * is the HFA driver which supports this method.
3519 : *
3520 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3521 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3522 : * applied.
3523 : * @param nOverviews number of overviews to build.
3524 : * @param panOverviewList the list of overview decimation factors to build.
3525 : * @param pfnProgress a function to call to report progress, or NULL.
3526 : * @param pProgressData application data to pass to the progress function.
3527 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3528 : * key=value pairs, or NULL
3529 : *
3530 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3531 : */
3532 :
3533 : /**/
3534 : /**/
3535 :
3536 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3537 : int /*nOverviews*/,
3538 : const int * /*panOverviewList*/,
3539 : GDALProgressFunc /*pfnProgress*/,
3540 : void * /*pProgressData*/,
3541 : CSLConstList /* papszOptions */)
3542 :
3543 : {
3544 0 : ReportError(CE_Failure, CPLE_NotSupported,
3545 : "BuildOverviews() not supported for this dataset.");
3546 :
3547 0 : return (CE_Failure);
3548 : }
3549 :
3550 : /************************************************************************/
3551 : /* GetOffset() */
3552 : /************************************************************************/
3553 :
3554 : /**
3555 : * \brief Fetch the raster value offset.
3556 : *
3557 : * This value (in combination with the GetScale() value) can be used to
3558 : * transform raw pixel values into the units returned by GetUnitType().
3559 : * For example this might be used to store elevations in GUInt16 bands
3560 : * with a precision of 0.1, and starting from -100.
3561 : *
3562 : * Units value = (raw value * scale) + offset
3563 : *
3564 : * Note that applying scale and offset is of the responsibility of the user,
3565 : * and is not done by methods such as RasterIO() or ReadBlock().
3566 : *
3567 : * For file formats that don't know this intrinsically a value of zero
3568 : * is returned.
3569 : *
3570 : * This method is the same as the C function GDALGetRasterOffset().
3571 : *
3572 : * @param pbSuccess pointer to a boolean to use to indicate if the
3573 : * returned value is meaningful or not. May be NULL (default).
3574 : *
3575 : * @return the raster offset.
3576 : */
3577 :
3578 445 : double GDALRasterBand::GetOffset(int *pbSuccess)
3579 :
3580 : {
3581 445 : if (pbSuccess != nullptr)
3582 336 : *pbSuccess = FALSE;
3583 :
3584 445 : return 0.0;
3585 : }
3586 :
3587 : /************************************************************************/
3588 : /* GDALGetRasterOffset() */
3589 : /************************************************************************/
3590 :
3591 : /**
3592 : * \brief Fetch the raster value offset.
3593 : *
3594 : * @see GDALRasterBand::GetOffset()
3595 : */
3596 :
3597 402 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3598 :
3599 : {
3600 402 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3601 :
3602 402 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3603 402 : return poBand->GetOffset(pbSuccess);
3604 : }
3605 :
3606 : /************************************************************************/
3607 : /* SetOffset() */
3608 : /************************************************************************/
3609 :
3610 : /**
3611 : * \fn GDALRasterBand::SetOffset(double)
3612 : * \brief Set scaling offset.
3613 : *
3614 : * Very few formats implement this method. When not implemented it will
3615 : * issue a CPLE_NotSupported error and return CE_Failure.
3616 : *
3617 : * This method is the same as the C function GDALSetRasterOffset().
3618 : *
3619 : * @param dfNewOffset the new offset.
3620 : *
3621 : * @return CE_None or success or CE_Failure on failure.
3622 : */
3623 :
3624 : /**/
3625 : /**/
3626 :
3627 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3628 : {
3629 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3630 0 : ReportError(CE_Failure, CPLE_NotSupported,
3631 : "SetOffset() not supported on this raster band.");
3632 :
3633 0 : return CE_Failure;
3634 : }
3635 :
3636 : /************************************************************************/
3637 : /* GDALSetRasterOffset() */
3638 : /************************************************************************/
3639 :
3640 : /**
3641 : * \brief Set scaling offset.
3642 : *
3643 : * @see GDALRasterBand::SetOffset()
3644 : */
3645 :
3646 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3647 : double dfNewOffset)
3648 :
3649 : {
3650 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3651 :
3652 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3653 86 : return poBand->SetOffset(dfNewOffset);
3654 : }
3655 :
3656 : /************************************************************************/
3657 : /* GetScale() */
3658 : /************************************************************************/
3659 :
3660 : /**
3661 : * \brief Fetch the raster value scale.
3662 : *
3663 : * This value (in combination with the GetOffset() value) can be used to
3664 : * transform raw pixel values into the units returned by GetUnitType().
3665 : * For example this might be used to store elevations in GUInt16 bands
3666 : * with a precision of 0.1, and starting from -100.
3667 : *
3668 : * Units value = (raw value * scale) + offset
3669 : *
3670 : * Note that applying scale and offset is of the responsibility of the user,
3671 : * and is not done by methods such as RasterIO() or ReadBlock().
3672 : *
3673 : * For file formats that don't know this intrinsically a value of one
3674 : * is returned.
3675 : *
3676 : * This method is the same as the C function GDALGetRasterScale().
3677 : *
3678 : * @param pbSuccess pointer to a boolean to use to indicate if the
3679 : * returned value is meaningful or not. May be NULL (default).
3680 : *
3681 : * @return the raster scale.
3682 : */
3683 :
3684 445 : double GDALRasterBand::GetScale(int *pbSuccess)
3685 :
3686 : {
3687 445 : if (pbSuccess != nullptr)
3688 336 : *pbSuccess = FALSE;
3689 :
3690 445 : return 1.0;
3691 : }
3692 :
3693 : /************************************************************************/
3694 : /* GDALGetRasterScale() */
3695 : /************************************************************************/
3696 :
3697 : /**
3698 : * \brief Fetch the raster value scale.
3699 : *
3700 : * @see GDALRasterBand::GetScale()
3701 : */
3702 :
3703 400 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3704 :
3705 : {
3706 400 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3707 :
3708 400 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3709 400 : return poBand->GetScale(pbSuccess);
3710 : }
3711 :
3712 : /************************************************************************/
3713 : /* SetScale() */
3714 : /************************************************************************/
3715 :
3716 : /**
3717 : * \fn GDALRasterBand::SetScale(double)
3718 : * \brief Set scaling ratio.
3719 : *
3720 : * Very few formats implement this method. When not implemented it will
3721 : * issue a CPLE_NotSupported error and return CE_Failure.
3722 : *
3723 : * This method is the same as the C function GDALSetRasterScale().
3724 : *
3725 : * @param dfNewScale the new scale.
3726 : *
3727 : * @return CE_None or success or CE_Failure on failure.
3728 : */
3729 :
3730 : /**/
3731 : /**/
3732 :
3733 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3734 :
3735 : {
3736 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3737 0 : ReportError(CE_Failure, CPLE_NotSupported,
3738 : "SetScale() not supported on this raster band.");
3739 :
3740 0 : return CE_Failure;
3741 : }
3742 :
3743 : /************************************************************************/
3744 : /* GDALSetRasterScale() */
3745 : /************************************************************************/
3746 :
3747 : /**
3748 : * \brief Set scaling ratio.
3749 : *
3750 : * @see GDALRasterBand::SetScale()
3751 : */
3752 :
3753 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3754 :
3755 : {
3756 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3757 :
3758 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3759 87 : return poBand->SetScale(dfNewOffset);
3760 : }
3761 :
3762 : /************************************************************************/
3763 : /* GetUnitType() */
3764 : /************************************************************************/
3765 :
3766 : /**
3767 : * \brief Return raster unit type.
3768 : *
3769 : * Return a name for the units of this raster's values. For instance, it
3770 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3771 : * units are available, a value of "" will be returned. The returned string
3772 : * should not be modified, nor freed by the calling application.
3773 : *
3774 : * This method is the same as the C function GDALGetRasterUnitType().
3775 : *
3776 : * @return unit name string.
3777 : */
3778 :
3779 165 : const char *GDALRasterBand::GetUnitType()
3780 :
3781 : {
3782 165 : return "";
3783 : }
3784 :
3785 : /************************************************************************/
3786 : /* GDALGetRasterUnitType() */
3787 : /************************************************************************/
3788 :
3789 : /**
3790 : * \brief Return raster unit type.
3791 : *
3792 : * @see GDALRasterBand::GetUnitType()
3793 : */
3794 :
3795 1662 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3796 :
3797 : {
3798 1662 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3799 :
3800 1662 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3801 1662 : return poBand->GetUnitType();
3802 : }
3803 :
3804 : /************************************************************************/
3805 : /* SetUnitType() */
3806 : /************************************************************************/
3807 :
3808 : /**
3809 : * \fn GDALRasterBand::SetUnitType(const char*)
3810 : * \brief Set unit type.
3811 : *
3812 : * Set the unit type for a raster band. Values should be one of
3813 : * "" (the default indicating it is unknown), "m" indicating meters,
3814 : * or "ft" indicating feet, though other nonstandard values are allowed.
3815 : *
3816 : * This method is the same as the C function GDALSetRasterUnitType().
3817 : *
3818 : * @param pszNewValue the new unit type value.
3819 : *
3820 : * @return CE_None on success or CE_Failure if not successful, or
3821 : * unsupported.
3822 : */
3823 :
3824 : /**/
3825 : /**/
3826 :
3827 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3828 :
3829 : {
3830 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3831 0 : ReportError(CE_Failure, CPLE_NotSupported,
3832 : "SetUnitType() not supported on this raster band.");
3833 0 : return CE_Failure;
3834 : }
3835 :
3836 : /************************************************************************/
3837 : /* GDALSetRasterUnitType() */
3838 : /************************************************************************/
3839 :
3840 : /**
3841 : * \brief Set unit type.
3842 : *
3843 : * @see GDALRasterBand::SetUnitType()
3844 : *
3845 : */
3846 :
3847 100 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3848 : const char *pszNewValue)
3849 :
3850 : {
3851 100 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3852 :
3853 100 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3854 100 : return poBand->SetUnitType(pszNewValue);
3855 : }
3856 :
3857 : /************************************************************************/
3858 : /* GetXSize() */
3859 : /************************************************************************/
3860 :
3861 : /**
3862 : * \brief Fetch XSize of raster.
3863 : *
3864 : * This method is the same as the C function GDALGetRasterBandXSize().
3865 : *
3866 : * @return the width in pixels of this band.
3867 : */
3868 :
3869 8475720 : int GDALRasterBand::GetXSize() const
3870 :
3871 : {
3872 8475720 : return nRasterXSize;
3873 : }
3874 :
3875 : /************************************************************************/
3876 : /* GDALGetRasterBandXSize() */
3877 : /************************************************************************/
3878 :
3879 : /**
3880 : * \brief Fetch XSize of raster.
3881 : *
3882 : * @see GDALRasterBand::GetXSize()
3883 : */
3884 :
3885 58070 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3886 :
3887 : {
3888 58070 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3889 :
3890 58070 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3891 58070 : return poBand->GetXSize();
3892 : }
3893 :
3894 : /************************************************************************/
3895 : /* GetYSize() */
3896 : /************************************************************************/
3897 :
3898 : /**
3899 : * \brief Fetch YSize of raster.
3900 : *
3901 : * This method is the same as the C function GDALGetRasterBandYSize().
3902 : *
3903 : * @return the height in pixels of this band.
3904 : */
3905 :
3906 4706730 : int GDALRasterBand::GetYSize() const
3907 :
3908 : {
3909 4706730 : return nRasterYSize;
3910 : }
3911 :
3912 : /************************************************************************/
3913 : /* GDALGetRasterBandYSize() */
3914 : /************************************************************************/
3915 :
3916 : /**
3917 : * \brief Fetch YSize of raster.
3918 : *
3919 : * @see GDALRasterBand::GetYSize()
3920 : */
3921 :
3922 56933 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3923 :
3924 : {
3925 56933 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3926 :
3927 56933 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3928 56933 : return poBand->GetYSize();
3929 : }
3930 :
3931 : /************************************************************************/
3932 : /* GetBand() */
3933 : /************************************************************************/
3934 :
3935 : /**
3936 : * \brief Fetch the band number.
3937 : *
3938 : * This method returns the band that this GDALRasterBand objects represents
3939 : * within its dataset. This method may return a value of 0 to indicate
3940 : * GDALRasterBand objects without an apparently relationship to a dataset,
3941 : * such as GDALRasterBands serving as overviews.
3942 : *
3943 : * This method is the same as the C function GDALGetBandNumber().
3944 : *
3945 : * @return band number (1+) or 0 if the band number isn't known.
3946 : */
3947 :
3948 151931 : int GDALRasterBand::GetBand() const
3949 :
3950 : {
3951 151931 : return nBand;
3952 : }
3953 :
3954 : /************************************************************************/
3955 : /* GDALGetBandNumber() */
3956 : /************************************************************************/
3957 :
3958 : /**
3959 : * \brief Fetch the band number.
3960 : *
3961 : * @see GDALRasterBand::GetBand()
3962 : */
3963 :
3964 159 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3965 :
3966 : {
3967 159 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3968 :
3969 159 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3970 159 : return poBand->GetBand();
3971 : }
3972 :
3973 : /************************************************************************/
3974 : /* GetDataset() */
3975 : /************************************************************************/
3976 :
3977 : /**
3978 : * \brief Fetch the owning dataset handle.
3979 : *
3980 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3981 : * such as overviews or other "freestanding" bands.
3982 : *
3983 : * This method is the same as the C function GDALGetBandDataset().
3984 : *
3985 : * @return the pointer to the GDALDataset to which this band belongs, or
3986 : * NULL if this cannot be determined.
3987 : */
3988 :
3989 5290970 : GDALDataset *GDALRasterBand::GetDataset() const
3990 :
3991 : {
3992 5290970 : return poDS;
3993 : }
3994 :
3995 : /************************************************************************/
3996 : /* GDALGetBandDataset() */
3997 : /************************************************************************/
3998 :
3999 : /**
4000 : * \brief Fetch the owning dataset handle.
4001 : *
4002 : * @see GDALRasterBand::GetDataset()
4003 : */
4004 :
4005 359 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4006 :
4007 : {
4008 359 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4009 :
4010 359 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4011 359 : return GDALDataset::ToHandle(poBand->GetDataset());
4012 : }
4013 :
4014 : /************************************************************************/
4015 : /* ComputeFloat16NoDataValue() */
4016 : /************************************************************************/
4017 :
4018 3074 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4019 : double dfNoDataValue,
4020 : int &bGotNoDataValue,
4021 : GFloat16 &hfNoDataValue,
4022 : bool &bGotFloat16NoDataValue)
4023 : {
4024 3074 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4025 : {
4026 7 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4027 7 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4028 : {
4029 7 : hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4030 7 : bGotFloat16NoDataValue = true;
4031 7 : bGotNoDataValue = false;
4032 : }
4033 : }
4034 3074 : }
4035 :
4036 : /************************************************************************/
4037 : /* ComputeFloatNoDataValue() */
4038 : /************************************************************************/
4039 :
4040 3074 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4041 : double dfNoDataValue,
4042 : int &bGotNoDataValue,
4043 : float &fNoDataValue,
4044 : bool &bGotFloatNoDataValue)
4045 : {
4046 3074 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4047 : {
4048 97 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4049 97 : if (GDALIsValueInRange<float>(dfNoDataValue))
4050 : {
4051 97 : fNoDataValue = static_cast<float>(dfNoDataValue);
4052 97 : bGotFloatNoDataValue = true;
4053 97 : bGotNoDataValue = false;
4054 : }
4055 : }
4056 3050 : else if (eDataType == GDT_Int16 && bGotNoDataValue &&
4057 73 : GDALIsValueExactAs<int16_t>(dfNoDataValue))
4058 : {
4059 73 : fNoDataValue = static_cast<float>(dfNoDataValue);
4060 73 : bGotFloatNoDataValue = true;
4061 : }
4062 2917 : else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
4063 13 : GDALIsValueExactAs<uint16_t>(dfNoDataValue))
4064 : {
4065 13 : fNoDataValue = static_cast<float>(dfNoDataValue);
4066 13 : bGotFloatNoDataValue = true;
4067 : }
4068 2898 : else if (eDataType == GDT_Float16 && bGotNoDataValue &&
4069 7 : GDALIsValueExactAs<GFloat16>(dfNoDataValue))
4070 : {
4071 7 : fNoDataValue = static_cast<float>(dfNoDataValue);
4072 7 : bGotFloatNoDataValue = true;
4073 : }
4074 3074 : }
4075 :
4076 : /************************************************************************/
4077 : /* struct GDALNoDataValues */
4078 : /************************************************************************/
4079 :
4080 : /**
4081 : * \brief No-data-values for all types
4082 : *
4083 : * The functions below pass various no-data-values around. To avoid
4084 : * long argument lists, this struct collects the no-data-values for
4085 : * all types into a single, convenient place.
4086 : **/
4087 :
4088 : struct GDALNoDataValues
4089 : {
4090 : int bGotNoDataValue;
4091 : double dfNoDataValue;
4092 :
4093 : bool bGotInt64NoDataValue;
4094 : int64_t nInt64NoDataValue;
4095 :
4096 : bool bGotUInt64NoDataValue;
4097 : uint64_t nUInt64NoDataValue;
4098 :
4099 : bool bGotFloatNoDataValue;
4100 : float fNoDataValue;
4101 :
4102 : bool bGotFloat16NoDataValue;
4103 : GFloat16 hfNoDataValue;
4104 :
4105 3174 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4106 3174 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4107 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4108 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4109 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4110 3174 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4111 : {
4112 3174 : if (eDataType == GDT_Int64)
4113 : {
4114 62 : int nGot = false;
4115 62 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4116 62 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4117 62 : if (bGotInt64NoDataValue)
4118 : {
4119 10 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4120 10 : bGotNoDataValue =
4121 10 : nInt64NoDataValue <=
4122 20 : std::numeric_limits<int64_t>::max() - 1024 &&
4123 10 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4124 : }
4125 : else
4126 52 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4127 : }
4128 3112 : else if (eDataType == GDT_UInt64)
4129 : {
4130 38 : int nGot = false;
4131 38 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4132 38 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4133 38 : if (bGotUInt64NoDataValue)
4134 : {
4135 10 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4136 10 : bGotNoDataValue =
4137 10 : nUInt64NoDataValue <=
4138 20 : std::numeric_limits<uint64_t>::max() - 2048 &&
4139 10 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4140 : }
4141 : else
4142 28 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4143 : }
4144 : else
4145 : {
4146 3074 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4147 3074 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4148 :
4149 3074 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4150 3074 : fNoDataValue, bGotFloatNoDataValue);
4151 :
4152 3074 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4153 3074 : hfNoDataValue, bGotFloat16NoDataValue);
4154 : }
4155 3174 : }
4156 : };
4157 :
4158 : /************************************************************************/
4159 : /* ARE_REAL_EQUAL() */
4160 : /************************************************************************/
4161 :
4162 28 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4163 : {
4164 : using std::abs;
4165 56 : return dfVal1 == dfVal2 || /* Should cover infinity */
4166 28 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4167 28 : abs(dfVal1 + dfVal2) * ulp;
4168 : }
4169 :
4170 : /************************************************************************/
4171 : /* GetHistogram() */
4172 : /************************************************************************/
4173 :
4174 : /**
4175 : * \brief Compute raster histogram.
4176 : *
4177 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4178 : *
4179 : * For example to compute a simple 256 entry histogram of eight bit data,
4180 : * the following would be suitable. The unusual bounds are to ensure that
4181 : * bucket boundaries don't fall right on integer values causing possible errors
4182 : * due to rounding after scaling.
4183 : \code{.cpp}
4184 : GUIntBig anHistogram[256];
4185 :
4186 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4187 : GDALDummyProgress, nullptr );
4188 : \endcode
4189 : *
4190 : * Note that setting bApproxOK will generally result in a subsampling of the
4191 : * file, and will utilize overviews if available. It should generally
4192 : * produce a representative histogram for the data that is suitable for use
4193 : * in generating histogram based luts for instance. Generally bApproxOK is
4194 : * much faster than an exactly computed histogram.
4195 : *
4196 : * This method is the same as the C functions GDALGetRasterHistogram() and
4197 : * GDALGetRasterHistogramEx().
4198 : *
4199 : * @param dfMin the lower bound of the histogram.
4200 : * @param dfMax the upper bound of the histogram.
4201 : * @param nBuckets the number of buckets in panHistogram.
4202 : * @param panHistogram array into which the histogram totals are placed.
4203 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4204 : * mapped into panHistogram[0], and values above will be mapped into
4205 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4206 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4207 : * @param pfnProgress function to report progress to completion.
4208 : * @param pProgressData application data to pass to pfnProgress.
4209 : *
4210 : * @return CE_None on success, or CE_Failure if something goes wrong.
4211 : */
4212 :
4213 45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4214 : GUIntBig *panHistogram,
4215 : int bIncludeOutOfRange, int bApproxOK,
4216 : GDALProgressFunc pfnProgress,
4217 : void *pProgressData)
4218 :
4219 : {
4220 45 : CPLAssert(nullptr != panHistogram);
4221 :
4222 45 : if (pfnProgress == nullptr)
4223 29 : pfnProgress = GDALDummyProgress;
4224 :
4225 : /* -------------------------------------------------------------------- */
4226 : /* If we have overviews, use them for the histogram. */
4227 : /* -------------------------------------------------------------------- */
4228 45 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4229 : {
4230 : // FIXME: should we use the most reduced overview here or use some
4231 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4232 : // does?
4233 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4234 :
4235 0 : if (poBestOverview != this)
4236 : {
4237 0 : return poBestOverview->GetHistogram(
4238 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4239 0 : bApproxOK, pfnProgress, pProgressData);
4240 : }
4241 : }
4242 :
4243 : /* -------------------------------------------------------------------- */
4244 : /* Read actual data and build histogram. */
4245 : /* -------------------------------------------------------------------- */
4246 45 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4247 : {
4248 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4249 0 : return CE_Failure;
4250 : }
4251 :
4252 : // Written this way to deal with NaN
4253 45 : if (!(dfMax > dfMin))
4254 : {
4255 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4256 : "dfMax should be strictly greater than dfMin");
4257 5 : return CE_Failure;
4258 : }
4259 :
4260 : GDALRasterIOExtraArg sExtraArg;
4261 40 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4262 :
4263 40 : const double dfScale = nBuckets / (dfMax - dfMin);
4264 40 : if (dfScale == 0 || !std::isfinite(dfScale))
4265 : {
4266 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4267 : "dfMin and dfMax should be finite values such that "
4268 : "nBuckets / (dfMax - dfMin) is non-zero");
4269 5 : return CE_Failure;
4270 : }
4271 35 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4272 :
4273 35 : GDALNoDataValues sNoDataValues(this, eDataType);
4274 35 : GDALRasterBand *poMaskBand = nullptr;
4275 35 : if (!sNoDataValues.bGotNoDataValue)
4276 : {
4277 34 : const int l_nMaskFlags = GetMaskFlags();
4278 36 : if (l_nMaskFlags != GMF_ALL_VALID &&
4279 2 : GetColorInterpretation() != GCI_AlphaBand)
4280 : {
4281 2 : poMaskBand = GetMaskBand();
4282 : }
4283 : }
4284 :
4285 35 : bool bSignedByte = false;
4286 35 : if (eDataType == GDT_UInt8)
4287 : {
4288 26 : EnablePixelTypeSignedByteWarning(false);
4289 : const char *pszPixelType =
4290 26 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4291 26 : EnablePixelTypeSignedByteWarning(true);
4292 26 : bSignedByte =
4293 26 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4294 : }
4295 :
4296 35 : if (bApproxOK && HasArbitraryOverviews())
4297 : {
4298 : /* --------------------------------------------------------------------
4299 : */
4300 : /* Figure out how much the image should be reduced to get an */
4301 : /* approximate value. */
4302 : /* --------------------------------------------------------------------
4303 : */
4304 : const double dfReduction =
4305 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4306 : GDALSTAT_APPROX_NUMSAMPLES);
4307 :
4308 0 : int nXReduced = nRasterXSize;
4309 0 : int nYReduced = nRasterYSize;
4310 0 : if (dfReduction > 1.0)
4311 : {
4312 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4313 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4314 :
4315 : // Catch the case of huge resizing ratios here
4316 0 : if (nXReduced == 0)
4317 0 : nXReduced = 1;
4318 0 : if (nYReduced == 0)
4319 0 : nYReduced = 1;
4320 : }
4321 :
4322 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4323 : nXReduced, nYReduced);
4324 0 : if (!pData)
4325 0 : return CE_Failure;
4326 :
4327 : const CPLErr eErr =
4328 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4329 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4330 0 : if (eErr != CE_None)
4331 : {
4332 0 : CPLFree(pData);
4333 0 : return eErr;
4334 : }
4335 :
4336 0 : GByte *pabyMaskData = nullptr;
4337 0 : if (poMaskBand)
4338 : {
4339 : pabyMaskData =
4340 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4341 0 : if (!pabyMaskData)
4342 : {
4343 0 : CPLFree(pData);
4344 0 : return CE_Failure;
4345 : }
4346 :
4347 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4348 : pabyMaskData, nXReduced, nYReduced,
4349 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
4350 : {
4351 0 : CPLFree(pData);
4352 0 : CPLFree(pabyMaskData);
4353 0 : return CE_Failure;
4354 : }
4355 : }
4356 :
4357 : // This isn't the fastest way to do this, but is easier for now.
4358 0 : for (int iY = 0; iY < nYReduced; iY++)
4359 : {
4360 0 : for (int iX = 0; iX < nXReduced; iX++)
4361 : {
4362 0 : const int iOffset = iX + iY * nXReduced;
4363 0 : double dfValue = 0.0;
4364 :
4365 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4366 0 : continue;
4367 :
4368 0 : switch (eDataType)
4369 : {
4370 0 : case GDT_UInt8:
4371 : {
4372 0 : if (bSignedByte)
4373 0 : dfValue =
4374 0 : static_cast<signed char *>(pData)[iOffset];
4375 : else
4376 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4377 0 : break;
4378 : }
4379 0 : case GDT_Int8:
4380 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4381 0 : break;
4382 0 : case GDT_UInt16:
4383 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4384 0 : break;
4385 0 : case GDT_Int16:
4386 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4387 0 : break;
4388 0 : case GDT_UInt32:
4389 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4390 0 : break;
4391 0 : case GDT_Int32:
4392 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4393 0 : break;
4394 0 : case GDT_UInt64:
4395 0 : dfValue = static_cast<double>(
4396 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4397 0 : break;
4398 0 : case GDT_Int64:
4399 0 : dfValue = static_cast<double>(
4400 0 : static_cast<GInt64 *>(pData)[iOffset]);
4401 0 : break;
4402 0 : case GDT_Float16:
4403 : {
4404 : using namespace std;
4405 0 : const GFloat16 hfValue =
4406 0 : static_cast<GFloat16 *>(pData)[iOffset];
4407 0 : if (isnan(hfValue) ||
4408 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4409 0 : ARE_REAL_EQUAL(hfValue,
4410 : sNoDataValues.hfNoDataValue)))
4411 0 : continue;
4412 0 : dfValue = hfValue;
4413 0 : break;
4414 : }
4415 0 : case GDT_Float32:
4416 : {
4417 0 : const float fValue =
4418 0 : static_cast<float *>(pData)[iOffset];
4419 0 : if (std::isnan(fValue) ||
4420 0 : (sNoDataValues.bGotFloatNoDataValue &&
4421 0 : ARE_REAL_EQUAL(fValue,
4422 : sNoDataValues.fNoDataValue)))
4423 0 : continue;
4424 0 : dfValue = double(fValue);
4425 0 : break;
4426 : }
4427 0 : case GDT_Float64:
4428 0 : dfValue = static_cast<double *>(pData)[iOffset];
4429 0 : if (std::isnan(dfValue))
4430 0 : continue;
4431 0 : break;
4432 0 : case GDT_CInt16:
4433 : {
4434 0 : const double dfReal =
4435 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4436 0 : const double dfImag =
4437 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4438 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4439 0 : continue;
4440 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4441 : }
4442 0 : break;
4443 0 : case GDT_CInt32:
4444 : {
4445 0 : const double dfReal =
4446 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4447 0 : const double dfImag =
4448 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4449 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4450 0 : continue;
4451 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4452 : }
4453 0 : break;
4454 0 : case GDT_CFloat16:
4455 : {
4456 : const double dfReal =
4457 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4458 : const double dfImag =
4459 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4460 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4461 0 : continue;
4462 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4463 0 : break;
4464 : }
4465 0 : case GDT_CFloat32:
4466 : {
4467 0 : const double dfReal =
4468 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4469 0 : const double dfImag = double(
4470 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4471 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4472 0 : continue;
4473 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4474 0 : break;
4475 : }
4476 0 : case GDT_CFloat64:
4477 : {
4478 0 : const double dfReal =
4479 0 : static_cast<double *>(pData)[iOffset * 2];
4480 0 : const double dfImag =
4481 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4482 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4483 0 : continue;
4484 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4485 0 : break;
4486 : }
4487 0 : case GDT_Unknown:
4488 : case GDT_TypeCount:
4489 0 : CPLAssert(false);
4490 : }
4491 :
4492 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4493 0 : sNoDataValues.bGotNoDataValue &&
4494 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4495 0 : continue;
4496 :
4497 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4498 : // finite, the result of the multiplication cannot be NaN
4499 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4500 :
4501 0 : if (dfIndex < 0)
4502 : {
4503 0 : if (bIncludeOutOfRange)
4504 0 : panHistogram[0]++;
4505 : }
4506 0 : else if (dfIndex >= nBuckets)
4507 : {
4508 0 : if (bIncludeOutOfRange)
4509 0 : ++panHistogram[nBuckets - 1];
4510 : }
4511 : else
4512 : {
4513 0 : ++panHistogram[static_cast<int>(dfIndex)];
4514 : }
4515 : }
4516 : }
4517 :
4518 0 : CPLFree(pData);
4519 0 : CPLFree(pabyMaskData);
4520 : }
4521 : else // No arbitrary overviews.
4522 : {
4523 35 : if (!InitBlockInfo())
4524 0 : return CE_Failure;
4525 :
4526 : /* --------------------------------------------------------------------
4527 : */
4528 : /* Figure out the ratio of blocks we will read to get an */
4529 : /* approximate value. */
4530 : /* --------------------------------------------------------------------
4531 : */
4532 :
4533 35 : int nSampleRate = 1;
4534 35 : if (bApproxOK)
4535 : {
4536 8 : nSampleRate = static_cast<int>(std::max(
4537 16 : 1.0,
4538 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4539 : // We want to avoid probing only the first column of blocks for
4540 : // a square shaped raster, because it is not unlikely that it may
4541 : // be padding only (#6378).
4542 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4543 1 : nSampleRate += 1;
4544 : }
4545 :
4546 35 : GByte *pabyMaskData = nullptr;
4547 35 : if (poMaskBand)
4548 : {
4549 : pabyMaskData = static_cast<GByte *>(
4550 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4551 2 : if (!pabyMaskData)
4552 : {
4553 0 : return CE_Failure;
4554 : }
4555 : }
4556 :
4557 : /* --------------------------------------------------------------------
4558 : */
4559 : /* Read the blocks, and add to histogram. */
4560 : /* --------------------------------------------------------------------
4561 : */
4562 35 : for (GIntBig iSampleBlock = 0;
4563 160 : iSampleBlock <
4564 160 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4565 125 : iSampleBlock += nSampleRate)
4566 : {
4567 125 : if (!pfnProgress(
4568 125 : static_cast<double>(iSampleBlock) /
4569 125 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4570 : "Compute Histogram", pProgressData))
4571 : {
4572 0 : CPLFree(pabyMaskData);
4573 0 : return CE_Failure;
4574 : }
4575 :
4576 125 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4577 125 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4578 :
4579 125 : int nXCheck = 0, nYCheck = 0;
4580 125 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4581 :
4582 127 : if (poMaskBand &&
4583 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4584 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4585 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4586 2 : 0, nBlockXSize, nullptr) != CE_None)
4587 : {
4588 0 : CPLFree(pabyMaskData);
4589 0 : return CE_Failure;
4590 : }
4591 :
4592 125 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4593 125 : if (poBlock == nullptr)
4594 : {
4595 0 : CPLFree(pabyMaskData);
4596 0 : return CE_Failure;
4597 : }
4598 :
4599 125 : void *pData = poBlock->GetDataRef();
4600 :
4601 : // this is a special case for a common situation.
4602 125 : if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4603 89 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4604 86 : nXCheck == nBlockXSize && nBuckets == 256)
4605 : {
4606 86 : const GPtrDiff_t nPixels =
4607 86 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4608 86 : GByte *pabyData = static_cast<GByte *>(pData);
4609 :
4610 79640 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4611 : {
4612 79554 : if (pabyMaskData && pabyMaskData[i] == 0)
4613 0 : continue;
4614 79554 : if (!(sNoDataValues.bGotNoDataValue &&
4615 512 : (pabyData[i] ==
4616 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4617 : {
4618 79298 : panHistogram[pabyData[i]]++;
4619 : }
4620 : }
4621 :
4622 86 : poBlock->DropLock();
4623 86 : continue; // To next sample block.
4624 : }
4625 :
4626 : // This isn't the fastest way to do this, but is easier for now.
4627 257 : for (int iY = 0; iY < nYCheck; iY++)
4628 : {
4629 36389 : for (int iX = 0; iX < nXCheck; iX++)
4630 : {
4631 36171 : const GPtrDiff_t iOffset =
4632 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4633 :
4634 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4635 2 : continue;
4636 :
4637 36169 : double dfValue = 0.0;
4638 :
4639 36169 : switch (eDataType)
4640 : {
4641 19716 : case GDT_UInt8:
4642 : {
4643 19716 : if (bSignedByte)
4644 0 : dfValue =
4645 0 : static_cast<signed char *>(pData)[iOffset];
4646 : else
4647 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4648 19716 : break;
4649 : }
4650 1 : case GDT_Int8:
4651 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4652 1 : break;
4653 16384 : case GDT_UInt16:
4654 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4655 16384 : break;
4656 3 : case GDT_Int16:
4657 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4658 3 : break;
4659 0 : case GDT_UInt32:
4660 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4661 0 : break;
4662 60 : case GDT_Int32:
4663 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4664 60 : break;
4665 0 : case GDT_UInt64:
4666 0 : dfValue = static_cast<double>(
4667 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4668 0 : break;
4669 0 : case GDT_Int64:
4670 0 : dfValue = static_cast<double>(
4671 0 : static_cast<GInt64 *>(pData)[iOffset]);
4672 0 : break;
4673 0 : case GDT_Float16:
4674 : {
4675 : using namespace std;
4676 0 : const GFloat16 hfValue =
4677 0 : static_cast<GFloat16 *>(pData)[iOffset];
4678 0 : if (isnan(hfValue) ||
4679 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4680 0 : ARE_REAL_EQUAL(hfValue,
4681 : sNoDataValues.hfNoDataValue)))
4682 0 : continue;
4683 0 : dfValue = hfValue;
4684 0 : break;
4685 : }
4686 3 : case GDT_Float32:
4687 : {
4688 3 : const float fValue =
4689 3 : static_cast<float *>(pData)[iOffset];
4690 6 : if (std::isnan(fValue) ||
4691 6 : (sNoDataValues.bGotFloatNoDataValue &&
4692 3 : ARE_REAL_EQUAL(fValue,
4693 : sNoDataValues.fNoDataValue)))
4694 0 : continue;
4695 3 : dfValue = double(fValue);
4696 3 : break;
4697 : }
4698 2 : case GDT_Float64:
4699 2 : dfValue = static_cast<double *>(pData)[iOffset];
4700 2 : if (std::isnan(dfValue))
4701 0 : continue;
4702 2 : break;
4703 0 : case GDT_CInt16:
4704 : {
4705 0 : double dfReal =
4706 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4707 0 : double dfImag =
4708 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4709 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4710 0 : break;
4711 : }
4712 0 : case GDT_CInt32:
4713 : {
4714 0 : double dfReal =
4715 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4716 0 : double dfImag =
4717 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4718 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4719 0 : break;
4720 : }
4721 0 : case GDT_CFloat16:
4722 : {
4723 : double dfReal =
4724 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4725 : double dfImag =
4726 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4727 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4728 0 : continue;
4729 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4730 0 : break;
4731 : }
4732 0 : case GDT_CFloat32:
4733 : {
4734 0 : double dfReal = double(
4735 0 : static_cast<float *>(pData)[iOffset * 2]);
4736 0 : double dfImag = double(
4737 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4738 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4739 0 : continue;
4740 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4741 0 : break;
4742 : }
4743 0 : case GDT_CFloat64:
4744 : {
4745 0 : double dfReal =
4746 0 : static_cast<double *>(pData)[iOffset * 2];
4747 0 : double dfImag =
4748 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4749 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4750 0 : continue;
4751 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4752 0 : break;
4753 : }
4754 0 : case GDT_Unknown:
4755 : case GDT_TypeCount:
4756 0 : CPLAssert(false);
4757 : CPLFree(pabyMaskData);
4758 : return CE_Failure;
4759 : }
4760 :
4761 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4762 72338 : sNoDataValues.bGotNoDataValue &&
4763 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4764 0 : continue;
4765 :
4766 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4767 : // and finite, the result of the multiplication cannot be
4768 : // NaN
4769 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4770 :
4771 36169 : if (dfIndex < 0)
4772 : {
4773 1 : if (bIncludeOutOfRange)
4774 1 : panHistogram[0]++;
4775 : }
4776 36168 : else if (dfIndex >= nBuckets)
4777 : {
4778 7 : if (bIncludeOutOfRange)
4779 4 : ++panHistogram[nBuckets - 1];
4780 : }
4781 : else
4782 : {
4783 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4784 : }
4785 : }
4786 : }
4787 :
4788 39 : poBlock->DropLock();
4789 : }
4790 :
4791 35 : CPLFree(pabyMaskData);
4792 : }
4793 :
4794 35 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4795 :
4796 35 : return CE_None;
4797 : }
4798 :
4799 : /************************************************************************/
4800 : /* GDALGetRasterHistogram() */
4801 : /************************************************************************/
4802 :
4803 : /**
4804 : * \brief Compute raster histogram.
4805 : *
4806 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4807 : * exceeding 2 billion.
4808 : *
4809 : * @see GDALRasterBand::GetHistogram()
4810 : * @see GDALGetRasterHistogramEx()
4811 : */
4812 :
4813 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4814 : double dfMax, int nBuckets,
4815 : int *panHistogram,
4816 : int bIncludeOutOfRange, int bApproxOK,
4817 : GDALProgressFunc pfnProgress,
4818 : void *pProgressData)
4819 :
4820 : {
4821 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4822 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4823 :
4824 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4825 :
4826 : GUIntBig *panHistogramTemp =
4827 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4828 0 : if (panHistogramTemp == nullptr)
4829 : {
4830 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4831 : "Out of memory in GDALGetRasterHistogram().");
4832 0 : return CE_Failure;
4833 : }
4834 :
4835 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4836 : bIncludeOutOfRange, bApproxOK,
4837 0 : pfnProgress, pProgressData);
4838 :
4839 0 : if (eErr == CE_None)
4840 : {
4841 0 : for (int i = 0; i < nBuckets; i++)
4842 : {
4843 0 : if (panHistogramTemp[i] > INT_MAX)
4844 : {
4845 0 : CPLError(CE_Warning, CPLE_AppDefined,
4846 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4847 : " exceeds maximum 32 bit value",
4848 0 : i, panHistogramTemp[i]);
4849 0 : panHistogram[i] = INT_MAX;
4850 : }
4851 : else
4852 : {
4853 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4854 : }
4855 : }
4856 : }
4857 :
4858 0 : CPLFree(panHistogramTemp);
4859 :
4860 0 : return eErr;
4861 : }
4862 :
4863 : /************************************************************************/
4864 : /* GDALGetRasterHistogramEx() */
4865 : /************************************************************************/
4866 :
4867 : /**
4868 : * \brief Compute raster histogram.
4869 : *
4870 : * @see GDALRasterBand::GetHistogram()
4871 : *
4872 : */
4873 :
4874 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4875 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4876 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4877 : GDALProgressFunc pfnProgress, void *pProgressData)
4878 :
4879 : {
4880 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4881 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4882 :
4883 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4884 :
4885 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4886 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4887 26 : pProgressData);
4888 : }
4889 :
4890 : /************************************************************************/
4891 : /* GetDefaultHistogram() */
4892 : /************************************************************************/
4893 :
4894 : /**
4895 : * \brief Fetch default raster histogram.
4896 : *
4897 : * The default method in GDALRasterBand will compute a default histogram. This
4898 : * method is overridden by derived classes (such as GDALPamRasterBand,
4899 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4900 : * stored histogram.
4901 : *
4902 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4903 : * GDALGetDefaultHistogramEx().
4904 : *
4905 : * @param pdfMin pointer to double value that will contain the lower bound of
4906 : * the histogram.
4907 : * @param pdfMax pointer to double value that will contain the upper bound of
4908 : * the histogram.
4909 : * @param pnBuckets pointer to int value that will contain the number of buckets
4910 : * in *ppanHistogram.
4911 : * @param ppanHistogram pointer to array into which the histogram totals are
4912 : * placed. To be freed with VSIFree
4913 : * @param bForce TRUE to force the computation. If FALSE and no default
4914 : * histogram is available, the method will return CE_Warning
4915 : * @param pfnProgress function to report progress to completion.
4916 : * @param pProgressData application data to pass to pfnProgress.
4917 : *
4918 : * @return CE_None on success, CE_Failure if something goes wrong, or
4919 : * CE_Warning if no default histogram is available.
4920 : */
4921 :
4922 27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4923 : int *pnBuckets,
4924 : GUIntBig **ppanHistogram, int bForce,
4925 : GDALProgressFunc pfnProgress,
4926 : void *pProgressData)
4927 :
4928 : {
4929 27 : CPLAssert(nullptr != pnBuckets);
4930 27 : CPLAssert(nullptr != ppanHistogram);
4931 27 : CPLAssert(nullptr != pdfMin);
4932 27 : CPLAssert(nullptr != pdfMax);
4933 :
4934 27 : *pnBuckets = 0;
4935 27 : *ppanHistogram = nullptr;
4936 :
4937 27 : if (!bForce)
4938 5 : return CE_Warning;
4939 :
4940 22 : int nBuckets = 256;
4941 :
4942 22 : bool bSignedByte = false;
4943 22 : if (eDataType == GDT_UInt8)
4944 : {
4945 20 : EnablePixelTypeSignedByteWarning(false);
4946 : const char *pszPixelType =
4947 20 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4948 20 : EnablePixelTypeSignedByteWarning(true);
4949 20 : bSignedByte =
4950 20 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4951 : }
4952 :
4953 22 : if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4954 : {
4955 20 : *pdfMin = -0.5;
4956 20 : *pdfMax = 255.5;
4957 : }
4958 2 : else if (GetRasterDataType() == GDT_Int8)
4959 : {
4960 1 : *pdfMin = -128 - 0.5;
4961 1 : *pdfMax = 127 + 0.5;
4962 : }
4963 : else
4964 : {
4965 :
4966 : const CPLErr eErr =
4967 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4968 1 : if (eErr != CE_None)
4969 0 : return eErr;
4970 1 : if (*pdfMin == *pdfMax)
4971 : {
4972 1 : nBuckets = 1;
4973 1 : *pdfMin -= 0.5;
4974 1 : *pdfMax += 0.5;
4975 : }
4976 : else
4977 : {
4978 0 : const double dfHalfBucket =
4979 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4980 0 : *pdfMin -= dfHalfBucket;
4981 0 : *pdfMax += dfHalfBucket;
4982 : }
4983 : }
4984 :
4985 22 : *ppanHistogram =
4986 22 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4987 22 : if (*ppanHistogram == nullptr)
4988 : {
4989 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4990 : "Out of memory in GetDefaultHistogram().");
4991 0 : return CE_Failure;
4992 : }
4993 :
4994 22 : *pnBuckets = nBuckets;
4995 44 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4996 22 : TRUE, FALSE, pfnProgress, pProgressData);
4997 22 : if (eErr != CE_None)
4998 : {
4999 0 : *pnBuckets = 0;
5000 : }
5001 22 : return eErr;
5002 : }
5003 :
5004 : /************************************************************************/
5005 : /* GDALGetDefaultHistogram() */
5006 : /************************************************************************/
5007 :
5008 : /**
5009 : * \brief Fetch default raster histogram.
5010 : *
5011 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5012 : * exceeding 2 billion.
5013 : *
5014 : * @see GDALRasterBand::GDALGetDefaultHistogram()
5015 : * @see GDALGetRasterHistogramEx()
5016 : */
5017 :
5018 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5019 : double *pdfMin, double *pdfMax,
5020 : int *pnBuckets, int **ppanHistogram,
5021 : int bForce,
5022 : GDALProgressFunc pfnProgress,
5023 : void *pProgressData)
5024 :
5025 : {
5026 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5027 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5028 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5029 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5030 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5031 :
5032 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5033 0 : GUIntBig *panHistogramTemp = nullptr;
5034 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5035 : &panHistogramTemp, bForce,
5036 0 : pfnProgress, pProgressData);
5037 0 : if (eErr == CE_None)
5038 : {
5039 0 : const int nBuckets = *pnBuckets;
5040 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5041 0 : if (*ppanHistogram == nullptr)
5042 : {
5043 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5044 : "Out of memory in GDALGetDefaultHistogram().");
5045 0 : VSIFree(panHistogramTemp);
5046 0 : return CE_Failure;
5047 : }
5048 :
5049 0 : for (int i = 0; i < nBuckets; ++i)
5050 : {
5051 0 : if (panHistogramTemp[i] > INT_MAX)
5052 : {
5053 0 : CPLError(CE_Warning, CPLE_AppDefined,
5054 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5055 : " exceeds maximum 32 bit value",
5056 0 : i, panHistogramTemp[i]);
5057 0 : (*ppanHistogram)[i] = INT_MAX;
5058 : }
5059 : else
5060 : {
5061 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5062 : }
5063 : }
5064 :
5065 0 : CPLFree(panHistogramTemp);
5066 : }
5067 : else
5068 : {
5069 0 : *ppanHistogram = nullptr;
5070 : }
5071 :
5072 0 : return eErr;
5073 : }
5074 :
5075 : /************************************************************************/
5076 : /* GDALGetDefaultHistogramEx() */
5077 : /************************************************************************/
5078 :
5079 : /**
5080 : * \brief Fetch default raster histogram.
5081 : *
5082 : * @see GDALRasterBand::GetDefaultHistogram()
5083 : *
5084 : */
5085 :
5086 : CPLErr CPL_STDCALL
5087 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5088 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5089 : GDALProgressFunc pfnProgress, void *pProgressData)
5090 :
5091 : {
5092 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5093 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5094 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5095 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5096 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5097 :
5098 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5099 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5100 30 : bForce, pfnProgress, pProgressData);
5101 : }
5102 :
5103 : /************************************************************************/
5104 : /* AdviseRead() */
5105 : /************************************************************************/
5106 :
5107 : /**
5108 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5109 : * \brief Advise driver of upcoming read requests.
5110 : *
5111 : * Some GDAL drivers operate more efficiently if they know in advance what
5112 : * set of upcoming read requests will be made. The AdviseRead() method allows
5113 : * an application to notify the driver of the region of interest,
5114 : * and at what resolution the region will be read.
5115 : *
5116 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5117 : * accelerate access via some drivers.
5118 : *
5119 : * Depending on call paths, drivers might receive several calls to
5120 : * AdviseRead() with the same parameters.
5121 : *
5122 : * @param nXOff The pixel offset to the top left corner of the region
5123 : * of the band to be accessed. This would be zero to start from the left side.
5124 : *
5125 : * @param nYOff The line offset to the top left corner of the region
5126 : * of the band to be accessed. This would be zero to start from the top.
5127 : *
5128 : * @param nXSize The width of the region of the band to be accessed in pixels.
5129 : *
5130 : * @param nYSize The height of the region of the band to be accessed in lines.
5131 : *
5132 : * @param nBufXSize the width of the buffer image into which the desired region
5133 : * is to be read, or from which it is to be written.
5134 : *
5135 : * @param nBufYSize the height of the buffer image into which the desired
5136 : * region is to be read, or from which it is to be written.
5137 : *
5138 : * @param eBufType the type of the pixel values in the pData data buffer. The
5139 : * pixel values will automatically be translated to/from the GDALRasterBand
5140 : * data type as needed.
5141 : *
5142 : * @param papszOptions a list of name=value strings with special control
5143 : * options. Normally this is NULL.
5144 : *
5145 : * @return CE_Failure if the request is invalid and CE_None if it works or
5146 : * is ignored.
5147 : */
5148 :
5149 : /**/
5150 : /**/
5151 :
5152 114460 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5153 : int /*nYSize*/, int /*nBufXSize*/,
5154 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5155 : CSLConstList /*papszOptions*/)
5156 : {
5157 114460 : return CE_None;
5158 : }
5159 :
5160 : /************************************************************************/
5161 : /* GDALRasterAdviseRead() */
5162 : /************************************************************************/
5163 :
5164 : /**
5165 : * \brief Advise driver of upcoming read requests.
5166 : *
5167 : * @see GDALRasterBand::AdviseRead()
5168 : */
5169 :
5170 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5171 : int nYOff, int nXSize, int nYSize,
5172 : int nBufXSize, int nBufYSize,
5173 : GDALDataType eDT,
5174 : CSLConstList papszOptions)
5175 :
5176 : {
5177 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5178 :
5179 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5180 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5181 : nBufYSize, eDT,
5182 2 : const_cast<char **>(papszOptions));
5183 : }
5184 :
5185 : /************************************************************************/
5186 : /* GetStatistics() */
5187 : /************************************************************************/
5188 :
5189 : /**
5190 : * \brief Fetch image statistics.
5191 : *
5192 : * Returns the minimum, maximum, mean and standard deviation of all
5193 : * pixel values in this band. If approximate statistics are sufficient,
5194 : * the bApproxOK flag can be set to true in which case overviews, or a
5195 : * subset of image tiles may be used in computing the statistics.
5196 : *
5197 : * If bForce is FALSE results will only be returned if it can be done
5198 : * quickly (i.e. without scanning the image, typically by using pre-existing
5199 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5200 : * returned efficiently, the method will return CE_Warning but no warning will
5201 : * be issued. This is a non-standard use of the CE_Warning return value
5202 : * to indicate "nothing done".
5203 : *
5204 : * If bForce is TRUE, and results are quickly available without scanning the
5205 : * image, they will be used. If bForce is TRUE and results are not quickly
5206 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5207 : * which will scan the image.
5208 : *
5209 : * To always force recomputation of statistics, use ComputeStatistics() instead
5210 : * of this method.
5211 : *
5212 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5213 : * will generally cache statistics in the .pam file allowing fast fetch
5214 : * after the first request.
5215 : *
5216 : * This method is the same as the C function GDALGetRasterStatistics().
5217 : *
5218 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5219 : * or a subset of all tiles.
5220 : *
5221 : * @param bForce If FALSE statistics will only be returned if it can
5222 : * be done without rescanning the image. If TRUE, statistics computation will
5223 : * be forced if pre-existing values are not quickly available.
5224 : *
5225 : * @param pdfMin Location into which to load image minimum (may be NULL).
5226 : *
5227 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5228 : *
5229 : * @param pdfMean Location into which to load image mean (may be NULL).
5230 : *
5231 : * @param pdfStdDev Location into which to load image standard deviation
5232 : * (may be NULL).
5233 : *
5234 : * @return CE_None on success, CE_Warning if no values returned,
5235 : * CE_Failure if an error occurs.
5236 : */
5237 :
5238 673 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5239 : double *pdfMax, double *pdfMean,
5240 : double *pdfStdDev)
5241 :
5242 : {
5243 : /* -------------------------------------------------------------------- */
5244 : /* Do we already have metadata items for the requested values? */
5245 : /* -------------------------------------------------------------------- */
5246 1346 : if ((pdfMin == nullptr ||
5247 673 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5248 206 : (pdfMax == nullptr ||
5249 206 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5250 1552 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5251 206 : (pdfStdDev == nullptr ||
5252 206 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5253 : {
5254 206 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5255 : {
5256 199 : if (pdfMin != nullptr)
5257 199 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5258 199 : if (pdfMax != nullptr)
5259 199 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5260 199 : if (pdfMean != nullptr)
5261 199 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5262 199 : if (pdfStdDev != nullptr)
5263 199 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5264 :
5265 199 : return CE_None;
5266 : }
5267 : }
5268 :
5269 : /* -------------------------------------------------------------------- */
5270 : /* Does the driver already know the min/max? */
5271 : /* -------------------------------------------------------------------- */
5272 474 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5273 : {
5274 1 : int bSuccessMin = FALSE;
5275 1 : int bSuccessMax = FALSE;
5276 :
5277 1 : const double dfMin = GetMinimum(&bSuccessMin);
5278 1 : const double dfMax = GetMaximum(&bSuccessMax);
5279 :
5280 1 : if (bSuccessMin && bSuccessMax)
5281 : {
5282 0 : if (pdfMin != nullptr)
5283 0 : *pdfMin = dfMin;
5284 0 : if (pdfMax != nullptr)
5285 0 : *pdfMax = dfMax;
5286 0 : return CE_None;
5287 : }
5288 : }
5289 :
5290 : /* -------------------------------------------------------------------- */
5291 : /* Either return without results, or force computation. */
5292 : /* -------------------------------------------------------------------- */
5293 474 : if (!bForce)
5294 191 : return CE_Warning;
5295 : else
5296 283 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5297 283 : GDALDummyProgress, nullptr);
5298 : }
5299 :
5300 : /************************************************************************/
5301 : /* GDALGetRasterStatistics() */
5302 : /************************************************************************/
5303 :
5304 : /**
5305 : * \brief Fetch image statistics.
5306 : *
5307 : * @see GDALRasterBand::GetStatistics()
5308 : */
5309 :
5310 321 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5311 : int bForce, double *pdfMin,
5312 : double *pdfMax, double *pdfMean,
5313 : double *pdfStdDev)
5314 :
5315 : {
5316 321 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5317 :
5318 321 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5319 321 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5320 321 : pdfStdDev);
5321 : }
5322 :
5323 : /************************************************************************/
5324 : /* GDALUInt128 */
5325 : /************************************************************************/
5326 :
5327 : #ifdef HAVE_UINT128_T
5328 : class GDALUInt128
5329 : {
5330 : __uint128_t val;
5331 :
5332 1188 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5333 : {
5334 1188 : }
5335 :
5336 : public:
5337 792 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5338 : {
5339 : // Evaluates to just a single mul on x86_64
5340 792 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5341 : }
5342 :
5343 396 : GDALUInt128 operator-(const GDALUInt128 &other) const
5344 : {
5345 396 : return GDALUInt128(val - other.val);
5346 : }
5347 :
5348 387 : operator double() const
5349 : {
5350 387 : return static_cast<double>(val);
5351 : }
5352 : };
5353 : #else
5354 :
5355 : #if defined(_MSC_VER) && defined(_M_X64)
5356 : #include <intrin.h>
5357 : #endif
5358 :
5359 : class GDALUInt128
5360 : {
5361 : GUIntBig low, high;
5362 :
5363 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5364 : {
5365 : }
5366 :
5367 : public:
5368 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5369 : {
5370 : #if defined(_MSC_VER) && defined(_M_X64)
5371 : GUIntBig highRes;
5372 : GUIntBig lowRes = _umul128(first, second, &highRes);
5373 : return GDALUInt128(lowRes, highRes);
5374 : #else
5375 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5376 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5377 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5378 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5379 : GUIntBig highRes = 0;
5380 : const GUIntBig firstLowSecondHigh =
5381 : static_cast<GUIntBig>(firstLow) * secondHigh;
5382 : const GUIntBig firstHighSecondLow =
5383 : static_cast<GUIntBig>(firstHigh) * secondLow;
5384 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5385 : if (middleTerm < firstLowSecondHigh) // check for overflow
5386 : highRes += static_cast<GUIntBig>(1) << 32;
5387 : const GUIntBig firstLowSecondLow =
5388 : static_cast<GUIntBig>(firstLow) * secondLow;
5389 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5390 : if (lowRes < firstLowSecondLow) // check for overflow
5391 : highRes++;
5392 : highRes +=
5393 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5394 : return GDALUInt128(lowRes, highRes);
5395 : #endif
5396 : }
5397 :
5398 : GDALUInt128 operator-(const GDALUInt128 &other) const
5399 : {
5400 : GUIntBig highRes = high - other.high;
5401 : GUIntBig lowRes = low - other.low;
5402 : if (lowRes > low) // check for underflow
5403 : --highRes;
5404 : return GDALUInt128(lowRes, highRes);
5405 : }
5406 :
5407 : operator double() const
5408 : {
5409 : const double twoPow64 = 18446744073709551616.0;
5410 : return high * twoPow64 + low;
5411 : }
5412 : };
5413 : #endif
5414 :
5415 : /************************************************************************/
5416 : /* ComputeStatisticsInternal() */
5417 : /************************************************************************/
5418 :
5419 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5420 : // not needed.
5421 : #define static_cast_for_coverity_scan static_cast
5422 :
5423 : // The rationale for below optimizations is detailed in statistics.txt
5424 :
5425 : // Use with T = GByte or GUInt16 only !
5426 : template <class T, bool COMPUTE_OTHER_STATS>
5427 : struct ComputeStatisticsInternalGeneric
5428 : {
5429 255 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5430 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5431 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5432 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5433 : {
5434 : static_assert(std::is_same<T, GByte>::value ||
5435 : std::is_same<T, GUInt16>::value,
5436 : "bad type for T");
5437 255 : if (bHasNoData)
5438 : {
5439 : // General case
5440 620 : for (int iY = 0; iY < nYCheck; iY++)
5441 : {
5442 161785 : for (int iX = 0; iX < nXCheck; iX++)
5443 : {
5444 161293 : const GPtrDiff_t iOffset =
5445 161293 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5446 161293 : const GUInt32 nValue = pData[iOffset];
5447 161293 : if (nValue == nNoDataValue)
5448 323 : continue;
5449 160970 : if (nValue < nMin)
5450 44 : nMin = nValue;
5451 160970 : if (nValue > nMax)
5452 75 : nMax = nValue;
5453 : if constexpr (COMPUTE_OTHER_STATS)
5454 : {
5455 159334 : nValidCount++;
5456 159334 : nSum += nValue;
5457 159334 : nSumSquare +=
5458 159334 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5459 159334 : nValue;
5460 : }
5461 : }
5462 : }
5463 : if constexpr (COMPUTE_OTHER_STATS)
5464 : {
5465 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5466 : }
5467 : }
5468 145 : else if (nMin == std::numeric_limits<T>::lowest() &&
5469 18 : nMax == std::numeric_limits<T>::max())
5470 : {
5471 : if constexpr (COMPUTE_OTHER_STATS)
5472 : {
5473 : // Optimization when there is no nodata and we know we have already
5474 : // reached the min and max
5475 416 : for (int iY = 0; iY < nYCheck; iY++)
5476 : {
5477 : int iX;
5478 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5479 : {
5480 1600 : const GPtrDiff_t iOffset =
5481 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5482 1600 : const GUIntBig nValue = pData[iOffset];
5483 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5484 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5485 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5486 1600 : nSum += nValue;
5487 1600 : nSumSquare += nValue * nValue;
5488 1600 : nSum += nValue2;
5489 1600 : nSumSquare += nValue2 * nValue2;
5490 1600 : nSum += nValue3;
5491 1600 : nSumSquare += nValue3 * nValue3;
5492 1600 : nSum += nValue4;
5493 1600 : nSumSquare += nValue4 * nValue4;
5494 : }
5495 414 : for (; iX < nXCheck; ++iX)
5496 : {
5497 10 : const GPtrDiff_t iOffset =
5498 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5499 10 : const GUIntBig nValue = pData[iOffset];
5500 10 : nSum += nValue;
5501 10 : nSumSquare += nValue * nValue;
5502 : }
5503 : }
5504 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5505 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5506 : }
5507 : }
5508 : else
5509 : {
5510 6021 : for (int iY = 0; iY < nYCheck; iY++)
5511 : {
5512 : int iX;
5513 1270512 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5514 : {
5515 1264612 : const GPtrDiff_t iOffset =
5516 1264612 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5517 1264612 : const GUInt32 nValue = pData[iOffset];
5518 1264612 : const GUInt32 nValue2 = pData[iOffset + 1];
5519 1264612 : if (nValue < nValue2)
5520 : {
5521 2325 : if (nValue < nMin)
5522 51 : nMin = nValue;
5523 2325 : if (nValue2 > nMax)
5524 119 : nMax = nValue2;
5525 : }
5526 : else
5527 : {
5528 1262285 : if (nValue2 < nMin)
5529 67 : nMin = nValue2;
5530 1262285 : if (nValue > nMax)
5531 216 : nMax = nValue;
5532 : }
5533 : if constexpr (COMPUTE_OTHER_STATS)
5534 : {
5535 1257560 : nSum += nValue;
5536 1257560 : nSumSquare +=
5537 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5538 1257560 : nValue;
5539 1257560 : nSum += nValue2;
5540 1257560 : nSumSquare +=
5541 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5542 1257560 : nValue2;
5543 : }
5544 : }
5545 5906 : if (iX < nXCheck)
5546 : {
5547 27 : const GPtrDiff_t iOffset =
5548 27 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5549 27 : const GUInt32 nValue = pData[iOffset];
5550 27 : if (nValue < nMin)
5551 19 : nMin = nValue;
5552 27 : if (nValue > nMax)
5553 20 : nMax = nValue;
5554 : if (COMPUTE_OTHER_STATS)
5555 : {
5556 19 : nSum += nValue;
5557 19 : nSumSquare +=
5558 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5559 19 : nValue;
5560 : }
5561 : }
5562 : }
5563 : if constexpr (COMPUTE_OTHER_STATS)
5564 : {
5565 60 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5566 60 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5567 : }
5568 : }
5569 255 : }
5570 : };
5571 :
5572 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5573 : // using 64bit accumulators in internal loops. This also slightly helps in
5574 : // 64bit mode.
5575 : template <bool COMPUTE_OTHER_STATS>
5576 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5577 : {
5578 13781 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5579 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5580 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5581 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5582 : {
5583 13781 : int nOuterLoops = nXCheck / 65536;
5584 13781 : if (nXCheck % 65536)
5585 13781 : nOuterLoops++;
5586 :
5587 13781 : if (bHasNoData)
5588 : {
5589 : // General case
5590 23801 : for (int iY = 0; iY < nYCheck; iY++)
5591 : {
5592 13205 : int iX = 0;
5593 26410 : for (int k = 0; k < nOuterLoops; k++)
5594 : {
5595 13205 : int iMax = iX + 65536;
5596 13205 : if (iMax > nXCheck)
5597 13205 : iMax = nXCheck;
5598 13205 : GUInt32 nSum32bit = 0;
5599 13205 : GUInt32 nSumSquare32bit = 0;
5600 13205 : GUInt32 nValidCount32bit = 0;
5601 13205 : GUInt32 nSampleCount32bit = 0;
5602 20722932 : for (; iX < iMax; iX++)
5603 : {
5604 20709787 : const GPtrDiff_t iOffset =
5605 20709787 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5606 20709787 : const GUInt32 nValue = pData[iOffset];
5607 :
5608 20709787 : nSampleCount32bit++;
5609 20709787 : if (nValue == nNoDataValue)
5610 20353620 : continue;
5611 356112 : if (nValue < nMin)
5612 381 : nMin = nValue;
5613 356112 : if (nValue > nMax)
5614 838 : nMax = nValue;
5615 : if constexpr (COMPUTE_OTHER_STATS)
5616 : {
5617 32367 : nValidCount32bit++;
5618 32367 : nSum32bit += nValue;
5619 32367 : nSumSquare32bit += nValue * nValue;
5620 : }
5621 : }
5622 : if constexpr (COMPUTE_OTHER_STATS)
5623 : {
5624 945 : nSampleCount += nSampleCount32bit;
5625 945 : nValidCount += nValidCount32bit;
5626 945 : nSum += nSum32bit;
5627 945 : nSumSquare += nSumSquare32bit;
5628 : }
5629 : }
5630 : }
5631 : }
5632 3185 : else if (nMin == 0 && nMax == 255)
5633 : {
5634 : if constexpr (COMPUTE_OTHER_STATS)
5635 : {
5636 : // Optimization when there is no nodata and we know we have already
5637 : // reached the min and max
5638 2850 : for (int iY = 0; iY < nYCheck; iY++)
5639 : {
5640 2818 : int iX = 0;
5641 5636 : for (int k = 0; k < nOuterLoops; k++)
5642 : {
5643 2818 : int iMax = iX + 65536;
5644 2818 : if (iMax > nXCheck)
5645 2818 : iMax = nXCheck;
5646 2818 : GUInt32 nSum32bit = 0;
5647 2818 : GUInt32 nSumSquare32bit = 0;
5648 177298 : for (; iX + 3 < iMax; iX += 4)
5649 : {
5650 174480 : const GPtrDiff_t iOffset =
5651 174480 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5652 174480 : const GUInt32 nValue = pData[iOffset];
5653 174480 : const GUInt32 nValue2 = pData[iOffset + 1];
5654 174480 : const GUInt32 nValue3 = pData[iOffset + 2];
5655 174480 : const GUInt32 nValue4 = pData[iOffset + 3];
5656 174480 : nSum32bit += nValue;
5657 174480 : nSumSquare32bit += nValue * nValue;
5658 174480 : nSum32bit += nValue2;
5659 174480 : nSumSquare32bit += nValue2 * nValue2;
5660 174480 : nSum32bit += nValue3;
5661 174480 : nSumSquare32bit += nValue3 * nValue3;
5662 174480 : nSum32bit += nValue4;
5663 174480 : nSumSquare32bit += nValue4 * nValue4;
5664 : }
5665 2818 : nSum += nSum32bit;
5666 2818 : nSumSquare += nSumSquare32bit;
5667 : }
5668 2824 : for (; iX < nXCheck; ++iX)
5669 : {
5670 6 : const GPtrDiff_t iOffset =
5671 6 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5672 6 : const GUIntBig nValue = pData[iOffset];
5673 6 : nSum += nValue;
5674 6 : nSumSquare += nValue * nValue;
5675 : }
5676 : }
5677 32 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5678 32 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5679 32 : }
5680 : }
5681 : else
5682 : {
5683 8510 : for (int iY = 0; iY < nYCheck; iY++)
5684 : {
5685 5357 : int iX = 0;
5686 10714 : for (int k = 0; k < nOuterLoops; k++)
5687 : {
5688 5357 : int iMax = iX + 65536;
5689 5357 : if (iMax > nXCheck)
5690 5357 : iMax = nXCheck;
5691 5357 : GUInt32 nSum32bit = 0;
5692 5357 : GUInt32 nSumSquare32bit = 0;
5693 285321 : for (; iX + 1 < iMax; iX += 2)
5694 : {
5695 279964 : const GPtrDiff_t iOffset =
5696 279964 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5697 279964 : const GUInt32 nValue = pData[iOffset];
5698 279964 : const GUInt32 nValue2 = pData[iOffset + 1];
5699 279964 : if (nValue < nValue2)
5700 : {
5701 8151 : if (nValue < nMin)
5702 235 : nMin = nValue;
5703 8151 : if (nValue2 > nMax)
5704 226 : nMax = nValue2;
5705 : }
5706 : else
5707 : {
5708 271813 : if (nValue2 < nMin)
5709 364 : nMin = nValue2;
5710 271813 : if (nValue > nMax)
5711 837 : nMax = nValue;
5712 : }
5713 : if constexpr (COMPUTE_OTHER_STATS)
5714 : {
5715 257626 : nSum32bit += nValue;
5716 257626 : nSumSquare32bit += nValue * nValue;
5717 257626 : nSum32bit += nValue2;
5718 257626 : nSumSquare32bit += nValue2 * nValue2;
5719 : }
5720 : }
5721 : if constexpr (COMPUTE_OTHER_STATS)
5722 : {
5723 2150 : nSum += nSum32bit;
5724 2150 : nSumSquare += nSumSquare32bit;
5725 : }
5726 : }
5727 5357 : if (iX < nXCheck)
5728 : {
5729 1532 : const GPtrDiff_t iOffset =
5730 1532 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5731 1532 : const GUInt32 nValue = pData[iOffset];
5732 1532 : if (nValue < nMin)
5733 117 : nMin = nValue;
5734 1532 : if (nValue > nMax)
5735 101 : nMax = nValue;
5736 : if constexpr (COMPUTE_OTHER_STATS)
5737 : {
5738 321 : nSum += nValue;
5739 321 : nSumSquare +=
5740 321 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5741 321 : nValue;
5742 : }
5743 : }
5744 : }
5745 : if constexpr (COMPUTE_OTHER_STATS)
5746 : {
5747 936 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5748 936 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5749 : }
5750 : }
5751 13781 : }
5752 : };
5753 :
5754 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5755 : {
5756 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5757 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5758 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5759 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5760 : {
5761 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5762 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5763 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5764 : }
5765 : };
5766 :
5767 : #if (defined(__x86_64__) || defined(_M_X64) || \
5768 : defined(USE_NEON_OPTIMIZATIONS)) && \
5769 : (defined(__GNUC__) || defined(_MSC_VER))
5770 :
5771 : #include "gdal_avx2_emulation.hpp"
5772 :
5773 : #define ZERO256 GDALmm256_setzero_si256()
5774 :
5775 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5776 : static void
5777 21346 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5778 : // assumed to be aligned on 256 bits
5779 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5780 : GUIntBig &nSum, GUIntBig &nSumSquare,
5781 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5782 : {
5783 : // 32-byte alignment may not be enforced by linker, so do it at hand
5784 : GByte
5785 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5786 21346 : GByte *paby32ByteAligned =
5787 : aby32ByteUnaligned +
5788 21346 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5789 21346 : GByte *pabyMin = paby32ByteAligned;
5790 21346 : GByte *pabyMax = paby32ByteAligned + 32;
5791 21346 : GUInt32 *panSum =
5792 : COMPUTE_OTHER_STATS
5793 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5794 : : nullptr;
5795 21346 : GUInt32 *panSumSquare =
5796 : COMPUTE_OTHER_STATS
5797 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5798 : : nullptr;
5799 :
5800 21346 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5801 :
5802 21346 : GPtrDiff_t i = 0;
5803 : // Make sure that sumSquare can fit on uint32
5804 : // * 8 since we can hold 8 sums per vector register
5805 21346 : const int nMaxIterationsPerInnerLoop =
5806 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5807 21346 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5808 21346 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5809 21346 : nOuterLoops++;
5810 :
5811 : GDALm256i ymm_min =
5812 21346 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5813 21346 : GDALm256i ymm_max = ymm_min;
5814 21346 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5815 :
5816 42692 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5817 : {
5818 21346 : const auto iMax =
5819 21346 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5820 :
5821 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5822 21346 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5823 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5824 21346 : ZERO256; // holds 8 uint32 sums
5825 724785 : for (; i + 31 < iMax; i += 32)
5826 : {
5827 703439 : const GDALm256i ymm = GDALmm256_load_si256(
5828 703439 : reinterpret_cast<const GDALm256i *>(pData + i));
5829 : if (COMPUTE_MIN)
5830 : {
5831 243330 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5832 : }
5833 : if (COMPUTE_MAX)
5834 : {
5835 612140 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5836 : }
5837 :
5838 : if constexpr (COMPUTE_OTHER_STATS)
5839 : {
5840 : // Extract even-8bit values
5841 : const GDALm256i ymm_even =
5842 504167 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5843 : // Compute square of those 16 values as 32 bit result
5844 : // and add adjacent pairs
5845 : const GDALm256i ymm_even_square =
5846 504167 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5847 : // Add to the sumsquare accumulator
5848 : ymm_sumsquare =
5849 504167 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5850 :
5851 : // Extract odd-8bit values
5852 504167 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5853 : const GDALm256i ymm_odd_square =
5854 504167 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5855 : ymm_sumsquare =
5856 504167 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5857 :
5858 : // Now compute the sums
5859 504167 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5860 : GDALmm256_sad_epu8(ymm, ZERO256));
5861 : }
5862 : }
5863 :
5864 : if constexpr (COMPUTE_OTHER_STATS)
5865 : {
5866 10677 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5867 : ymm_sum);
5868 10677 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5869 : ymm_sumsquare);
5870 :
5871 10677 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5872 10677 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5873 10677 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5874 10677 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5875 : panSumSquare[7];
5876 : }
5877 : }
5878 :
5879 : if constexpr (COMPUTE_MIN)
5880 : {
5881 8449 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5882 : }
5883 : if constexpr (COMPUTE_MAX)
5884 : {
5885 17334 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5886 : }
5887 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5888 : {
5889 589281 : for (int j = 0; j < 32; j++)
5890 : {
5891 : if constexpr (COMPUTE_MIN)
5892 : {
5893 270368 : if (pabyMin[j] < nMin)
5894 1236 : nMin = pabyMin[j];
5895 : }
5896 : if constexpr (COMPUTE_MAX)
5897 : {
5898 554688 : if (pabyMax[j] > nMax)
5899 1799 : nMax = pabyMax[j];
5900 : }
5901 : }
5902 : }
5903 :
5904 234348 : for (; i < nBlockPixels; i++)
5905 : {
5906 213002 : const GUInt32 nValue = pData[i];
5907 : if constexpr (COMPUTE_MIN)
5908 : {
5909 88326 : if (nValue < nMin)
5910 2 : nMin = nValue;
5911 : }
5912 : if constexpr (COMPUTE_MAX)
5913 : {
5914 210227 : if (nValue > nMax)
5915 1150 : nMax = nValue;
5916 : }
5917 : if constexpr (COMPUTE_OTHER_STATS)
5918 : {
5919 77203 : nSum += nValue;
5920 77203 : nSumSquare +=
5921 77203 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5922 : }
5923 : }
5924 :
5925 : if constexpr (COMPUTE_OTHER_STATS)
5926 : {
5927 10677 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5928 10677 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5929 : }
5930 21346 : }
5931 :
5932 : // SSE2/AVX2 optimization for GByte case
5933 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5934 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5935 : // there are strictly equivalent to 2 parallel SSE2 streams.
5936 : template <bool COMPUTE_OTHER_STATS>
5937 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5938 : {
5939 30296 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5940 : // assumed to be aligned on 256 bits
5941 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5942 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5943 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5944 : GUIntBig &nValidCount)
5945 : {
5946 30296 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5947 30296 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5948 11610 : nMin <= nMax)
5949 : {
5950 : // 32-byte alignment may not be enforced by linker, so do it at hand
5951 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5952 1492 : GByte *paby32ByteAligned =
5953 : aby32ByteUnaligned +
5954 1492 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5955 1492 : GByte *pabyMin = paby32ByteAligned;
5956 1492 : GByte *pabyMax = paby32ByteAligned + 32;
5957 1492 : GUInt32 *panSum =
5958 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5959 1492 : GUInt32 *panSumSquare =
5960 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5961 :
5962 1492 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5963 :
5964 1492 : GPtrDiff_t i = 0;
5965 : // Make sure that sumSquare can fit on uint32
5966 : // * 8 since we can hold 8 sums per vector register
5967 1492 : const int nMaxIterationsPerInnerLoop =
5968 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5969 1492 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5970 1492 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5971 1492 : nOuterLoops++;
5972 :
5973 : const GDALm256i ymm_nodata =
5974 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5975 : // any non noData value in [min,max] would do.
5976 : const GDALm256i ymm_neutral =
5977 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5978 1492 : GDALm256i ymm_min = ymm_neutral;
5979 1492 : GDALm256i ymm_max = ymm_neutral;
5980 : [[maybe_unused]] const auto ymm_mask_8bits =
5981 1492 : GDALmm256_set1_epi16(0xFF);
5982 :
5983 1492 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5984 1492 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5985 1492 : const bool bComputeMinMax =
5986 1492 : nMin > nMinThreshold || nMax < nMaxThreshold;
5987 :
5988 2984 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5989 : {
5990 1492 : const auto iMax =
5991 1492 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5992 :
5993 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5994 1492 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5995 : // holds 8 uint32 sums
5996 1492 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5997 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5998 1492 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5999 1492 : const auto iInit = i;
6000 18982 : for (; i + 31 < iMax; i += 32)
6001 : {
6002 17490 : const GDALm256i ymm = GDALmm256_load_si256(
6003 17490 : reinterpret_cast<const GDALm256i *>(pData + i));
6004 :
6005 : // Check which values are nodata
6006 : const GDALm256i ymm_eq_nodata =
6007 17490 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6008 : if constexpr (COMPUTE_OTHER_STATS)
6009 : {
6010 : // Count how many values are nodata (due to cmpeq
6011 : // putting 255 when condition is met, this will actually
6012 : // be 255 times the number of nodata value, spread in 4
6013 : // 64 bits words). We can use add_epi32 as the counter
6014 : // will not overflow uint32
6015 9148 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6016 : ymm_count_nodata_mul_255,
6017 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6018 : }
6019 : // Replace all nodata values by zero for the purpose of sum
6020 : // and sumquare.
6021 : const GDALm256i ymm_nodata_by_zero =
6022 17490 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6023 17490 : if (bComputeMinMax)
6024 : {
6025 : // Replace all nodata values by a neutral value for the
6026 : // purpose of min and max.
6027 : const GDALm256i ymm_nodata_by_neutral =
6028 8720 : GDALmm256_or_si256(
6029 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6030 : ymm_nodata_by_zero);
6031 :
6032 : ymm_min =
6033 8720 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6034 : ymm_max =
6035 8720 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6036 : }
6037 :
6038 : if constexpr (COMPUTE_OTHER_STATS)
6039 : {
6040 : // Extract even-8bit values
6041 9148 : const GDALm256i ymm_even = GDALmm256_and_si256(
6042 : ymm_nodata_by_zero, ymm_mask_8bits);
6043 : // Compute square of those 16 values as 32 bit result
6044 : // and add adjacent pairs
6045 : const GDALm256i ymm_even_square =
6046 9148 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6047 : // Add to the sumsquare accumulator
6048 : ymm_sumsquare =
6049 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6050 :
6051 : // Extract odd-8bit values
6052 : const GDALm256i ymm_odd =
6053 9148 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6054 : const GDALm256i ymm_odd_square =
6055 9148 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6056 : ymm_sumsquare =
6057 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6058 :
6059 : // Now compute the sums
6060 9148 : ymm_sum = GDALmm256_add_epi32(
6061 : ymm_sum,
6062 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6063 : }
6064 : }
6065 :
6066 : if constexpr (COMPUTE_OTHER_STATS)
6067 : {
6068 186 : GUInt32 *panCoutNoDataMul255 = panSum;
6069 186 : GDALmm256_store_si256(
6070 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6071 : ymm_count_nodata_mul_255);
6072 :
6073 186 : nSampleCount += (i - iInit);
6074 :
6075 186 : nValidCount +=
6076 186 : (i - iInit) -
6077 186 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6078 186 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6079 : 255;
6080 :
6081 186 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6082 : ymm_sum);
6083 186 : GDALmm256_store_si256(
6084 : reinterpret_cast<GDALm256i *>(panSumSquare),
6085 : ymm_sumsquare);
6086 186 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6087 186 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6088 186 : panSumSquare[1] + panSumSquare[2] +
6089 186 : panSumSquare[3] + panSumSquare[4] +
6090 186 : panSumSquare[5] + panSumSquare[6] +
6091 : panSumSquare[7];
6092 : }
6093 : }
6094 :
6095 1492 : if (bComputeMinMax)
6096 : {
6097 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6098 : ymm_min);
6099 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6100 : ymm_max);
6101 47190 : for (int j = 0; j < 32; j++)
6102 : {
6103 45760 : if (pabyMin[j] < nMin)
6104 40 : nMin = pabyMin[j];
6105 45760 : if (pabyMax[j] > nMax)
6106 161 : nMax = pabyMax[j];
6107 : }
6108 : }
6109 :
6110 : if constexpr (COMPUTE_OTHER_STATS)
6111 : {
6112 186 : nSampleCount += nBlockPixels - i;
6113 : }
6114 34048 : for (; i < nBlockPixels; i++)
6115 : {
6116 32556 : const GUInt32 nValue = pData[i];
6117 32556 : if (nValue == nNoDataValue)
6118 24923 : continue;
6119 7633 : if (nValue < nMin)
6120 2 : nMin = nValue;
6121 7633 : if (nValue > nMax)
6122 14 : nMax = nValue;
6123 : if constexpr (COMPUTE_OTHER_STATS)
6124 : {
6125 3700 : nValidCount++;
6126 3700 : nSum += nValue;
6127 3700 : nSumSquare +=
6128 3700 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6129 3700 : nValue;
6130 : }
6131 1492 : }
6132 : }
6133 28804 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6134 : {
6135 14990 : if (nMin > 0)
6136 : {
6137 2093 : if (nMax < 255)
6138 : {
6139 : ComputeStatisticsByteNoNodata<true, true,
6140 1570 : COMPUTE_OTHER_STATS>(
6141 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6142 : nSampleCount, nValidCount);
6143 : }
6144 : else
6145 : {
6146 : ComputeStatisticsByteNoNodata<true, false,
6147 523 : COMPUTE_OTHER_STATS>(
6148 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6149 : nSampleCount, nValidCount);
6150 : }
6151 : }
6152 : else
6153 : {
6154 12897 : if (nMax < 255)
6155 : {
6156 : ComputeStatisticsByteNoNodata<false, true,
6157 9408 : COMPUTE_OTHER_STATS>(
6158 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6159 : nSampleCount, nValidCount);
6160 : }
6161 : else
6162 : {
6163 : ComputeStatisticsByteNoNodata<false, false,
6164 3489 : COMPUTE_OTHER_STATS>(
6165 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6166 : nSampleCount, nValidCount);
6167 : }
6168 : }
6169 : }
6170 12516 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6171 33 : (nBlockXSize % 32) == 0)
6172 : {
6173 6389 : for (int iY = 0; iY < nYCheck; iY++)
6174 : {
6175 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6176 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6177 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6178 33 : }
6179 : }
6180 : else
6181 : {
6182 13781 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6183 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6184 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6185 : }
6186 30296 : }
6187 : };
6188 :
6189 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6190 570 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6191 : GUIntBig i)
6192 : {
6193 570 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6194 570 : }
6195 :
6196 : // AVX2/SSE2 optimization for GUInt16 case
6197 : template <bool COMPUTE_OTHER_STATS>
6198 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6199 : {
6200 2099 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6201 : // assumed to be aligned on 128 bits
6202 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6203 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6204 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6205 : GUIntBig &nValidCount)
6206 : {
6207 2099 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6208 2099 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6209 : {
6210 1844 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6211 :
6212 1844 : GPtrDiff_t i = 0;
6213 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6214 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6215 : // Furthermore the shift is also needed to use madd_epi16
6216 1844 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6217 1844 : GDALm256i ymm_min = GDALmm256_load_si256(
6218 1844 : reinterpret_cast<const GDALm256i *>(pData + i));
6219 1844 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6220 1844 : GDALm256i ymm_max = ymm_min;
6221 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6222 1844 : ZERO256; // holds 4 uint64 sums
6223 :
6224 : // Make sure that sum can fit on uint32
6225 : // * 8 since we can hold 8 sums per vector register
6226 1844 : const int nMaxIterationsPerInnerLoop =
6227 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6228 1844 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6229 1844 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6230 1844 : nOuterLoops++;
6231 :
6232 1844 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6233 : [[maybe_unused]] const auto ymm_mask_16bits =
6234 1844 : GDALmm256_set1_epi32(0xFFFF);
6235 : [[maybe_unused]] const auto ymm_mask_32bits =
6236 1844 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6237 :
6238 1844 : GUIntBig nSumThis = 0;
6239 3712 : for (int k = 0; k < nOuterLoops; k++)
6240 : {
6241 1868 : const auto iMax =
6242 1868 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6243 :
6244 : [[maybe_unused]] GDALm256i ymm_sum =
6245 1868 : ZERO256; // holds 8 uint32 sums
6246 1057198 : for (; i + 15 < iMax; i += 16)
6247 : {
6248 1055330 : const GDALm256i ymm = GDALmm256_load_si256(
6249 1055330 : reinterpret_cast<const GDALm256i *>(pData + i));
6250 : const GDALm256i ymm_shifted =
6251 1055330 : GDALmm256_add_epi16(ymm, ymm_m32768);
6252 1055330 : if (bComputeMinMax)
6253 : {
6254 1037292 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6255 1037292 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6256 : }
6257 :
6258 : if constexpr (COMPUTE_OTHER_STATS)
6259 : {
6260 : // Note: the int32 range can overflow for (0-32768)^2 +
6261 : // (0-32768)^2 = 0x80000000, but as we know the result
6262 : // is positive, this is OK as we interpret is a uint32.
6263 : const GDALm256i ymm_square =
6264 188312 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6265 188312 : ymm_sumsquare = GDALmm256_add_epi64(
6266 : ymm_sumsquare,
6267 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6268 188312 : ymm_sumsquare = GDALmm256_add_epi64(
6269 : ymm_sumsquare,
6270 : GDALmm256_srli_epi64(ymm_square, 32));
6271 :
6272 : // Now compute the sums
6273 188312 : ymm_sum = GDALmm256_add_epi32(
6274 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6275 188312 : ymm_sum = GDALmm256_add_epi32(
6276 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6277 : }
6278 : }
6279 :
6280 : if constexpr (COMPUTE_OTHER_STATS)
6281 : {
6282 : GUInt32 anSum[8];
6283 570 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6284 : ymm_sum);
6285 570 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6286 570 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6287 570 : anSum[6] + anSum[7];
6288 : }
6289 : }
6290 :
6291 1844 : if (bComputeMinMax)
6292 : {
6293 : GUInt16 anMin[16];
6294 : GUInt16 anMax[16];
6295 :
6296 : // Unshift the result
6297 1762 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6298 1762 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6299 1762 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6300 : ymm_min);
6301 1762 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6302 : ymm_max);
6303 29954 : for (int j = 0; j < 16; j++)
6304 : {
6305 28192 : if (anMin[j] < nMin)
6306 389 : nMin = anMin[j];
6307 28192 : if (anMax[j] > nMax)
6308 567 : nMax = anMax[j];
6309 : }
6310 : }
6311 :
6312 : if constexpr (COMPUTE_OTHER_STATS)
6313 : {
6314 : GUIntBig anSumSquare[4];
6315 570 : GDALmm256_storeu_si256(
6316 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6317 570 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6318 : anSumSquare[3];
6319 :
6320 : // Unshift the sum of squares
6321 570 : UnshiftSumSquare(nSumSquare, nSumThis,
6322 : static_cast<GUIntBig>(i));
6323 :
6324 570 : nSum += nSumThis;
6325 :
6326 1014 : for (; i < nBlockPixels; i++)
6327 : {
6328 444 : const GUInt32 nValue = pData[i];
6329 444 : if (nValue < nMin)
6330 2 : nMin = nValue;
6331 444 : if (nValue > nMax)
6332 2 : nMax = nValue;
6333 444 : nSum += nValue;
6334 444 : nSumSquare +=
6335 444 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6336 444 : nValue;
6337 : }
6338 :
6339 570 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6340 570 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6341 1844 : }
6342 : }
6343 : else
6344 : {
6345 255 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6346 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6347 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6348 : }
6349 2099 : }
6350 : };
6351 :
6352 : #endif
6353 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6354 : // defined(_MSC_VER))
6355 :
6356 : /************************************************************************/
6357 : /* GetPixelValue() */
6358 : /************************************************************************/
6359 :
6360 15872100 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6361 : const void *pData, GPtrDiff_t iOffset,
6362 : const GDALNoDataValues &sNoDataValues,
6363 : bool &bValid)
6364 : {
6365 15872100 : bValid = true;
6366 15872100 : double dfValue = 0;
6367 15872100 : switch (eDataType)
6368 : {
6369 1400770 : case GDT_UInt8:
6370 : {
6371 1400770 : if (bSignedByte)
6372 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6373 : else
6374 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6375 1400770 : break;
6376 : }
6377 641 : case GDT_Int8:
6378 641 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6379 641 : break;
6380 200608 : case GDT_UInt16:
6381 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6382 200608 : break;
6383 54248 : case GDT_Int16:
6384 54248 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6385 54248 : break;
6386 10478 : case GDT_UInt32:
6387 10478 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6388 10478 : break;
6389 140132 : case GDT_Int32:
6390 140132 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6391 140132 : break;
6392 60 : case GDT_UInt64:
6393 60 : dfValue = static_cast<double>(
6394 60 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6395 60 : break;
6396 3268 : case GDT_Int64:
6397 3268 : dfValue = static_cast<double>(
6398 3268 : static_cast<const std::int64_t *>(pData)[iOffset]);
6399 3268 : break;
6400 40 : case GDT_Float16:
6401 : {
6402 : using namespace std;
6403 40 : const GFloat16 hfValue =
6404 40 : static_cast<const GFloat16 *>(pData)[iOffset];
6405 74 : if (isnan(hfValue) ||
6406 34 : (sNoDataValues.bGotFloat16NoDataValue &&
6407 28 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6408 : {
6409 6 : bValid = false;
6410 6 : return 0.0;
6411 : }
6412 34 : dfValue = hfValue;
6413 34 : return dfValue;
6414 : }
6415 13643900 : case GDT_Float32:
6416 : {
6417 13643900 : const float fValue = static_cast<const float *>(pData)[iOffset];
6418 27260900 : if (std::isnan(fValue) ||
6419 26885800 : (sNoDataValues.bGotFloatNoDataValue &&
6420 13268800 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6421 : {
6422 26883 : bValid = false;
6423 26883 : return 0.0;
6424 : }
6425 13617000 : dfValue = double(fValue);
6426 13617000 : return dfValue;
6427 : }
6428 400868 : case GDT_Float64:
6429 400868 : dfValue = static_cast<const double *>(pData)[iOffset];
6430 400868 : if (std::isnan(dfValue))
6431 : {
6432 6 : bValid = false;
6433 6 : return 0.0;
6434 : }
6435 400862 : break;
6436 2692 : case GDT_CInt16:
6437 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6438 2692 : break;
6439 2692 : case GDT_CInt32:
6440 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6441 2692 : break;
6442 0 : case GDT_CFloat16:
6443 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6444 0 : if (std::isnan(dfValue))
6445 : {
6446 0 : bValid = false;
6447 0 : return 0.0;
6448 : }
6449 0 : break;
6450 5812 : case GDT_CFloat32:
6451 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6452 5812 : if (std::isnan(dfValue))
6453 : {
6454 0 : bValid = false;
6455 0 : return 0.0;
6456 : }
6457 5812 : break;
6458 5892 : case GDT_CFloat64:
6459 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6460 5892 : if (std::isnan(dfValue))
6461 : {
6462 0 : bValid = false;
6463 0 : return 0.0;
6464 : }
6465 5892 : break;
6466 0 : case GDT_Unknown:
6467 : case GDT_TypeCount:
6468 0 : CPLAssert(false);
6469 : break;
6470 : }
6471 :
6472 2483320 : if (sNoDataValues.bGotNoDataValue &&
6473 255165 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6474 : {
6475 4222 : bValid = false;
6476 4222 : return 0.0;
6477 : }
6478 2223930 : return dfValue;
6479 : }
6480 :
6481 : /************************************************************************/
6482 : /* SetValidPercent() */
6483 : /************************************************************************/
6484 :
6485 : //! @cond Doxygen_Suppress
6486 : /**
6487 : * \brief Set percentage of valid (not nodata) pixels.
6488 : *
6489 : * Stores the percentage of valid pixels in the metadata item
6490 : * STATISTICS_VALID_PERCENT
6491 : *
6492 : * @param nSampleCount Number of sampled pixels.
6493 : *
6494 : * @param nValidCount Number of valid pixels.
6495 : */
6496 :
6497 595 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6498 : GUIntBig nValidCount)
6499 : {
6500 595 : if (nValidCount == 0)
6501 : {
6502 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6503 : }
6504 583 : else if (nValidCount == nSampleCount)
6505 : {
6506 491 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6507 : }
6508 : else /* nValidCount < nSampleCount */
6509 : {
6510 92 : char szValue[128] = {0};
6511 :
6512 : /* percentage is only an indicator: limit precision */
6513 92 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6514 92 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6515 :
6516 92 : if (EQUAL(szValue, "100"))
6517 : {
6518 : /* don't set 100 percent valid
6519 : * because some of the sampled pixels were nodata */
6520 4 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6521 : }
6522 : else
6523 : {
6524 88 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6525 : }
6526 : }
6527 595 : }
6528 :
6529 : //! @endcond
6530 :
6531 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6532 :
6533 : #ifdef __AVX2__
6534 :
6535 : #define set1_ps _mm256_set1_ps
6536 : #define loadu_ps _mm256_loadu_ps
6537 : #define or_ps _mm256_or_ps
6538 : #define min_ps _mm256_min_ps
6539 : #define max_ps _mm256_max_ps
6540 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6541 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6542 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6543 : #define movemask_ps _mm256_movemask_ps
6544 : #define storeu_ps _mm256_storeu_ps
6545 : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6546 : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6547 :
6548 : #define unpacklo_ps _mm256_unpacklo_ps
6549 : #define castps_pd _mm256_castps_pd
6550 :
6551 : inline __m256 dup_hi_ps(__m256 x)
6552 : {
6553 : const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6554 : return _mm256_permutevar8x32_ps(x, idx);
6555 : }
6556 :
6557 : #define setzero_pd _mm256_setzero_pd
6558 : #define set1_pd _mm256_set1_pd
6559 : #define loadu_pd _mm256_loadu_pd
6560 : #define or_pd _mm256_or_pd
6561 : #define min_pd _mm256_min_pd
6562 : #define max_pd _mm256_max_pd
6563 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6564 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6565 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6566 : #define movemask_pd _mm256_movemask_pd
6567 : #define add_pd _mm256_add_pd
6568 : #define sub_pd _mm256_sub_pd
6569 : #define mul_pd _mm256_mul_pd
6570 : #define div_pd _mm256_div_pd
6571 : #define storeu_pd _mm256_storeu_pd
6572 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6573 : #define blendv_pd _mm256_blendv_pd
6574 : #ifdef __FMA__
6575 : #define fmadd_pd _mm256_fmadd_pd
6576 : #else
6577 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6578 : #endif
6579 :
6580 : #else
6581 :
6582 : #define set1_ps _mm_set1_ps
6583 : #define loadu_ps _mm_loadu_ps
6584 : #define or_ps _mm_or_ps
6585 : #define min_ps _mm_min_ps
6586 : #define max_ps _mm_max_ps
6587 : #define cmpeq_ps _mm_cmpeq_ps
6588 : #define cmpneq_ps _mm_cmpneq_ps
6589 : #define cmpunord_ps _mm_cmpunord_ps
6590 : #define movemask_ps _mm_movemask_ps
6591 : #define storeu_ps _mm_storeu_ps
6592 : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6593 : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6594 : #define unpacklo_ps _mm_unpacklo_ps
6595 : #define castps_pd _mm_castps_pd
6596 : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6597 :
6598 : #define setzero_pd _mm_setzero_pd
6599 : #define set1_pd _mm_set1_pd
6600 : #define loadu_pd _mm_loadu_pd
6601 : #define or_pd _mm_or_pd
6602 : #define min_pd _mm_min_pd
6603 : #define max_pd _mm_max_pd
6604 : #define cmpeq_pd _mm_cmpeq_pd
6605 : #define cmpneq_pd _mm_cmpneq_pd
6606 : #define cmpunord_pd _mm_cmpunord_pd
6607 : #define movemask_pd _mm_movemask_pd
6608 : #define add_pd _mm_add_pd
6609 : #define sub_pd _mm_sub_pd
6610 : #define mul_pd _mm_mul_pd
6611 : #define div_pd _mm_div_pd
6612 : #define storeu_pd _mm_storeu_pd
6613 : #define cvtsd_f64 _mm_cvtsd_f64
6614 : #ifdef __FMA__
6615 : #define fmadd_pd _mm_fmadd_pd
6616 : #else
6617 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6618 : #endif
6619 :
6620 4299340 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6621 : {
6622 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6623 : return _mm_blendv_pd(a, b, mask);
6624 : #else
6625 12898000 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6626 : #endif
6627 : }
6628 : #endif
6629 :
6630 : #define dup_lo_ps(x) unpacklo_ps((x), (x))
6631 :
6632 : /************************************************************************/
6633 : /* ComputeStatisticsFloat32_SSE2() */
6634 : /************************************************************************/
6635 :
6636 : template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6637 : #if defined(__GNUC__)
6638 : __attribute__((noinline))
6639 : #endif
6640 : static int
6641 8330 : ComputeStatisticsFloat32_SSE2(const float *const pafData,
6642 : [[maybe_unused]] float fNoDataValue, int iX,
6643 : int nCount, float &fMin, float &fMax,
6644 : double &dfBlockMean, double &dfBlockM2,
6645 : double &dfBlockValidCount)
6646 : {
6647 8330 : auto vValidCount = setzero_pd();
6648 8330 : const auto vOne = set1_pd(1);
6649 8330 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6650 :
6651 8330 : auto vMin = set1_ps(fMin);
6652 16660 : auto vMax = set1_ps(fMax);
6653 :
6654 8330 : auto vMean_lo = setzero_pd();
6655 8330 : auto vM2_lo = setzero_pd();
6656 :
6657 8330 : auto vMean_hi = setzero_pd();
6658 8330 : auto vM2_hi = setzero_pd();
6659 :
6660 8330 : constexpr int VALS_PER_LOOP =
6661 : static_cast<int>(sizeof(vOne) / sizeof(float));
6662 1258087 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6663 : {
6664 2499510 : const auto vValues = loadu_ps(pafData + iX);
6665 :
6666 : if constexpr (HAS_NAN)
6667 : {
6668 1236117 : auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6669 : if constexpr (HAS_NODATA)
6670 : {
6671 : isNaNOrNoData =
6672 0 : or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6673 : }
6674 1236117 : if (movemask_ps(isNaNOrNoData))
6675 : {
6676 1 : break;
6677 : }
6678 : }
6679 : else if constexpr (HAS_NODATA)
6680 : {
6681 0 : if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6682 : {
6683 0 : break;
6684 : }
6685 : }
6686 :
6687 1249754 : vMin = min_ps(vMin, vValues);
6688 1249754 : vMax = max_ps(vMax, vValues);
6689 :
6690 1249754 : const auto vValues_lo = cvtps_lo_pd(vValues);
6691 2499508 : const auto vValues_hi = cvtps_hi_pd(vValues);
6692 1249754 : [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6693 :
6694 1249754 : vValidCount = add_pd(vValidCount, vOne);
6695 1249754 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6696 :
6697 1249754 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6698 2298362 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6699 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6700 : {
6701 : const auto vMinNotSameAsMax_lo =
6702 1048608 : castps_pd(dup_lo_ps(vMinNotSameAsMax));
6703 1048608 : vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6704 : const auto vNewM2_lo =
6705 2097216 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6706 1048608 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6707 : }
6708 : else
6709 : {
6710 201146 : vMean_lo = vNewMean_lo;
6711 603438 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6712 : }
6713 :
6714 1249754 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6715 2298362 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6716 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6717 : {
6718 : const auto vMinNotSameAsMax_hi =
6719 1048608 : castps_pd(dup_hi_ps(vMinNotSameAsMax));
6720 1048608 : vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6721 : const auto vNewM2_hi =
6722 2097216 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6723 1048608 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6724 : }
6725 : else
6726 : {
6727 201146 : vMean_hi = vNewMean_hi;
6728 603438 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6729 : }
6730 : }
6731 8330 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6732 8330 : if (dfValidVectorCount > 0)
6733 : {
6734 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6735 : storeu_ps(afMin, vMin);
6736 : storeu_ps(afMax, vMax);
6737 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6738 : {
6739 31964 : fMin = std::min(fMin, afMin[i]);
6740 31964 : fMax = std::max(fMax, afMax[i]);
6741 : }
6742 :
6743 : double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6744 : storeu_pd(adfMean, vMean_lo);
6745 : storeu_pd(adfM2, vM2_lo);
6746 7991 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6747 7991 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6748 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6749 : {
6750 31964 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6751 31964 : dfBlockM2 += adfM2[i];
6752 31964 : if (adfMean[i] != dfBlockMean)
6753 : {
6754 13172 : const double dfDelta = adfMean[i] - dfBlockMean;
6755 13172 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6756 13172 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6757 13172 : dfValidVectorCount / dfNewValidCount;
6758 : }
6759 31964 : dfBlockValidCount = dfNewValidCount;
6760 : }
6761 : }
6762 :
6763 8330 : return iX;
6764 : }
6765 :
6766 : /************************************************************************/
6767 : /* ComputeStatisticsFloat64_SSE2() */
6768 : /************************************************************************/
6769 :
6770 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6771 : #if defined(__GNUC__)
6772 : __attribute__((noinline))
6773 : #endif
6774 : static int
6775 2367 : ComputeStatisticsFloat64_SSE2(const double *padfData,
6776 : [[maybe_unused]] double dfNoDataValue, int iX,
6777 : int nCount, double &dfMin, double &dfMax,
6778 : double &dfBlockMean, double &dfBlockM2,
6779 : double &dfBlockValidCount)
6780 : {
6781 2367 : auto vValidCount = setzero_pd();
6782 2367 : const auto vOne = set1_pd(1);
6783 2367 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6784 :
6785 2367 : auto vMin_lo = set1_pd(dfMin);
6786 4734 : auto vMax_lo = set1_pd(dfMax);
6787 2367 : auto vMean_lo = setzero_pd();
6788 2367 : auto vM2_lo = setzero_pd();
6789 :
6790 2367 : auto vMin_hi = vMin_lo;
6791 2367 : auto vMax_hi = vMax_lo;
6792 2367 : auto vMean_hi = setzero_pd();
6793 2367 : auto vM2_hi = setzero_pd();
6794 :
6795 2367 : constexpr int VALS_PER_LOOP =
6796 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6797 107199 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6798 : {
6799 104875 : const auto vValues_lo = loadu_pd(padfData + iX);
6800 209750 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6801 : // Check if there's at least one NaN in both vectors
6802 104875 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6803 : if constexpr (HAS_NODATA)
6804 : {
6805 : isNaNOrNoData =
6806 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6807 : cmpeq_pd(vValues_hi, vNoData)));
6808 : }
6809 104875 : if (movemask_pd(isNaNOrNoData))
6810 : {
6811 43 : break;
6812 : }
6813 :
6814 104832 : vValidCount = add_pd(vValidCount, vOne);
6815 104832 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6816 :
6817 104832 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6818 104832 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6819 104832 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6820 131060 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6821 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6822 : {
6823 26228 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6824 26228 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6825 : const auto vNewM2_lo =
6826 52456 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6827 26228 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6828 : }
6829 : else
6830 : {
6831 78604 : vMean_lo = vNewMean_lo;
6832 235812 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6833 : }
6834 :
6835 104832 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6836 104832 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6837 104832 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6838 131060 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6839 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6840 : {
6841 26228 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6842 26228 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6843 : const auto vNewM2_hi =
6844 52456 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6845 26228 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6846 : }
6847 : else
6848 : {
6849 78604 : vMean_hi = vNewMean_hi;
6850 235812 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6851 : }
6852 : }
6853 2367 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6854 2367 : if (dfValidVectorCount > 0)
6855 : {
6856 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6857 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6858 : storeu_pd(adfMin, vMin_lo);
6859 : storeu_pd(adfMax, vMax_lo);
6860 : storeu_pd(adfMean, vMean_lo);
6861 : storeu_pd(adfM2, vM2_lo);
6862 1801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6863 1801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6864 1801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6865 1801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6866 :
6867 9005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6868 : {
6869 7204 : dfMin = std::min(dfMin, adfMin[i]);
6870 7204 : dfMax = std::max(dfMax, adfMax[i]);
6871 7204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6872 7204 : dfBlockM2 += adfM2[i];
6873 7204 : if (adfMean[i] != dfBlockMean)
6874 : {
6875 5871 : const double dfDelta = adfMean[i] - dfBlockMean;
6876 5871 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6877 5871 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6878 5871 : dfValidVectorCount / dfNewValidCount;
6879 : }
6880 7204 : dfBlockValidCount = dfNewValidCount;
6881 : }
6882 : }
6883 :
6884 2367 : return iX;
6885 : }
6886 :
6887 : #endif
6888 :
6889 : /************************************************************************/
6890 : /* ComputeBlockStatisticsFloat32() */
6891 : /************************************************************************/
6892 :
6893 : template <bool HAS_NAN, bool HAS_NODATA>
6894 4733 : static void ComputeBlockStatisticsFloat32(
6895 : const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6896 : const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6897 : float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6898 : double &dfBlockValidCountInOut)
6899 : {
6900 4733 : float fMin = fMinInOut;
6901 4733 : float fMax = fMaxInOut;
6902 4733 : double dfBlockMean = dfBlockMeanInOut;
6903 4733 : double dfBlockM2 = dfBlockM2InOut;
6904 4733 : double dfBlockValidCount = dfBlockValidCountInOut;
6905 :
6906 13063 : for (int iY = 0; iY < nYCheck; iY++)
6907 : {
6908 8330 : const int iOffset = iY * nBlockXSize;
6909 8330 : if (dfBlockValidCount > 0 && fMin != fMax)
6910 : {
6911 3470 : int iX = 0;
6912 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6913 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6914 : /* bCheckMinEqMax = */ false,
6915 3470 : HAS_NODATA>(
6916 3470 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6917 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6918 : #endif
6919 4011 : for (; iX < nXCheck; iX++)
6920 : {
6921 541 : const float fValue = pafSrcData[iOffset + iX];
6922 : if constexpr (HAS_NAN)
6923 : {
6924 535 : if (std::isnan(fValue))
6925 13 : continue;
6926 : }
6927 : if constexpr (HAS_NODATA)
6928 : {
6929 6 : if (fValue == sNoDataValues.fNoDataValue)
6930 1 : continue;
6931 : }
6932 527 : fMin = std::min(fMin, fValue);
6933 527 : fMax = std::max(fMax, fValue);
6934 527 : dfBlockValidCount += 1.0;
6935 527 : const double dfValue = static_cast<double>(fValue);
6936 527 : const double dfDelta = dfValue - dfBlockMean;
6937 527 : dfBlockMean += dfDelta / dfBlockValidCount;
6938 527 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6939 3470 : }
6940 : }
6941 : else
6942 : {
6943 4860 : int iX = 0;
6944 4860 : if (dfBlockValidCount == 0)
6945 : {
6946 4734 : while (iX < nXCheck)
6947 : {
6948 4734 : const float fValue = pafSrcData[iOffset + iX];
6949 4734 : ++iX;
6950 : if constexpr (HAS_NAN)
6951 : {
6952 2340 : if (std::isnan(fValue))
6953 0 : continue;
6954 : }
6955 : if constexpr (HAS_NODATA)
6956 : {
6957 9 : if (fValue == sNoDataValues.fNoDataValue)
6958 1 : continue;
6959 : }
6960 4733 : fMin = std::min(fMin, fValue);
6961 4733 : fMax = std::max(fMax, fValue);
6962 4733 : dfBlockValidCount = 1;
6963 4733 : dfBlockMean = static_cast<double>(fValue);
6964 4733 : break;
6965 : }
6966 : }
6967 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6968 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6969 : /* bCheckMinEqMax = */ true,
6970 4860 : HAS_NODATA>(
6971 4860 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6972 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6973 : #endif
6974 14998 : for (; iX < nXCheck; iX++)
6975 : {
6976 10138 : const float fValue = pafSrcData[iOffset + iX];
6977 : if constexpr (HAS_NAN)
6978 : {
6979 6877 : if (std::isnan(fValue))
6980 7 : continue;
6981 : }
6982 : if constexpr (HAS_NODATA)
6983 : {
6984 13 : if (fValue == sNoDataValues.fNoDataValue)
6985 3 : continue;
6986 : }
6987 10128 : fMin = std::min(fMin, fValue);
6988 10128 : fMax = std::max(fMax, fValue);
6989 10128 : dfBlockValidCount += 1.0;
6990 10128 : if (fMin != fMax)
6991 : {
6992 3263 : const double dfValue = static_cast<double>(fValue);
6993 3263 : const double dfDelta = dfValue - dfBlockMean;
6994 3263 : dfBlockMean += dfDelta / dfBlockValidCount;
6995 3263 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6996 : }
6997 : }
6998 : }
6999 : }
7000 :
7001 4733 : fMinInOut = fMin;
7002 4733 : fMaxInOut = fMax;
7003 4733 : dfBlockMeanInOut = dfBlockMean;
7004 4733 : dfBlockM2InOut = dfBlockM2;
7005 4733 : dfBlockValidCountInOut = dfBlockValidCount;
7006 4733 : }
7007 :
7008 : /************************************************************************/
7009 : /* StatisticsTaskFloat32 */
7010 : /************************************************************************/
7011 :
7012 : namespace
7013 : {
7014 : struct StatisticsTaskFloat32
7015 : {
7016 : double dfBlockMean = 0;
7017 : double dfBlockM2 = 0;
7018 : double dfBlockValidCount = 0;
7019 : GDALDataType eDataType = GDT_Unknown;
7020 : bool bHasNoData = false;
7021 : GDALNoDataValues *psNoDataValues = nullptr;
7022 : const float *pafSrcData = nullptr;
7023 : float fMin = std::numeric_limits<float>::infinity();
7024 : float fMax = -std::numeric_limits<float>::infinity();
7025 : int nChunkXSize = 0;
7026 : int nXCheck = 0;
7027 : int nYCheck = 0;
7028 :
7029 4733 : void Perform()
7030 : {
7031 4733 : if (GDALDataTypeIsInteger(eDataType))
7032 : {
7033 2393 : if (bHasNoData)
7034 : {
7035 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7036 8 : /* HAS_NODATA = */ true>(
7037 8 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7038 8 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7039 : }
7040 : else
7041 : {
7042 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7043 2385 : /* HAS_NODATA = */ false>(
7044 2385 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7045 2385 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7046 : }
7047 : }
7048 : else
7049 : {
7050 2340 : if (bHasNoData)
7051 : {
7052 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7053 0 : /* HAS_NODATA = */ true>(
7054 0 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7055 0 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7056 : }
7057 : else
7058 : {
7059 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7060 2340 : /* HAS_NODATA = */ false>(
7061 2340 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7062 2340 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7063 : }
7064 : }
7065 4733 : }
7066 : };
7067 : } // namespace
7068 :
7069 : /************************************************************************/
7070 : /* ComputeStatistics() */
7071 : /************************************************************************/
7072 :
7073 : /**
7074 : * \brief Compute image statistics.
7075 : *
7076 : * Returns the minimum, maximum, mean and standard deviation of all
7077 : * pixel values in this band. If approximate statistics are sufficient,
7078 : * the bApproxOK flag can be set to true in which case overviews, or a
7079 : * subset of image tiles may be used in computing the statistics.
7080 : *
7081 : * Once computed, the statistics will generally be "set" back on the
7082 : * raster band using SetStatistics().
7083 : *
7084 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7085 : *
7086 : * This method is the same as the C function GDALComputeRasterStatistics().
7087 : *
7088 : * @param bApproxOK If TRUE statistics may be computed based on overviews
7089 : * or a subset of all tiles.
7090 : *
7091 : * @param pdfMin Location into which to load image minimum (may be NULL).
7092 : *
7093 : * @param pdfMax Location into which to load image maximum (may be NULL).-
7094 : *
7095 : * @param pdfMean Location into which to load image mean (may be NULL).
7096 : *
7097 : * @param pdfStdDev Location into which to load image standard deviation
7098 : * (may be NULL).
7099 : *
7100 : * @param pfnProgress a function to call to report progress, or NULL.
7101 : *
7102 : * @param pProgressData application data to pass to the progress function.
7103 : *
7104 : * @return CE_None on success, or CE_Failure if an error occurs or processing
7105 : * is terminated by the user.
7106 : */
7107 :
7108 573 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7109 : double *pdfMax, double *pdfMean,
7110 : double *pdfStdDev,
7111 : GDALProgressFunc pfnProgress,
7112 : void *pProgressData)
7113 :
7114 : {
7115 573 : if (pfnProgress == nullptr)
7116 244 : pfnProgress = GDALDummyProgress;
7117 :
7118 : /* -------------------------------------------------------------------- */
7119 : /* If we have overview bands, use them for statistics. */
7120 : /* -------------------------------------------------------------------- */
7121 573 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7122 : {
7123 : GDALRasterBand *poBand =
7124 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7125 :
7126 3 : if (poBand != this)
7127 : {
7128 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
7129 : pdfMean, pdfStdDev,
7130 3 : pfnProgress, pProgressData);
7131 3 : if (eErr == CE_None)
7132 : {
7133 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7134 : {
7135 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7136 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7137 : }
7138 :
7139 : /* transfer metadata from overview band to this */
7140 : const char *pszPercentValid =
7141 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7142 :
7143 3 : if (pszPercentValid != nullptr)
7144 : {
7145 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
7146 3 : pszPercentValid);
7147 : }
7148 : }
7149 3 : return eErr;
7150 : }
7151 : }
7152 :
7153 570 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7154 : {
7155 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7156 0 : return CE_Failure;
7157 : }
7158 :
7159 : /* -------------------------------------------------------------------- */
7160 : /* Read actual data and compute statistics. */
7161 : /* -------------------------------------------------------------------- */
7162 : // Using Welford algorithm:
7163 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7164 : // to compute standard deviation in a more numerically robust way than
7165 : // the difference of the sum of square values with the square of the sum.
7166 : // dfMean and dfM2 are updated at each sample.
7167 : // dfM2 is the sum of square of differences to the current mean.
7168 570 : double dfMin = std::numeric_limits<double>::infinity();
7169 570 : double dfMax = -std::numeric_limits<double>::infinity();
7170 570 : double dfMean = 0.0;
7171 570 : double dfM2 = 0.0;
7172 :
7173 : GDALRasterIOExtraArg sExtraArg;
7174 570 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7175 :
7176 570 : GDALNoDataValues sNoDataValues(this, eDataType);
7177 570 : GDALRasterBand *poMaskBand = nullptr;
7178 570 : if (!sNoDataValues.bGotNoDataValue)
7179 : {
7180 499 : const int l_nMaskFlags = GetMaskFlags();
7181 557 : if (l_nMaskFlags != GMF_ALL_VALID &&
7182 58 : GetColorInterpretation() != GCI_AlphaBand)
7183 : {
7184 58 : poMaskBand = GetMaskBand();
7185 : }
7186 : }
7187 :
7188 570 : bool bSignedByte = false;
7189 570 : if (eDataType == GDT_UInt8)
7190 : {
7191 217 : EnablePixelTypeSignedByteWarning(false);
7192 : const char *pszPixelType =
7193 217 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7194 217 : EnablePixelTypeSignedByteWarning(true);
7195 217 : bSignedByte =
7196 217 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7197 : }
7198 :
7199 570 : GUIntBig nSampleCount = 0;
7200 570 : GUIntBig nValidCount = 0;
7201 :
7202 570 : if (bApproxOK && HasArbitraryOverviews())
7203 : {
7204 : /* --------------------------------------------------------------------
7205 : */
7206 : /* Figure out how much the image should be reduced to get an */
7207 : /* approximate value. */
7208 : /* --------------------------------------------------------------------
7209 : */
7210 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7211 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7212 :
7213 0 : int nXReduced = nRasterXSize;
7214 0 : int nYReduced = nRasterYSize;
7215 0 : if (dfReduction > 1.0)
7216 : {
7217 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7218 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7219 :
7220 : // Catch the case of huge resizing ratios here
7221 0 : if (nXReduced == 0)
7222 0 : nXReduced = 1;
7223 0 : if (nYReduced == 0)
7224 0 : nYReduced = 1;
7225 : }
7226 :
7227 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7228 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7229 :
7230 : const CPLErr eErr =
7231 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7232 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7233 0 : if (eErr != CE_None)
7234 : {
7235 0 : CPLFree(pData);
7236 0 : return eErr;
7237 : }
7238 :
7239 0 : GByte *pabyMaskData = nullptr;
7240 0 : if (poMaskBand)
7241 : {
7242 : pabyMaskData =
7243 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7244 0 : if (!pabyMaskData)
7245 : {
7246 0 : CPLFree(pData);
7247 0 : return CE_Failure;
7248 : }
7249 :
7250 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7251 : pabyMaskData, nXReduced, nYReduced,
7252 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
7253 : {
7254 0 : CPLFree(pData);
7255 0 : CPLFree(pabyMaskData);
7256 0 : return CE_Failure;
7257 : }
7258 : }
7259 :
7260 : /* this isn't the fastest way to do this, but is easier for now */
7261 0 : for (int iY = 0; iY < nYReduced; iY++)
7262 : {
7263 0 : for (int iX = 0; iX < nXReduced; iX++)
7264 : {
7265 0 : const int iOffset = iX + iY * nXReduced;
7266 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7267 0 : continue;
7268 :
7269 0 : bool bValid = true;
7270 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7271 0 : iOffset, sNoDataValues, bValid);
7272 0 : if (!bValid)
7273 0 : continue;
7274 :
7275 0 : dfMin = std::min(dfMin, dfValue);
7276 0 : dfMax = std::max(dfMax, dfValue);
7277 :
7278 0 : nValidCount++;
7279 0 : if (dfMin == dfMax)
7280 : {
7281 0 : if (nValidCount == 1)
7282 0 : dfMean = dfMin;
7283 : }
7284 : else
7285 : {
7286 0 : const double dfDelta = dfValue - dfMean;
7287 0 : dfMean += dfDelta / nValidCount;
7288 0 : dfM2 += dfDelta * (dfValue - dfMean);
7289 : }
7290 : }
7291 : }
7292 :
7293 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7294 :
7295 0 : CPLFree(pData);
7296 0 : CPLFree(pabyMaskData);
7297 : }
7298 :
7299 : else // No arbitrary overviews.
7300 : {
7301 570 : if (!InitBlockInfo())
7302 251 : return CE_Failure;
7303 :
7304 : /* --------------------------------------------------------------------
7305 : */
7306 : /* Figure out the ratio of blocks we will read to get an */
7307 : /* approximate value. */
7308 : /* --------------------------------------------------------------------
7309 : */
7310 570 : int nSampleRate = 1;
7311 570 : if (bApproxOK)
7312 : {
7313 43 : nSampleRate = static_cast<int>(std::max(
7314 86 : 1.0,
7315 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7316 : // We want to avoid probing only the first column of blocks for
7317 : // a square shaped raster, because it is not unlikely that it may
7318 : // be padding only (#6378)
7319 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7320 1 : nSampleRate += 1;
7321 : }
7322 570 : if (nSampleRate == 1)
7323 536 : bApproxOK = false;
7324 :
7325 : // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7326 : // for each block, and possibly for the whole raster.
7327 570 : if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7328 312 : eDataType == GDT_UInt16))
7329 : {
7330 : // We can do integer computation on the whole raster in the Byte case
7331 : // only if the number of pixels explored is lower than
7332 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7333 : // Should be 99.99999% of cases.
7334 : // For GUInt16, this limits to raster of 4 giga pixels
7335 :
7336 : const bool bIntegerStats =
7337 451 : ((eDataType == GDT_UInt8 &&
7338 200 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7339 200 : nSampleRate <
7340 200 : GUINTBIG_MAX / (255U * 255U) /
7341 200 : (static_cast<GUInt64>(nBlockXSize) *
7342 200 : static_cast<GUInt64>(nBlockYSize))) ||
7343 51 : (eDataType == GDT_UInt16 &&
7344 51 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7345 51 : nSampleRate <
7346 51 : GUINTBIG_MAX / (65535U * 65535U) /
7347 51 : (static_cast<GUInt64>(nBlockXSize) *
7348 553 : static_cast<GUInt64>(nBlockYSize)))) &&
7349 : // Can be set to NO for easier debugging of the !bIntegerStats
7350 : // case which requires huge rasters to trigger
7351 251 : CPLTestBool(
7352 251 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7353 :
7354 251 : const GUInt32 nMaxValueType =
7355 251 : (eDataType == GDT_UInt8) ? 255 : 65535;
7356 251 : GUInt32 nMin = nMaxValueType;
7357 251 : GUInt32 nMax = 0;
7358 251 : GUIntBig nSum = 0;
7359 251 : GUIntBig nSumSquare = 0;
7360 : // If no valid nodata, map to invalid value (256 for Byte)
7361 251 : const GUInt32 nNoDataValue =
7362 286 : (sNoDataValues.bGotNoDataValue &&
7363 35 : sNoDataValues.dfNoDataValue >= 0 &&
7364 35 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7365 35 : fabs(sNoDataValues.dfNoDataValue -
7366 35 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7367 : 1e-10)) < 1e-10)
7368 286 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7369 : : nMaxValueType + 1;
7370 :
7371 251 : for (GIntBig iSampleBlock = 0;
7372 13098 : iSampleBlock <
7373 13098 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7374 12847 : iSampleBlock += nSampleRate)
7375 : {
7376 12847 : const int iYBlock =
7377 12847 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7378 12847 : const int iXBlock =
7379 12847 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7380 :
7381 : GDALRasterBlock *const poBlock =
7382 12847 : GetLockedBlockRef(iXBlock, iYBlock);
7383 12847 : if (poBlock == nullptr)
7384 0 : return CE_Failure;
7385 :
7386 12847 : void *const pData = poBlock->GetDataRef();
7387 :
7388 12847 : int nXCheck = 0, nYCheck = 0;
7389 12847 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7390 :
7391 12847 : GUIntBig nBlockSum = 0;
7392 12847 : GUIntBig nBlockSumSquare = 0;
7393 12847 : GUIntBig nBlockSampleCount = 0;
7394 12847 : GUIntBig nBlockValidCount = 0;
7395 12847 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7396 12847 : GUIntBig &nBlockSumSquareRef =
7397 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7398 12847 : GUIntBig &nBlockSampleCountRef =
7399 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7400 12847 : GUIntBig &nBlockValidCountRef =
7401 : bIntegerStats ? nValidCount : nBlockValidCount;
7402 :
7403 12847 : if (eDataType == GDT_UInt8)
7404 : {
7405 : ComputeStatisticsInternal<
7406 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7407 12161 : f(nXCheck, nBlockXSize, nYCheck,
7408 : static_cast<const GByte *>(pData),
7409 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7410 : nMax, nBlockSumRef, nBlockSumSquareRef,
7411 : nBlockSampleCountRef, nBlockValidCountRef);
7412 : }
7413 : else
7414 : {
7415 : ComputeStatisticsInternal<
7416 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7417 686 : f(nXCheck, nBlockXSize, nYCheck,
7418 : static_cast<const GUInt16 *>(pData),
7419 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7420 : nMax, nBlockSumRef, nBlockSumSquareRef,
7421 : nBlockSampleCountRef, nBlockValidCountRef);
7422 : }
7423 :
7424 12847 : poBlock->DropLock();
7425 :
7426 12847 : if (!bIntegerStats)
7427 : {
7428 169 : nSampleCount += nBlockSampleCount;
7429 169 : if (nBlockValidCount)
7430 : {
7431 : // Update the global mean and M2 (the difference of the
7432 : // square to the mean) from the values of the block
7433 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7434 169 : const double dfBlockValidCount =
7435 169 : static_cast<double>(nBlockValidCount);
7436 169 : const double dfBlockMean =
7437 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7438 : const double dfBlockM2 =
7439 169 : static_cast<double>(
7440 169 : GDALUInt128::Mul(nBlockSumSquare,
7441 169 : nBlockValidCount) -
7442 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7443 169 : dfBlockValidCount;
7444 169 : const double dfDelta = dfBlockMean - dfMean;
7445 169 : const auto nNewValidCount =
7446 169 : nValidCount + nBlockValidCount;
7447 169 : const double dfNewValidCount =
7448 : static_cast<double>(nNewValidCount);
7449 169 : dfMean +=
7450 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7451 169 : dfM2 +=
7452 169 : dfBlockM2 + dfDelta * dfDelta *
7453 169 : static_cast<double>(nValidCount) *
7454 169 : dfBlockValidCount / dfNewValidCount;
7455 169 : nValidCount = nNewValidCount;
7456 : }
7457 : }
7458 :
7459 12847 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7460 12847 : (static_cast<double>(nBlocksPerRow) *
7461 12847 : nBlocksPerColumn),
7462 : "Compute Statistics", pProgressData))
7463 : {
7464 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7465 : "User terminated");
7466 0 : return CE_Failure;
7467 : }
7468 : }
7469 :
7470 251 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7471 : {
7472 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7473 0 : return CE_Failure;
7474 : }
7475 :
7476 251 : double dfStdDev = 0;
7477 251 : if (bIntegerStats)
7478 : {
7479 227 : if (nValidCount)
7480 218 : dfMean = static_cast<double>(nSum) / nValidCount;
7481 :
7482 : // To avoid potential precision issues when doing the difference,
7483 : // we need to do that computation on 128 bit rather than casting
7484 : // to double
7485 : const GDALUInt128 nTmpForStdDev(
7486 227 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7487 454 : GDALUInt128::Mul(nSum, nSum));
7488 227 : dfStdDev =
7489 227 : nValidCount > 0
7490 227 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7491 : : 0.0;
7492 : }
7493 24 : else if (nValidCount > 0)
7494 : {
7495 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7496 : }
7497 :
7498 : /// Save computed information
7499 251 : if (nValidCount > 0)
7500 : {
7501 242 : if (bApproxOK)
7502 : {
7503 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7504 : }
7505 218 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7506 : {
7507 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7508 : }
7509 242 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7510 : }
7511 :
7512 251 : SetValidPercent(nSampleCount, nValidCount);
7513 :
7514 : /* --------------------------------------------------------------------
7515 : */
7516 : /* Record results. */
7517 : /* --------------------------------------------------------------------
7518 : */
7519 251 : if (pdfMin != nullptr)
7520 248 : *pdfMin = nValidCount ? nMin : 0;
7521 251 : if (pdfMax != nullptr)
7522 248 : *pdfMax = nValidCount ? nMax : 0;
7523 :
7524 251 : if (pdfMean != nullptr)
7525 244 : *pdfMean = dfMean;
7526 :
7527 251 : if (pdfStdDev != nullptr)
7528 244 : *pdfStdDev = dfStdDev;
7529 :
7530 251 : if (nValidCount > 0)
7531 242 : return CE_None;
7532 :
7533 9 : ReportError(CE_Failure, CPLE_AppDefined,
7534 : "Failed to compute statistics, no valid pixels found "
7535 : "in sampling.");
7536 9 : return CE_Failure;
7537 : }
7538 :
7539 319 : GByte *pabyMaskData = nullptr;
7540 319 : if (poMaskBand)
7541 : {
7542 : pabyMaskData = static_cast<GByte *>(
7543 58 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7544 58 : if (!pabyMaskData)
7545 : {
7546 0 : return CE_Failure;
7547 : }
7548 : }
7549 :
7550 319 : float fMin = std::numeric_limits<float>::infinity();
7551 319 : float fMax = -std::numeric_limits<float>::infinity();
7552 : bool bFloat32Optim =
7553 133 : (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7554 319 : eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7555 209 : !pabyMaskData &&
7556 847 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7557 209 : CPLTestBool(
7558 319 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7559 0 : std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7560 :
7561 319 : int nChunkXSize = nBlockXSize;
7562 319 : int nChunkYSize = nBlockYSize;
7563 319 : int nChunksPerRow = nBlocksPerRow;
7564 319 : int nChunksPerCol = nBlocksPerColumn;
7565 :
7566 : #define nBlockXSize use_nChunkXSize_instead
7567 : #define nBlockYSize use_nChunkYSize_instead
7568 : #define nBlocksPerRow use_nChunksPerRow_instead
7569 : #define nBlocksPerColumn use_nChunksPerCol_instead
7570 :
7571 319 : int nThreads = 1;
7572 319 : CPLWorkerThreadPool *psThreadPool = nullptr;
7573 319 : if (bFloat32Optim)
7574 : {
7575 207 : if (nChunkYSize > 1)
7576 : {
7577 : const char *pszNumThreads =
7578 15 : CPLGetConfigOption("GDAL_NUM_THREADS", nullptr);
7579 15 : if (pszNumThreads)
7580 : {
7581 4 : if (EQUAL(pszNumThreads, "ALL_CPUS"))
7582 4 : nThreads = CPLGetNumCPUs();
7583 : else
7584 0 : nThreads =
7585 0 : std::clamp(atoi(pszNumThreads), 1, CPLGetNumCPUs());
7586 4 : if (nThreads > 1)
7587 4 : psThreadPool = GDALGetGlobalThreadPool(nThreads);
7588 : }
7589 : }
7590 :
7591 207 : int nNewChunkXSize = nChunkXSize;
7592 211 : if (!bApproxOK && nThreads > 1 &&
7593 4 : MayMultiBlockReadingBeMultiThreaded())
7594 : {
7595 0 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7596 0 : const size_t nChunkPixels =
7597 0 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7598 0 : if (nRAMAmount > 0 &&
7599 : nChunkPixels <=
7600 0 : std::numeric_limits<size_t>::max() / sizeof(float))
7601 : {
7602 0 : const size_t nBlockSizeAsFloat32 =
7603 : sizeof(float) * nChunkPixels;
7604 0 : const int64_t nBlockCount =
7605 0 : nRAMAmount / nBlockSizeAsFloat32;
7606 0 : if (nBlockCount >= 2)
7607 : {
7608 0 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7609 0 : nChunkXSize * std::min<int64_t>(
7610 : nBlockCount,
7611 0 : std::numeric_limits<int>::max() /
7612 0 : nChunkPixels),
7613 0 : nRasterXSize));
7614 :
7615 0 : CPLAssert(nChunkXSize <
7616 : std::numeric_limits<int>::max() /
7617 : nChunkYSize);
7618 : }
7619 : }
7620 : }
7621 207 : if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7622 : {
7623 187 : pafTemp.reset(static_cast<float *>(
7624 187 : VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7625 187 : bFloat32Optim = pafTemp != nullptr;
7626 187 : if (bFloat32Optim)
7627 : {
7628 187 : nChunkXSize = nNewChunkXSize;
7629 : nChunksPerRow =
7630 187 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7631 : }
7632 : }
7633 207 : CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7634 : nChunkXSize, nChunkYSize);
7635 : }
7636 :
7637 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7638 : const bool bFloat64Optim =
7639 23 : eDataType == GDT_Float64 && !pabyMaskData &&
7640 365 : nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7641 23 : CPLTestBool(
7642 319 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7643 : #endif
7644 :
7645 319 : std::vector<StatisticsTaskFloat32> tasksFloat32;
7646 :
7647 319 : for (GIntBig iSampleBlock = 0;
7648 6034 : iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7649 5715 : iSampleBlock += nSampleRate)
7650 : {
7651 5715 : const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7652 5715 : const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7653 :
7654 : const int nXCheck =
7655 5715 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7656 : const int nYCheck =
7657 5715 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7658 :
7659 6300 : if (poMaskBand &&
7660 585 : poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7661 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7662 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7663 : 0, nChunkXSize, nullptr) != CE_None)
7664 : {
7665 0 : CPLFree(pabyMaskData);
7666 0 : return CE_Failure;
7667 : }
7668 :
7669 5715 : GDALRasterBlock *poBlock = nullptr;
7670 5715 : if (pafTemp)
7671 : {
7672 2393 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7673 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7674 2393 : pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7675 2393 : static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7676 2393 : nullptr) != CE_None)
7677 : {
7678 0 : CPLFree(pabyMaskData);
7679 0 : return CE_Failure;
7680 : }
7681 : }
7682 : else
7683 : {
7684 3322 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7685 3322 : if (poBlock == nullptr)
7686 : {
7687 0 : CPLFree(pabyMaskData);
7688 0 : return CE_Failure;
7689 : }
7690 : }
7691 :
7692 : const void *const pData =
7693 5715 : poBlock ? poBlock->GetDataRef() : pafTemp.get();
7694 :
7695 5715 : if (bFloat32Optim)
7696 : {
7697 4729 : const float *const pafSrcData =
7698 : static_cast<const float *>(pData);
7699 :
7700 4735 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7701 6 : !std::isnan(sNoDataValues.fNoDataValue);
7702 4729 : const int nTasks = std::min(nYCheck, nThreads);
7703 4729 : const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7704 4729 : tasksFloat32.clear();
7705 9462 : for (int i = 0; i < nTasks; ++i)
7706 : {
7707 4733 : StatisticsTaskFloat32 task;
7708 4733 : task.eDataType = eDataType;
7709 4733 : task.bHasNoData = bHasNoData;
7710 4733 : task.psNoDataValues = &sNoDataValues;
7711 4733 : task.nChunkXSize = nChunkXSize;
7712 4733 : task.fMin = fMin;
7713 4733 : task.fMax = fMax;
7714 4733 : task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7715 4733 : nRowsPerTask *
7716 4733 : nChunkXSize;
7717 4733 : task.nXCheck = nXCheck;
7718 4733 : task.nYCheck =
7719 4733 : std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7720 4733 : tasksFloat32.emplace_back(std::move(task));
7721 : }
7722 4729 : if (psThreadPool)
7723 : {
7724 8 : auto poJobQueue = psThreadPool->CreateJobQueue();
7725 12 : for (auto &task : tasksFloat32)
7726 : {
7727 16 : poJobQueue->SubmitJob([&task]() { task.Perform(); });
7728 : }
7729 4 : poJobQueue->WaitCompletion();
7730 : }
7731 : else
7732 : {
7733 4725 : tasksFloat32[0].Perform();
7734 : }
7735 :
7736 9462 : for (const auto &task : tasksFloat32)
7737 : {
7738 4733 : if (task.dfBlockValidCount > 0)
7739 : {
7740 4733 : fMin = std::min(fMin, task.fMin);
7741 4733 : fMax = std::max(fMax, task.fMax);
7742 :
7743 : // Update the global mean and M2 (the difference of the
7744 : // square to the mean) from the values of the block
7745 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7746 4733 : const auto nNewValidCount =
7747 4733 : nValidCount +
7748 4733 : static_cast<int>(task.dfBlockValidCount);
7749 4733 : dfM2 += task.dfBlockM2;
7750 4733 : if (task.dfBlockMean != dfMean)
7751 : {
7752 1167 : if (nValidCount == 0)
7753 : {
7754 50 : dfMean = task.dfBlockMean;
7755 : }
7756 : else
7757 : {
7758 1117 : const double dfDelta =
7759 1117 : task.dfBlockMean - dfMean;
7760 1117 : const double dfNewValidCount =
7761 : static_cast<double>(nNewValidCount);
7762 1117 : dfMean += dfDelta * (task.dfBlockValidCount /
7763 : dfNewValidCount);
7764 1117 : dfM2 += dfDelta * dfDelta *
7765 1117 : static_cast<double>(nValidCount) *
7766 1117 : task.dfBlockValidCount /
7767 : dfNewValidCount;
7768 : }
7769 : }
7770 4733 : nValidCount = nNewValidCount;
7771 : }
7772 : }
7773 : }
7774 :
7775 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7776 986 : else if (bFloat64Optim)
7777 : {
7778 : const bool bHasNoData =
7779 563 : sNoDataValues.bGotNoDataValue &&
7780 269 : !std::isnan(sNoDataValues.dfNoDataValue);
7781 294 : double dfBlockMean = 0;
7782 294 : double dfBlockM2 = 0;
7783 294 : double dfBlockValidCount = 0;
7784 2661 : for (int iY = 0; iY < nYCheck; iY++)
7785 : {
7786 2367 : const int iOffset = iY * nChunkXSize;
7787 2367 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7788 : {
7789 1817 : int iX = 0;
7790 1817 : if (bHasNoData)
7791 : {
7792 : iX = ComputeStatisticsFloat64_SSE2<
7793 : /* bCheckMinEqMax = */ false,
7794 387 : /* bHasNoData = */ true>(
7795 387 : static_cast<const double *>(pData) + iOffset,
7796 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7797 : dfMax, dfBlockMean, dfBlockM2,
7798 : dfBlockValidCount);
7799 : }
7800 : else
7801 : {
7802 : iX = ComputeStatisticsFloat64_SSE2<
7803 : /* bCheckMinEqMax = */ false,
7804 1430 : /* bHasNoData = */ false>(
7805 1430 : static_cast<const double *>(pData) + iOffset,
7806 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7807 : dfMax, dfBlockMean, dfBlockM2,
7808 : dfBlockValidCount);
7809 : }
7810 2959 : for (; iX < nXCheck; iX++)
7811 : {
7812 1142 : const double dfValue = static_cast<const double *>(
7813 1142 : pData)[iOffset + iX];
7814 1665 : if (std::isnan(dfValue) ||
7815 523 : (bHasNoData &&
7816 523 : dfValue == sNoDataValues.dfNoDataValue))
7817 59 : continue;
7818 1083 : dfMin = std::min(dfMin, dfValue);
7819 1083 : dfMax = std::max(dfMax, dfValue);
7820 1083 : dfBlockValidCount += 1.0;
7821 1083 : const double dfDelta = dfValue - dfBlockMean;
7822 1083 : dfBlockMean += dfDelta / dfBlockValidCount;
7823 1083 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7824 1817 : }
7825 : }
7826 : else
7827 : {
7828 550 : int iX = 0;
7829 550 : if (dfBlockValidCount == 0)
7830 : {
7831 7673 : for (; iX < nXCheck; iX++)
7832 : {
7833 7639 : const double dfValue =
7834 : static_cast<const double *>(
7835 7639 : pData)[iOffset + iX];
7836 15253 : if (std::isnan(dfValue) ||
7837 7614 : (bHasNoData &&
7838 7614 : dfValue == sNoDataValues.dfNoDataValue))
7839 7377 : continue;
7840 262 : dfMin = std::min(dfMin, dfValue);
7841 262 : dfMax = std::max(dfMax, dfValue);
7842 262 : dfBlockValidCount = 1;
7843 262 : dfBlockMean = dfValue;
7844 262 : iX++;
7845 262 : break;
7846 : }
7847 : }
7848 550 : if (bHasNoData)
7849 : {
7850 : iX = ComputeStatisticsFloat64_SSE2<
7851 : /* bCheckMinEqMax = */ true,
7852 398 : /* bHasNoData = */ true>(
7853 398 : static_cast<const double *>(pData) + iOffset,
7854 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7855 : dfMax, dfBlockMean, dfBlockM2,
7856 : dfBlockValidCount);
7857 : }
7858 : else
7859 : {
7860 : iX = ComputeStatisticsFloat64_SSE2<
7861 : /* bCheckMinEqMax = */ true,
7862 152 : /* bHasNoData = */ false>(
7863 152 : static_cast<const double *>(pData) + iOffset,
7864 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7865 : dfMax, dfBlockMean, dfBlockM2,
7866 : dfBlockValidCount);
7867 : }
7868 1121 : for (; iX < nXCheck; iX++)
7869 : {
7870 571 : const double dfValue = static_cast<const double *>(
7871 571 : pData)[iOffset + iX];
7872 1103 : if (std::isnan(dfValue) ||
7873 532 : (bHasNoData &&
7874 532 : dfValue == sNoDataValues.dfNoDataValue))
7875 146 : continue;
7876 425 : dfMin = std::min(dfMin, dfValue);
7877 425 : dfMax = std::max(dfMax, dfValue);
7878 425 : dfBlockValidCount += 1.0;
7879 425 : if (dfMin != dfMax)
7880 : {
7881 150 : const double dfDelta = dfValue - dfBlockMean;
7882 150 : dfBlockMean += dfDelta / dfBlockValidCount;
7883 150 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7884 : }
7885 : }
7886 : }
7887 : }
7888 :
7889 294 : if (dfBlockValidCount > 0)
7890 : {
7891 : // Update the global mean and M2 (the difference of the
7892 : // square to the mean) from the values of the block
7893 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7894 262 : const auto nNewValidCount =
7895 262 : nValidCount + static_cast<int>(dfBlockValidCount);
7896 262 : dfM2 += dfBlockM2;
7897 262 : if (dfBlockMean != dfMean)
7898 : {
7899 249 : if (nValidCount == 0)
7900 : {
7901 20 : dfMean = dfBlockMean;
7902 : }
7903 : else
7904 : {
7905 229 : const double dfDelta = dfBlockMean - dfMean;
7906 229 : const double dfNewValidCount =
7907 : static_cast<double>(nNewValidCount);
7908 229 : dfMean +=
7909 229 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7910 229 : dfM2 += dfDelta * dfDelta *
7911 229 : static_cast<double>(nValidCount) *
7912 229 : dfBlockValidCount / dfNewValidCount;
7913 : }
7914 : }
7915 262 : nValidCount = nNewValidCount;
7916 : }
7917 : }
7918 : #endif // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7919 :
7920 : else
7921 : {
7922 : // This isn't the fastest way to do this, but is easier for now.
7923 6046 : for (int iY = 0; iY < nYCheck; iY++)
7924 : {
7925 5354 : if (nValidCount && dfMin != dfMax)
7926 : {
7927 712990 : for (int iX = 0; iX < nXCheck; iX++)
7928 : {
7929 708474 : const GPtrDiff_t iOffset =
7930 708474 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
7931 708474 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7932 9653 : continue;
7933 :
7934 698847 : bool bValid = true;
7935 : double dfValue =
7936 698847 : GetPixelValue(eDataType, bSignedByte, pData,
7937 698847 : iOffset, sNoDataValues, bValid);
7938 :
7939 698847 : if (!bValid)
7940 26 : continue;
7941 :
7942 698821 : dfMin = std::min(dfMin, dfValue);
7943 698821 : dfMax = std::max(dfMax, dfValue);
7944 :
7945 698821 : nValidCount++;
7946 698821 : const double dfDelta = dfValue - dfMean;
7947 698821 : dfMean += dfDelta / nValidCount;
7948 698821 : dfM2 += dfDelta * (dfValue - dfMean);
7949 4516 : }
7950 : }
7951 : else
7952 : {
7953 838 : int iX = 0;
7954 838 : if (nValidCount == 0)
7955 : {
7956 94429 : for (; iX < nXCheck; iX++)
7957 : {
7958 94372 : const GPtrDiff_t iOffset =
7959 94372 : iX +
7960 94372 : static_cast<GPtrDiff_t>(iY) * nChunkXSize;
7961 94372 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7962 94281 : continue;
7963 :
7964 91 : bool bValid = true;
7965 91 : double dfValue = GetPixelValue(
7966 : eDataType, bSignedByte, pData, iOffset,
7967 : sNoDataValues, bValid);
7968 :
7969 91 : if (!bValid)
7970 0 : continue;
7971 :
7972 91 : dfMin = dfValue;
7973 91 : dfMax = dfValue;
7974 91 : dfMean = dfValue;
7975 91 : nValidCount = 1;
7976 91 : iX++;
7977 91 : break;
7978 : }
7979 : }
7980 167021 : for (; iX < nXCheck; iX++)
7981 : {
7982 166183 : const GPtrDiff_t iOffset =
7983 166183 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
7984 166183 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7985 376 : continue;
7986 :
7987 165822 : bool bValid = true;
7988 : double dfValue =
7989 165822 : GetPixelValue(eDataType, bSignedByte, pData,
7990 165822 : iOffset, sNoDataValues, bValid);
7991 :
7992 165822 : if (!bValid)
7993 15 : continue;
7994 :
7995 165807 : dfMin = std::min(dfMin, dfValue);
7996 165807 : dfMax = std::max(dfMax, dfValue);
7997 :
7998 165807 : nValidCount++;
7999 165807 : if (dfMin != dfMax)
8000 : {
8001 2636 : const double dfDelta = dfValue - dfMean;
8002 2636 : dfMean += dfDelta / nValidCount;
8003 2636 : dfM2 += dfDelta * (dfValue - dfMean);
8004 : }
8005 : }
8006 : }
8007 : }
8008 : }
8009 :
8010 5715 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8011 :
8012 5715 : if (poBlock)
8013 3322 : poBlock->DropLock();
8014 :
8015 5715 : if (!pfnProgress(
8016 5715 : static_cast<double>(iSampleBlock) /
8017 5715 : (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8018 : "Compute Statistics", pProgressData))
8019 : {
8020 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8021 0 : CPLFree(pabyMaskData);
8022 0 : return CE_Failure;
8023 : }
8024 : }
8025 :
8026 : #undef nBlockXSize
8027 : #undef nBlockYSize
8028 : #undef nBlocksPerRow
8029 : #undef nBlocksPerColumn
8030 :
8031 319 : if (bFloat32Optim)
8032 : {
8033 207 : dfMin = static_cast<double>(fMin);
8034 207 : dfMax = static_cast<double>(fMax);
8035 : }
8036 319 : CPLFree(pabyMaskData);
8037 : }
8038 :
8039 319 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8040 : {
8041 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8042 0 : return CE_Failure;
8043 : }
8044 :
8045 : /* -------------------------------------------------------------------- */
8046 : /* Save computed information. */
8047 : /* -------------------------------------------------------------------- */
8048 319 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8049 :
8050 319 : if (nValidCount > 0)
8051 : {
8052 318 : if (bApproxOK)
8053 : {
8054 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8055 : }
8056 310 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8057 : {
8058 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8059 : }
8060 318 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8061 : }
8062 : else
8063 : {
8064 1 : dfMin = 0.0;
8065 1 : dfMax = 0.0;
8066 : }
8067 :
8068 319 : SetValidPercent(nSampleCount, nValidCount);
8069 :
8070 : /* -------------------------------------------------------------------- */
8071 : /* Record results. */
8072 : /* -------------------------------------------------------------------- */
8073 319 : if (pdfMin != nullptr)
8074 316 : *pdfMin = dfMin;
8075 319 : if (pdfMax != nullptr)
8076 316 : *pdfMax = dfMax;
8077 :
8078 319 : if (pdfMean != nullptr)
8079 313 : *pdfMean = dfMean;
8080 :
8081 319 : if (pdfStdDev != nullptr)
8082 313 : *pdfStdDev = dfStdDev;
8083 :
8084 319 : if (nValidCount > 0)
8085 318 : return CE_None;
8086 :
8087 1 : ReportError(
8088 : CE_Failure, CPLE_AppDefined,
8089 : "Failed to compute statistics, no valid pixels found in sampling.");
8090 1 : return CE_Failure;
8091 : }
8092 :
8093 : /************************************************************************/
8094 : /* GDALComputeRasterStatistics() */
8095 : /************************************************************************/
8096 :
8097 : /**
8098 : * \brief Compute image statistics.
8099 : *
8100 : * @see GDALRasterBand::ComputeStatistics()
8101 : */
8102 :
8103 230 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8104 : int bApproxOK, double *pdfMin,
8105 : double *pdfMax, double *pdfMean,
8106 : double *pdfStdDev,
8107 : GDALProgressFunc pfnProgress,
8108 : void *pProgressData)
8109 :
8110 : {
8111 230 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8112 :
8113 230 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8114 :
8115 230 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8116 230 : pdfStdDev, pfnProgress, pProgressData);
8117 : }
8118 :
8119 : /************************************************************************/
8120 : /* SetStatistics() */
8121 : /************************************************************************/
8122 :
8123 : /**
8124 : * \brief Set statistics on band.
8125 : *
8126 : * This method can be used to store min/max/mean/standard deviation
8127 : * statistics on a raster band.
8128 : *
8129 : * The default implementation stores them as metadata, and will only work
8130 : * on formats that can save arbitrary metadata. This method cannot detect
8131 : * whether metadata will be properly saved and so may return CE_None even
8132 : * if the statistics will never be saved.
8133 : *
8134 : * This method is the same as the C function GDALSetRasterStatistics().
8135 : *
8136 : * @param dfMin minimum pixel value.
8137 : *
8138 : * @param dfMax maximum pixel value.
8139 : *
8140 : * @param dfMean mean (average) of all pixel values.
8141 : *
8142 : * @param dfStdDev Standard deviation of all pixel values.
8143 : *
8144 : * @return CE_None on success or CE_Failure on failure.
8145 : */
8146 :
8147 593 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8148 : double dfStdDev)
8149 :
8150 : {
8151 593 : char szValue[128] = {0};
8152 :
8153 593 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8154 593 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
8155 :
8156 593 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8157 593 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8158 :
8159 593 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8160 593 : SetMetadataItem("STATISTICS_MEAN", szValue);
8161 :
8162 593 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8163 593 : SetMetadataItem("STATISTICS_STDDEV", szValue);
8164 :
8165 593 : return CE_None;
8166 : }
8167 :
8168 : /************************************************************************/
8169 : /* GDALSetRasterStatistics() */
8170 : /************************************************************************/
8171 :
8172 : /**
8173 : * \brief Set statistics on band.
8174 : *
8175 : * @see GDALRasterBand::SetStatistics()
8176 : */
8177 :
8178 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8179 : double dfMax, double dfMean,
8180 : double dfStdDev)
8181 :
8182 : {
8183 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8184 :
8185 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8186 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8187 : }
8188 :
8189 : /************************************************************************/
8190 : /* ComputeRasterMinMax() */
8191 : /************************************************************************/
8192 :
8193 : template <class T, bool HAS_NODATA>
8194 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8195 : T *pMax)
8196 : {
8197 2 : T min0 = *pMin;
8198 2 : T max0 = *pMax;
8199 2 : T min1 = *pMin;
8200 2 : T max1 = *pMax;
8201 : size_t i;
8202 2 : for (i = 0; i + 1 < nElts; i += 2)
8203 : {
8204 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8205 : {
8206 0 : min0 = std::min(min0, buffer[i]);
8207 0 : max0 = std::max(max0, buffer[i]);
8208 : }
8209 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8210 : {
8211 0 : min1 = std::min(min1, buffer[i + 1]);
8212 0 : max1 = std::max(max1, buffer[i + 1]);
8213 : }
8214 : }
8215 2 : T min = std::min(min0, min1);
8216 2 : T max = std::max(max0, max1);
8217 2 : if (i < nElts)
8218 : {
8219 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8220 : {
8221 2 : min = std::min(min, buffer[i]);
8222 2 : max = std::max(max, buffer[i]);
8223 : }
8224 : }
8225 2 : *pMin = min;
8226 2 : *pMax = max;
8227 2 : }
8228 :
8229 : template <GDALDataType eDataType, bool bSignedByte>
8230 : static void
8231 6703 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8232 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8233 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
8234 : {
8235 6703 : double dfLocalMin = dfMin;
8236 6703 : double dfLocalMax = dfMax;
8237 :
8238 22051 : for (int iY = 0; iY < nYCheck; iY++)
8239 : {
8240 14858421 : for (int iX = 0; iX < nXCheck; iX++)
8241 : {
8242 14843085 : const GPtrDiff_t iOffset =
8243 14843085 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8244 14843085 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8245 109836 : continue;
8246 14760102 : bool bValid = true;
8247 14760102 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8248 : iOffset, sNoDataValues, bValid);
8249 14760102 : if (!bValid)
8250 26871 : continue;
8251 :
8252 14733202 : dfLocalMin = std::min(dfLocalMin, dfValue);
8253 14733202 : dfLocalMax = std::max(dfLocalMax, dfValue);
8254 : }
8255 : }
8256 :
8257 6703 : dfMin = dfLocalMin;
8258 6703 : dfMax = dfLocalMax;
8259 6703 : }
8260 :
8261 6703 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8262 : bool bSignedByte, int nXCheck, int nYCheck,
8263 : int nBlockXSize,
8264 : const GDALNoDataValues &sNoDataValues,
8265 : const GByte *pabyMaskData, double &dfMin,
8266 : double &dfMax)
8267 : {
8268 6703 : switch (eDataType)
8269 : {
8270 0 : case GDT_Unknown:
8271 0 : CPLAssert(false);
8272 : break;
8273 660 : case GDT_UInt8:
8274 660 : if (bSignedByte)
8275 : {
8276 3 : ComputeMinMaxGeneric<GDT_UInt8, true>(
8277 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8278 : pabyMaskData, dfMin, dfMax);
8279 : }
8280 : else
8281 : {
8282 657 : ComputeMinMaxGeneric<GDT_UInt8, false>(
8283 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8284 : pabyMaskData, dfMin, dfMax);
8285 : }
8286 660 : break;
8287 4 : case GDT_Int8:
8288 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8289 : nBlockXSize, sNoDataValues,
8290 : pabyMaskData, dfMin, dfMax);
8291 4 : break;
8292 969 : case GDT_UInt16:
8293 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8294 : nBlockXSize, sNoDataValues,
8295 : pabyMaskData, dfMin, dfMax);
8296 969 : break;
8297 2 : case GDT_Int16:
8298 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8299 : nBlockXSize, sNoDataValues,
8300 : pabyMaskData, dfMin, dfMax);
8301 2 : break;
8302 3 : case GDT_UInt32:
8303 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8304 : nBlockXSize, sNoDataValues,
8305 : pabyMaskData, dfMin, dfMax);
8306 3 : break;
8307 3 : case GDT_Int32:
8308 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8309 : nBlockXSize, sNoDataValues,
8310 : pabyMaskData, dfMin, dfMax);
8311 3 : break;
8312 4 : case GDT_UInt64:
8313 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8314 : nBlockXSize, sNoDataValues,
8315 : pabyMaskData, dfMin, dfMax);
8316 4 : break;
8317 4 : case GDT_Int64:
8318 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8319 : nBlockXSize, sNoDataValues,
8320 : pabyMaskData, dfMin, dfMax);
8321 4 : break;
8322 2 : case GDT_Float16:
8323 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8324 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8325 : pabyMaskData, dfMin, dfMax);
8326 2 : break;
8327 4941 : case GDT_Float32:
8328 4941 : ComputeMinMaxGeneric<GDT_Float32, false>(
8329 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8330 : pabyMaskData, dfMin, dfMax);
8331 4941 : break;
8332 1 : case GDT_Float64:
8333 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8334 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8335 : pabyMaskData, dfMin, dfMax);
8336 1 : break;
8337 9 : case GDT_CInt16:
8338 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8339 : nBlockXSize, sNoDataValues,
8340 : pabyMaskData, dfMin, dfMax);
8341 9 : break;
8342 9 : case GDT_CInt32:
8343 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8344 : nBlockXSize, sNoDataValues,
8345 : pabyMaskData, dfMin, dfMax);
8346 9 : break;
8347 0 : case GDT_CFloat16:
8348 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8349 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8350 : pabyMaskData, dfMin, dfMax);
8351 0 : break;
8352 75 : case GDT_CFloat32:
8353 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8354 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8355 : pabyMaskData, dfMin, dfMax);
8356 75 : break;
8357 17 : case GDT_CFloat64:
8358 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8359 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8360 : pabyMaskData, dfMin, dfMax);
8361 17 : break;
8362 0 : case GDT_TypeCount:
8363 0 : CPLAssert(false);
8364 : break;
8365 : }
8366 6703 : }
8367 :
8368 189 : static bool ComputeMinMaxGenericIterBlocks(
8369 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8370 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8371 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8372 : double &dfMin, double &dfMax)
8373 :
8374 : {
8375 189 : GByte *pabyMaskData = nullptr;
8376 : int nBlockXSize, nBlockYSize;
8377 189 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8378 :
8379 189 : if (poMaskBand)
8380 : {
8381 : pabyMaskData =
8382 125 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8383 125 : if (!pabyMaskData)
8384 : {
8385 0 : return false;
8386 : }
8387 : }
8388 :
8389 6892 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8390 6703 : iSampleBlock += nSampleRate)
8391 : {
8392 6703 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8393 6703 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8394 :
8395 6703 : int nXCheck = 0, nYCheck = 0;
8396 6703 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8397 :
8398 13283 : if (poMaskBand &&
8399 6580 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8400 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8401 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8402 : nBlockXSize, nullptr) != CE_None)
8403 : {
8404 0 : CPLFree(pabyMaskData);
8405 0 : return false;
8406 : }
8407 :
8408 6703 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8409 6703 : if (poBlock == nullptr)
8410 : {
8411 0 : CPLFree(pabyMaskData);
8412 0 : return false;
8413 : }
8414 :
8415 6703 : void *const pData = poBlock->GetDataRef();
8416 :
8417 6703 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8418 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8419 : dfMax);
8420 :
8421 6703 : poBlock->DropLock();
8422 : }
8423 :
8424 189 : CPLFree(pabyMaskData);
8425 189 : return true;
8426 : }
8427 :
8428 : /**
8429 : * \brief Compute the min/max values for a band.
8430 : *
8431 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8432 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8433 : * get an approximate min/max. If the band has a nodata value it will
8434 : * be excluded from the minimum and maximum.
8435 : *
8436 : * If bApprox is FALSE, then all pixels will be read and used to compute
8437 : * an exact range.
8438 : *
8439 : * This method is the same as the C function GDALComputeRasterMinMax().
8440 : *
8441 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8442 : * FALSE.
8443 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8444 : * maximum (adfMinMax[1]) are returned.
8445 : *
8446 : * @return CE_None on success or CE_Failure on failure.
8447 : */
8448 :
8449 1819 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8450 : {
8451 : /* -------------------------------------------------------------------- */
8452 : /* Does the driver already know the min/max? */
8453 : /* -------------------------------------------------------------------- */
8454 1819 : if (bApproxOK)
8455 : {
8456 23 : int bSuccessMin = FALSE;
8457 23 : int bSuccessMax = FALSE;
8458 :
8459 23 : double dfMin = GetMinimum(&bSuccessMin);
8460 23 : double dfMax = GetMaximum(&bSuccessMax);
8461 :
8462 23 : if (bSuccessMin && bSuccessMax)
8463 : {
8464 1 : adfMinMax[0] = dfMin;
8465 1 : adfMinMax[1] = dfMax;
8466 1 : return CE_None;
8467 : }
8468 : }
8469 :
8470 : /* -------------------------------------------------------------------- */
8471 : /* If we have overview bands, use them for min/max. */
8472 : /* -------------------------------------------------------------------- */
8473 : // cppcheck-suppress knownConditionTrueFalse
8474 1818 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8475 : {
8476 : GDALRasterBand *poBand =
8477 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8478 :
8479 0 : if (poBand != this)
8480 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8481 : }
8482 :
8483 : /* -------------------------------------------------------------------- */
8484 : /* Read actual data and compute minimum and maximum. */
8485 : /* -------------------------------------------------------------------- */
8486 1818 : GDALNoDataValues sNoDataValues(this, eDataType);
8487 1818 : GDALRasterBand *poMaskBand = nullptr;
8488 1818 : if (!sNoDataValues.bGotNoDataValue)
8489 : {
8490 1555 : const int l_nMaskFlags = GetMaskFlags();
8491 1680 : if (l_nMaskFlags != GMF_ALL_VALID &&
8492 125 : GetColorInterpretation() != GCI_AlphaBand)
8493 : {
8494 125 : poMaskBand = GetMaskBand();
8495 : }
8496 : }
8497 :
8498 1818 : if (!bApproxOK &&
8499 1796 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8500 1658 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8501 1455 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8502 1409 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8503 1796 : eDataType == GDT_Float64) &&
8504 : !poMaskBand)
8505 : {
8506 1470 : CPLErr eErr = ComputeRasterMinMaxLocation(
8507 735 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8508 735 : if (eErr == CE_Warning)
8509 : {
8510 9 : ReportError(CE_Failure, CPLE_AppDefined,
8511 : "Failed to compute min/max, no valid pixels found in "
8512 : "sampling.");
8513 9 : eErr = CE_Failure;
8514 : }
8515 735 : return eErr;
8516 : }
8517 :
8518 1083 : bool bSignedByte = false;
8519 1083 : if (eDataType == GDT_UInt8)
8520 : {
8521 783 : EnablePixelTypeSignedByteWarning(false);
8522 : const char *pszPixelType =
8523 783 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8524 783 : EnablePixelTypeSignedByteWarning(true);
8525 783 : bSignedByte =
8526 783 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8527 : }
8528 :
8529 : GDALRasterIOExtraArg sExtraArg;
8530 1083 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8531 :
8532 2166 : GUInt32 nMin = (eDataType == GDT_UInt8)
8533 1083 : ? 255
8534 : : 65535; // used for GByte & GUInt16 cases
8535 1083 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8536 1083 : GInt16 nMinInt16 =
8537 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8538 1083 : GInt16 nMaxInt16 =
8539 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8540 1083 : double dfMin =
8541 : std::numeric_limits<double>::infinity(); // used for generic code path
8542 1083 : double dfMax =
8543 : -std::numeric_limits<double>::infinity(); // used for generic code path
8544 1083 : const bool bUseOptimizedPath =
8545 1289 : !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8546 206 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8547 :
8548 : const auto ComputeMinMaxForBlock =
8549 19550 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8550 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8551 113170 : int nYCheck)
8552 : {
8553 19550 : if (eDataType == GDT_UInt8 && !bSignedByte)
8554 : {
8555 : const bool bHasNoData =
8556 11572 : sNoDataValues.bGotNoDataValue &&
8557 29707 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8558 11572 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8559 11572 : sNoDataValues.dfNoDataValue;
8560 18135 : const GUInt32 nNoDataValue =
8561 18135 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8562 : : 0;
8563 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8564 : ComputeStatisticsInternal<GByte,
8565 : /* COMPUTE_OTHER_STATS = */ false>::
8566 18135 : f(nXCheck, nBufferWidth, nYCheck,
8567 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8568 18135 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8569 : }
8570 1415 : else if (eDataType == GDT_UInt16)
8571 : {
8572 : const bool bHasNoData =
8573 84 : sNoDataValues.bGotNoDataValue &&
8574 1497 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8575 84 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8576 84 : sNoDataValues.dfNoDataValue;
8577 1413 : const GUInt32 nNoDataValue =
8578 1413 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8579 : : 0;
8580 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8581 : ComputeStatisticsInternal<GUInt16,
8582 : /* COMPUTE_OTHER_STATS = */ false>::
8583 1413 : f(nXCheck, nBufferWidth, nYCheck,
8584 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8585 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8586 : }
8587 2 : else if (eDataType == GDT_Int16)
8588 : {
8589 : const bool bHasNoData =
8590 0 : sNoDataValues.bGotNoDataValue &&
8591 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8592 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8593 0 : sNoDataValues.dfNoDataValue;
8594 2 : if (bHasNoData)
8595 : {
8596 0 : const int16_t nNoDataValue =
8597 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8598 0 : for (int iY = 0; iY < nYCheck; iY++)
8599 : {
8600 0 : ComputeMinMax<int16_t, true>(
8601 0 : static_cast<const int16_t *>(pData) +
8602 0 : static_cast<size_t>(iY) * nBufferWidth,
8603 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8604 : }
8605 : }
8606 : else
8607 : {
8608 4 : for (int iY = 0; iY < nYCheck; iY++)
8609 : {
8610 2 : ComputeMinMax<int16_t, false>(
8611 2 : static_cast<const int16_t *>(pData) +
8612 2 : static_cast<size_t>(iY) * nBufferWidth,
8613 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8614 : }
8615 : }
8616 : }
8617 19550 : };
8618 :
8619 1083 : if (bApproxOK && HasArbitraryOverviews())
8620 : {
8621 : /* --------------------------------------------------------------------
8622 : */
8623 : /* Figure out how much the image should be reduced to get an */
8624 : /* approximate value. */
8625 : /* --------------------------------------------------------------------
8626 : */
8627 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8628 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8629 :
8630 0 : int nXReduced = nRasterXSize;
8631 0 : int nYReduced = nRasterYSize;
8632 0 : if (dfReduction > 1.0)
8633 : {
8634 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8635 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8636 :
8637 : // Catch the case of huge resizing ratios here
8638 0 : if (nXReduced == 0)
8639 0 : nXReduced = 1;
8640 0 : if (nYReduced == 0)
8641 0 : nYReduced = 1;
8642 : }
8643 :
8644 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8645 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8646 :
8647 : const CPLErr eErr =
8648 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8649 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8650 0 : if (eErr != CE_None)
8651 : {
8652 0 : CPLFree(pData);
8653 0 : return eErr;
8654 : }
8655 :
8656 0 : GByte *pabyMaskData = nullptr;
8657 0 : if (poMaskBand)
8658 : {
8659 : pabyMaskData =
8660 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8661 0 : if (!pabyMaskData)
8662 : {
8663 0 : CPLFree(pData);
8664 0 : return CE_Failure;
8665 : }
8666 :
8667 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8668 : pabyMaskData, nXReduced, nYReduced,
8669 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
8670 : {
8671 0 : CPLFree(pData);
8672 0 : CPLFree(pabyMaskData);
8673 0 : return CE_Failure;
8674 : }
8675 : }
8676 :
8677 0 : if (bUseOptimizedPath)
8678 : {
8679 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8680 : }
8681 : else
8682 : {
8683 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8684 : nYReduced, nXReduced, sNoDataValues,
8685 : pabyMaskData, dfMin, dfMax);
8686 : }
8687 :
8688 0 : CPLFree(pData);
8689 0 : CPLFree(pabyMaskData);
8690 : }
8691 :
8692 : else // No arbitrary overviews
8693 : {
8694 1083 : if (!InitBlockInfo())
8695 0 : return CE_Failure;
8696 :
8697 : /* --------------------------------------------------------------------
8698 : */
8699 : /* Figure out the ratio of blocks we will read to get an */
8700 : /* approximate value. */
8701 : /* --------------------------------------------------------------------
8702 : */
8703 1083 : int nSampleRate = 1;
8704 :
8705 1083 : if (bApproxOK)
8706 : {
8707 22 : nSampleRate = static_cast<int>(std::max(
8708 44 : 1.0,
8709 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8710 : // We want to avoid probing only the first column of blocks for
8711 : // a square shaped raster, because it is not unlikely that it may
8712 : // be padding only (#6378).
8713 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8714 0 : nSampleRate += 1;
8715 : }
8716 :
8717 1083 : if (bUseOptimizedPath)
8718 : {
8719 894 : for (GIntBig iSampleBlock = 0;
8720 20370 : iSampleBlock <
8721 20370 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8722 19476 : iSampleBlock += nSampleRate)
8723 : {
8724 19552 : const int iYBlock =
8725 19552 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8726 19552 : const int iXBlock =
8727 19552 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8728 :
8729 19552 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8730 19552 : if (poBlock == nullptr)
8731 2 : return CE_Failure;
8732 :
8733 19550 : void *const pData = poBlock->GetDataRef();
8734 :
8735 19550 : int nXCheck = 0, nYCheck = 0;
8736 19550 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8737 :
8738 19550 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8739 :
8740 19550 : poBlock->DropLock();
8741 :
8742 19550 : if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8743 4110 : nMax == 255)
8744 74 : break;
8745 : }
8746 : }
8747 : else
8748 : {
8749 189 : const GIntBig nTotalBlocks =
8750 189 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8751 189 : if (!ComputeMinMaxGenericIterBlocks(
8752 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8753 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8754 : {
8755 0 : return CE_Failure;
8756 : }
8757 : }
8758 : }
8759 :
8760 1081 : if (bUseOptimizedPath)
8761 : {
8762 892 : if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8763 : {
8764 891 : dfMin = nMin;
8765 891 : dfMax = nMax;
8766 : }
8767 1 : else if (eDataType == GDT_Int16)
8768 : {
8769 1 : dfMin = nMinInt16;
8770 1 : dfMax = nMaxInt16;
8771 : }
8772 : }
8773 :
8774 1081 : if (dfMin > dfMax)
8775 : {
8776 24 : adfMinMax[0] = 0;
8777 24 : adfMinMax[1] = 0;
8778 24 : ReportError(
8779 : CE_Failure, CPLE_AppDefined,
8780 : "Failed to compute min/max, no valid pixels found in sampling.");
8781 24 : return CE_Failure;
8782 : }
8783 :
8784 1057 : adfMinMax[0] = dfMin;
8785 1057 : adfMinMax[1] = dfMax;
8786 :
8787 1057 : return CE_None;
8788 : }
8789 :
8790 : /************************************************************************/
8791 : /* GDALComputeRasterMinMax() */
8792 : /************************************************************************/
8793 :
8794 : /**
8795 : * \brief Compute the min/max values for a band.
8796 : *
8797 : * @see GDALRasterBand::ComputeRasterMinMax()
8798 : *
8799 : * @note Prior to GDAL 3.6, this function returned void
8800 : */
8801 :
8802 1668 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8803 : double adfMinMax[2])
8804 :
8805 : {
8806 1668 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8807 :
8808 1668 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8809 1668 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8810 : }
8811 :
8812 : /************************************************************************/
8813 : /* ComputeRasterMinMaxLocation() */
8814 : /************************************************************************/
8815 :
8816 : /**
8817 : * \brief Compute the min/max values for a band, and their location.
8818 : *
8819 : * Pixels whose value matches the nodata value or are masked by the mask
8820 : * band are ignored.
8821 : *
8822 : * If the minimum or maximum value is hit in several locations, it is not
8823 : * specified which one will be returned.
8824 : *
8825 : * @param[out] pdfMin Pointer to the minimum value.
8826 : * @param[out] pdfMax Pointer to the maximum value.
8827 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8828 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8829 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8830 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8831 : *
8832 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8833 : * CE_Failure in case of error.
8834 : *
8835 : * @since GDAL 3.11
8836 : */
8837 :
8838 751 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8839 : double *pdfMax, int *pnMinX,
8840 : int *pnMinY, int *pnMaxX,
8841 : int *pnMaxY)
8842 : {
8843 751 : int nMinX = -1;
8844 751 : int nMinY = -1;
8845 751 : int nMaxX = -1;
8846 751 : int nMaxY = -1;
8847 751 : double dfMin = std::numeric_limits<double>::infinity();
8848 751 : double dfMax = -std::numeric_limits<double>::infinity();
8849 751 : if (pdfMin)
8850 748 : *pdfMin = dfMin;
8851 751 : if (pdfMax)
8852 748 : *pdfMax = dfMax;
8853 751 : if (pnMinX)
8854 14 : *pnMinX = nMinX;
8855 751 : if (pnMinY)
8856 14 : *pnMinY = nMinY;
8857 751 : if (pnMaxX)
8858 14 : *pnMaxX = nMaxX;
8859 751 : if (pnMaxY)
8860 14 : *pnMaxY = nMaxY;
8861 :
8862 751 : if (GDALDataTypeIsComplex(eDataType))
8863 : {
8864 0 : CPLError(CE_Failure, CPLE_NotSupported,
8865 : "Complex data type not supported");
8866 0 : return CE_Failure;
8867 : }
8868 :
8869 751 : if (!InitBlockInfo())
8870 0 : return CE_Failure;
8871 :
8872 751 : GDALNoDataValues sNoDataValues(this, eDataType);
8873 751 : GDALRasterBand *poMaskBand = nullptr;
8874 751 : if (!sNoDataValues.bGotNoDataValue)
8875 : {
8876 578 : const int l_nMaskFlags = GetMaskFlags();
8877 579 : if (l_nMaskFlags != GMF_ALL_VALID &&
8878 1 : GetColorInterpretation() != GCI_AlphaBand)
8879 : {
8880 1 : poMaskBand = GetMaskBand();
8881 : }
8882 : }
8883 :
8884 751 : bool bSignedByte = false;
8885 751 : if (eDataType == GDT_UInt8)
8886 : {
8887 7 : EnablePixelTypeSignedByteWarning(false);
8888 : const char *pszPixelType =
8889 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8890 7 : EnablePixelTypeSignedByteWarning(true);
8891 7 : bSignedByte =
8892 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8893 : }
8894 :
8895 751 : GByte *pabyMaskData = nullptr;
8896 751 : if (poMaskBand)
8897 : {
8898 : pabyMaskData =
8899 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8900 1 : if (!pabyMaskData)
8901 : {
8902 0 : return CE_Failure;
8903 : }
8904 : }
8905 :
8906 751 : const GIntBig nTotalBlocks =
8907 751 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8908 751 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8909 751 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8910 7857 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8911 : {
8912 7109 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8913 7109 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8914 :
8915 7109 : int nXCheck = 0, nYCheck = 0;
8916 7109 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8917 :
8918 7111 : if (poMaskBand &&
8919 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8920 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8921 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8922 2 : nBlockXSize, nullptr) != CE_None)
8923 : {
8924 0 : CPLFree(pabyMaskData);
8925 0 : return CE_Failure;
8926 : }
8927 :
8928 7109 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8929 7109 : if (poBlock == nullptr)
8930 : {
8931 0 : CPLFree(pabyMaskData);
8932 0 : return CE_Failure;
8933 : }
8934 :
8935 7109 : void *const pData = poBlock->GetDataRef();
8936 :
8937 7109 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8938 : {
8939 5059 : for (int iY = 0; iY < nYCheck; ++iY)
8940 : {
8941 238290 : for (int iX = 0; iX < nXCheck; ++iX)
8942 : {
8943 233478 : const GPtrDiff_t iOffset =
8944 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8945 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8946 2 : continue;
8947 233476 : bool bValid = true;
8948 : double dfValue =
8949 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8950 : sNoDataValues, bValid);
8951 233476 : if (!bValid)
8952 0 : continue;
8953 233476 : if (dfValue < dfMin)
8954 : {
8955 606 : dfMin = dfValue;
8956 606 : nMinX = iXBlock * nBlockXSize + iX;
8957 606 : nMinY = iYBlock * nBlockYSize + iY;
8958 : }
8959 233476 : if (dfValue > dfMax)
8960 : {
8961 1515 : dfMax = dfValue;
8962 1515 : nMaxX = iXBlock * nBlockXSize + iX;
8963 1515 : nMaxY = iYBlock * nBlockYSize + iY;
8964 : }
8965 : }
8966 247 : }
8967 : }
8968 : else
8969 : {
8970 6862 : size_t pos_min = 0;
8971 6862 : size_t pos_max = 0;
8972 6862 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8973 6862 : if (bNeedsMin && bNeedsMax)
8974 : {
8975 13716 : std::tie(pos_min, pos_max) = gdal::minmax_element(
8976 6858 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8977 6858 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8978 13716 : sNoDataValues.dfNoDataValue);
8979 : }
8980 4 : else if (bNeedsMin)
8981 : {
8982 1 : pos_min = gdal::min_element(
8983 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8984 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8985 : sNoDataValues.dfNoDataValue);
8986 : }
8987 3 : else if (bNeedsMax)
8988 : {
8989 2 : pos_max = gdal::max_element(
8990 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8991 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8992 : sNoDataValues.dfNoDataValue);
8993 : }
8994 :
8995 6862 : if (bNeedsMin)
8996 : {
8997 6859 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8998 6859 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8999 6859 : bool bValid = true;
9000 : const double dfMinValueBlock =
9001 6859 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9002 : sNoDataValues, bValid);
9003 6859 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9004 : {
9005 1042 : dfMin = dfMinValueBlock;
9006 1042 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
9007 1042 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
9008 : }
9009 : }
9010 :
9011 6862 : if (bNeedsMax)
9012 : {
9013 6860 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9014 6860 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9015 6860 : bool bValid = true;
9016 : const double dfMaxValueBlock =
9017 6860 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9018 : sNoDataValues, bValid);
9019 6860 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9020 : {
9021 962 : dfMax = dfMaxValueBlock;
9022 962 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9023 962 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9024 : }
9025 : }
9026 : }
9027 :
9028 7109 : poBlock->DropLock();
9029 :
9030 7109 : if (eDataType == GDT_UInt8)
9031 : {
9032 10 : if (bNeedsMin && dfMin == 0)
9033 : {
9034 1 : bNeedsMin = false;
9035 : }
9036 10 : if (bNeedsMax && dfMax == 255)
9037 : {
9038 4 : bNeedsMax = false;
9039 : }
9040 10 : if (!bNeedsMin && !bNeedsMax)
9041 : {
9042 3 : break;
9043 : }
9044 : }
9045 : }
9046 :
9047 751 : CPLFree(pabyMaskData);
9048 :
9049 751 : if (pdfMin)
9050 748 : *pdfMin = dfMin;
9051 751 : if (pdfMax)
9052 748 : *pdfMax = dfMax;
9053 751 : if (pnMinX)
9054 14 : *pnMinX = nMinX;
9055 751 : if (pnMinY)
9056 14 : *pnMinY = nMinY;
9057 751 : if (pnMaxX)
9058 14 : *pnMaxX = nMaxX;
9059 751 : if (pnMaxY)
9060 14 : *pnMaxY = nMaxY;
9061 751 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9062 751 : : CE_None;
9063 : }
9064 :
9065 : /************************************************************************/
9066 : /* GDALComputeRasterMinMaxLocation() */
9067 : /************************************************************************/
9068 :
9069 : /**
9070 : * \brief Compute the min/max values for a band, and their location.
9071 : *
9072 : * @see GDALRasterBand::ComputeRasterMinMax()
9073 : * @since GDAL 3.11
9074 : */
9075 :
9076 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9077 : double *pdfMax, int *pnMinX, int *pnMinY,
9078 : int *pnMaxX, int *pnMaxY)
9079 :
9080 : {
9081 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9082 :
9083 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9084 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9085 14 : pnMaxX, pnMaxY);
9086 : }
9087 :
9088 : /************************************************************************/
9089 : /* SetDefaultHistogram() */
9090 : /************************************************************************/
9091 :
9092 : /* FIXME : add proper documentation */
9093 : /**
9094 : * \brief Set default histogram.
9095 : *
9096 : * This method is the same as the C function GDALSetDefaultHistogram() and
9097 : * GDALSetDefaultHistogramEx()
9098 : */
9099 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9100 : double /* dfMax */,
9101 : int /* nBuckets */,
9102 : GUIntBig * /* panHistogram */)
9103 :
9104 : {
9105 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9106 0 : ReportError(CE_Failure, CPLE_NotSupported,
9107 : "SetDefaultHistogram() not implemented for this format.");
9108 :
9109 0 : return CE_Failure;
9110 : }
9111 :
9112 : /************************************************************************/
9113 : /* GDALSetDefaultHistogram() */
9114 : /************************************************************************/
9115 :
9116 : /**
9117 : * \brief Set default histogram.
9118 : *
9119 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9120 : * 2 billion.
9121 : *
9122 : * @see GDALRasterBand::SetDefaultHistogram()
9123 : * @see GDALSetRasterHistogramEx()
9124 : */
9125 :
9126 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9127 : double dfMax, int nBuckets,
9128 : int *panHistogram)
9129 :
9130 : {
9131 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9132 :
9133 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9134 :
9135 : GUIntBig *panHistogramTemp =
9136 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9137 0 : if (panHistogramTemp == nullptr)
9138 : {
9139 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9140 : "Out of memory in GDALSetDefaultHistogram().");
9141 0 : return CE_Failure;
9142 : }
9143 :
9144 0 : for (int i = 0; i < nBuckets; ++i)
9145 : {
9146 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9147 : }
9148 :
9149 : const CPLErr eErr =
9150 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9151 :
9152 0 : CPLFree(panHistogramTemp);
9153 :
9154 0 : return eErr;
9155 : }
9156 :
9157 : /************************************************************************/
9158 : /* GDALSetDefaultHistogramEx() */
9159 : /************************************************************************/
9160 :
9161 : /**
9162 : * \brief Set default histogram.
9163 : *
9164 : * @see GDALRasterBand::SetDefaultHistogram()
9165 : *
9166 : */
9167 :
9168 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9169 : double dfMin, double dfMax,
9170 : int nBuckets,
9171 : GUIntBig *panHistogram)
9172 :
9173 : {
9174 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9175 :
9176 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9177 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9178 : }
9179 :
9180 : /************************************************************************/
9181 : /* GetDefaultRAT() */
9182 : /************************************************************************/
9183 :
9184 : /**
9185 : * \brief Fetch default Raster Attribute Table.
9186 : *
9187 : * A RAT will be returned if there is a default one associated with the
9188 : * band, otherwise NULL is returned. The returned RAT is owned by the
9189 : * band and should not be deleted by the application.
9190 : *
9191 : * This method is the same as the C function GDALGetDefaultRAT().
9192 : *
9193 : * @return NULL, or a pointer to an internal RAT owned by the band.
9194 : */
9195 :
9196 180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9197 :
9198 : {
9199 180 : return nullptr;
9200 : }
9201 :
9202 : /************************************************************************/
9203 : /* GDALGetDefaultRAT() */
9204 : /************************************************************************/
9205 :
9206 : /**
9207 : * \brief Fetch default Raster Attribute Table.
9208 : *
9209 : * @see GDALRasterBand::GetDefaultRAT()
9210 : */
9211 :
9212 1249 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9213 :
9214 : {
9215 1249 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9216 :
9217 1249 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9218 1249 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9219 : }
9220 :
9221 : /************************************************************************/
9222 : /* SetDefaultRAT() */
9223 : /************************************************************************/
9224 :
9225 : /**
9226 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9227 : * \brief Set default Raster Attribute Table.
9228 : *
9229 : * Associates a default RAT with the band. If not implemented for the
9230 : * format a CPLE_NotSupported error will be issued. If successful a copy
9231 : * of the RAT is made, the original remains owned by the caller.
9232 : *
9233 : * This method is the same as the C function GDALSetDefaultRAT().
9234 : *
9235 : * @param poRAT the RAT to assign to the band.
9236 : *
9237 : * @return CE_None on success or CE_Failure if unsupported or otherwise
9238 : * failing.
9239 : */
9240 :
9241 : /**/
9242 : /**/
9243 :
9244 : CPLErr
9245 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9246 : {
9247 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9248 : {
9249 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
9250 0 : ReportError(CE_Failure, CPLE_NotSupported,
9251 : "SetDefaultRAT() not implemented for this format.");
9252 0 : CPLPopErrorHandler();
9253 : }
9254 0 : return CE_Failure;
9255 : }
9256 :
9257 : /************************************************************************/
9258 : /* GDALSetDefaultRAT() */
9259 : /************************************************************************/
9260 :
9261 : /**
9262 : * \brief Set default Raster Attribute Table.
9263 : *
9264 : * @see GDALRasterBand::GDALSetDefaultRAT()
9265 : */
9266 :
9267 39 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9268 : GDALRasterAttributeTableH hRAT)
9269 :
9270 : {
9271 39 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9272 :
9273 39 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9274 :
9275 39 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9276 : }
9277 :
9278 : /************************************************************************/
9279 : /* HasNoData() */
9280 : /************************************************************************/
9281 :
9282 133565 : bool GDALRasterBand::HasNoData() const
9283 : {
9284 133565 : int bHaveNoDataRaw = FALSE;
9285 133565 : bool bHaveNoData = false;
9286 133565 : GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9287 133565 : if (eDataType == GDT_Int64)
9288 : {
9289 212 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9290 212 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9291 : }
9292 133353 : else if (eDataType == GDT_UInt64)
9293 : {
9294 160 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9295 160 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9296 : }
9297 : else
9298 : {
9299 133193 : const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9300 133193 : if (bHaveNoDataRaw &&
9301 133193 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9302 : {
9303 1184 : bHaveNoData = true;
9304 : }
9305 : }
9306 133565 : return bHaveNoData;
9307 : }
9308 :
9309 : /************************************************************************/
9310 : /* GetMaskBand() */
9311 : /************************************************************************/
9312 :
9313 : /**
9314 : * \brief Return the mask band associated with the band.
9315 : *
9316 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9317 : * that returns one of four default implementations :
9318 : * <ul>
9319 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9320 : * </li>
9321 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9322 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9323 : * GMF_NODATA | GMF_PER_DATASET.
9324 : * </li>
9325 : * <li>If the band has a nodata value set, an instance of the new
9326 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9327 : * GMF_NODATA.
9328 : * </li>
9329 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9330 : * to apply to this band (specific rules yet to be determined) and that is of
9331 : * type GDT_UInt8 then that alpha band will be returned, and the flags
9332 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9333 : * </li>
9334 : * <li>If neither of the above apply, an instance of the new
9335 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9336 : * pixels. The null flags will return GMF_ALL_VALID.
9337 : * </li>
9338 : * </ul>
9339 : *
9340 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9341 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9342 : *
9343 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9344 : * dataset, with the same name as the main dataset and suffixed with .msk,
9345 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9346 : * main dataset.
9347 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9348 : * level, where xx matches the band number of a band of the main dataset. The
9349 : * value of those items is a combination of the flags GMF_ALL_VALID,
9350 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9351 : * a band, then the other rules explained above will be used to generate a
9352 : * on-the-fly mask band.
9353 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9354 : *
9355 : * This method is the same as the C function GDALGetMaskBand().
9356 : *
9357 : * @return a valid mask band.
9358 : *
9359 : *
9360 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9361 : *
9362 : */
9363 814214 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9364 :
9365 : {
9366 814214 : if (poMask != nullptr)
9367 : {
9368 714428 : if (poMask.IsOwned())
9369 : {
9370 334370 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9371 : {
9372 33697 : if (HasNoData())
9373 : {
9374 9 : InvalidateMaskBand();
9375 : }
9376 : }
9377 300673 : else if (auto poNoDataMaskBand =
9378 300673 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9379 : {
9380 412 : int bHaveNoDataRaw = FALSE;
9381 412 : bool bIsSame = false;
9382 412 : if (eDataType == GDT_Int64)
9383 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9384 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9385 10 : bHaveNoDataRaw;
9386 395 : else if (eDataType == GDT_UInt64)
9387 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9388 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9389 10 : bHaveNoDataRaw;
9390 : else
9391 : {
9392 : const double dfNoDataValue =
9393 378 : GetNoDataValue(&bHaveNoDataRaw);
9394 378 : if (bHaveNoDataRaw)
9395 : {
9396 375 : bIsSame =
9397 375 : std::isnan(dfNoDataValue)
9398 375 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9399 340 : : poNoDataMaskBand->m_dfNoDataValue ==
9400 : dfNoDataValue;
9401 : }
9402 : }
9403 412 : if (!bIsSame)
9404 23 : InvalidateMaskBand();
9405 : }
9406 : }
9407 :
9408 714428 : if (poMask)
9409 714396 : return poMask.get();
9410 : }
9411 :
9412 : /* -------------------------------------------------------------------- */
9413 : /* Check for a mask in a .msk file. */
9414 : /* -------------------------------------------------------------------- */
9415 99818 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9416 : {
9417 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9418 47 : if (poMask != nullptr)
9419 : {
9420 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9421 45 : return poMask.get();
9422 : }
9423 : }
9424 :
9425 : /* -------------------------------------------------------------------- */
9426 : /* Check for NODATA_VALUES metadata. */
9427 : /* -------------------------------------------------------------------- */
9428 99773 : if (poDS != nullptr)
9429 : {
9430 : const char *pszGDALNoDataValues =
9431 99753 : poDS->GetMetadataItem("NODATA_VALUES");
9432 99753 : if (pszGDALNoDataValues != nullptr)
9433 : {
9434 71 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9435 : pszGDALNoDataValues, " ", FALSE, FALSE);
9436 :
9437 : // Make sure we have as many values as bands.
9438 140 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9439 69 : poDS->GetRasterCount() != 0)
9440 : {
9441 : // Make sure that all bands have the same data type
9442 : // This is clearly not a fundamental condition, just a
9443 : // condition to make implementation easier.
9444 69 : GDALDataType eDT = GDT_Unknown;
9445 69 : int i = 0; // Used after for.
9446 272 : for (; i < poDS->GetRasterCount(); ++i)
9447 : {
9448 203 : if (i == 0)
9449 69 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9450 134 : else if (eDT !=
9451 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9452 : {
9453 0 : break;
9454 : }
9455 : }
9456 69 : if (i == poDS->GetRasterCount())
9457 : {
9458 69 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9459 : try
9460 : {
9461 69 : poMask.reset(
9462 138 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9463 : }
9464 0 : catch (const std::bad_alloc &)
9465 : {
9466 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9467 0 : poMask.reset();
9468 : }
9469 69 : CSLDestroy(papszGDALNoDataValues);
9470 69 : return poMask.get();
9471 : }
9472 : else
9473 : {
9474 0 : ReportError(CE_Warning, CPLE_AppDefined,
9475 : "All bands should have the same type in "
9476 : "order the NODATA_VALUES metadata item "
9477 : "to be used as a mask.");
9478 : }
9479 : }
9480 : else
9481 : {
9482 2 : ReportError(
9483 : CE_Warning, CPLE_AppDefined,
9484 : "NODATA_VALUES metadata item doesn't have the same number "
9485 : "of values as the number of bands. "
9486 : "Ignoring it for mask.");
9487 : }
9488 :
9489 2 : CSLDestroy(papszGDALNoDataValues);
9490 : }
9491 : }
9492 :
9493 : /* -------------------------------------------------------------------- */
9494 : /* Check for nodata case. */
9495 : /* -------------------------------------------------------------------- */
9496 99704 : if (HasNoData())
9497 : {
9498 1174 : nMaskFlags = GMF_NODATA;
9499 : try
9500 : {
9501 1174 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9502 : }
9503 0 : catch (const std::bad_alloc &)
9504 : {
9505 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9506 0 : poMask.reset();
9507 : }
9508 1174 : return poMask.get();
9509 : }
9510 :
9511 : /* -------------------------------------------------------------------- */
9512 : /* Check for alpha case. */
9513 : /* -------------------------------------------------------------------- */
9514 98511 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9515 197667 : this == poDS->GetRasterBand(1) &&
9516 626 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9517 : {
9518 233 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9519 : {
9520 189 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9521 189 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9522 189 : return poMask.get();
9523 : }
9524 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9525 : {
9526 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9527 : try
9528 : {
9529 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9530 46 : poDS->GetRasterBand(2)));
9531 : }
9532 0 : catch (const std::bad_alloc &)
9533 : {
9534 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9535 0 : poMask.reset();
9536 : }
9537 23 : return poMask.get();
9538 : }
9539 : }
9540 :
9541 98299 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9542 3141 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9543 197355 : this == poDS->GetRasterBand(3)) &&
9544 2454 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9545 : {
9546 1578 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9547 : {
9548 1522 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9549 1522 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9550 1522 : return poMask.get();
9551 : }
9552 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9553 : {
9554 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9555 : try
9556 : {
9557 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9558 84 : poDS->GetRasterBand(4)));
9559 : }
9560 0 : catch (const std::bad_alloc &)
9561 : {
9562 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9563 0 : poMask.reset();
9564 : }
9565 42 : return poMask.get();
9566 : }
9567 : }
9568 :
9569 : /* -------------------------------------------------------------------- */
9570 : /* Fallback to all valid case. */
9571 : /* -------------------------------------------------------------------- */
9572 96754 : nMaskFlags = GMF_ALL_VALID;
9573 : try
9574 : {
9575 96754 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9576 : }
9577 0 : catch (const std::bad_alloc &)
9578 : {
9579 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9580 0 : poMask.reset();
9581 : }
9582 :
9583 96754 : return poMask.get();
9584 : }
9585 :
9586 : /************************************************************************/
9587 : /* GDALGetMaskBand() */
9588 : /************************************************************************/
9589 :
9590 : /**
9591 : * \brief Return the mask band associated with the band.
9592 : *
9593 : * @see GDALRasterBand::GetMaskBand()
9594 : */
9595 :
9596 11049 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9597 :
9598 : {
9599 11049 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9600 :
9601 11049 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9602 11049 : return poBand->GetMaskBand();
9603 : }
9604 :
9605 : /************************************************************************/
9606 : /* GetMaskFlags() */
9607 : /************************************************************************/
9608 :
9609 : /**
9610 : * \brief Return the status flags of the mask band associated with the band.
9611 : *
9612 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9613 : * the following available definitions that may be extended in the future:
9614 : * <ul>
9615 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9616 : * 255. When used this will normally be the only flag set.
9617 : * </li>
9618 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9619 : * dataset.
9620 : * </li>
9621 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9622 : * and may have values other than 0 and 255.
9623 : * </li>
9624 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9625 : * nodata values. (mutually exclusive of GMF_ALPHA)
9626 : * </li>
9627 : * </ul>
9628 : *
9629 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9630 : * that returns one of four default implementations:
9631 : * <ul>
9632 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9633 : * </li>
9634 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9635 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9636 : * GMF_NODATA | GMF_PER_DATASET.
9637 : * </li>
9638 : * <li>If the band has a nodata value set, an instance of the new
9639 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9640 : * GMF_NODATA.
9641 : * </li>
9642 : * <li>If there is no nodata value, but the dataset has an alpha band that
9643 : * seems to apply to this band (specific rules yet to be determined) and that is
9644 : * of type GDT_UInt8 then that alpha band will be returned, and the flags
9645 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9646 : * </li>
9647 : * <li>If neither of the above apply, an instance of the new
9648 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9649 : * pixels. The null flags will return GMF_ALL_VALID.
9650 : * </li>
9651 : * </ul>
9652 : *
9653 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9654 : * dataset, with the same name as the main dataset and suffixed with .msk,
9655 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9656 : * main dataset.
9657 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9658 : * level, where xx matches the band number of a band of the main dataset. The
9659 : * value of those items is a combination of the flags GMF_ALL_VALID,
9660 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9661 : * a band, then the other rules explained above will be used to generate a
9662 : * on-the-fly mask band.
9663 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9664 : *
9665 : * This method is the same as the C function GDALGetMaskFlags().
9666 : *
9667 : *
9668 : * @return a valid mask band.
9669 : *
9670 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9671 : *
9672 : */
9673 159812 : int GDALRasterBand::GetMaskFlags()
9674 :
9675 : {
9676 : // If we don't have a band yet, force this now so that the masks value
9677 : // will be initialized.
9678 :
9679 159812 : if (poMask == nullptr)
9680 98095 : GetMaskBand();
9681 :
9682 159812 : return nMaskFlags;
9683 : }
9684 :
9685 : /************************************************************************/
9686 : /* GDALGetMaskFlags() */
9687 : /************************************************************************/
9688 :
9689 : /**
9690 : * \brief Return the status flags of the mask band associated with the band.
9691 : *
9692 : * @see GDALRasterBand::GetMaskFlags()
9693 : */
9694 :
9695 9131 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9696 :
9697 : {
9698 9131 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9699 :
9700 9131 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9701 9131 : return poBand->GetMaskFlags();
9702 : }
9703 :
9704 : /************************************************************************/
9705 : /* InvalidateMaskBand() */
9706 : /************************************************************************/
9707 :
9708 : //! @cond Doxygen_Suppress
9709 1858980 : void GDALRasterBand::InvalidateMaskBand()
9710 : {
9711 1858980 : poMask.reset();
9712 1858980 : nMaskFlags = 0;
9713 1858980 : }
9714 :
9715 : //! @endcond
9716 :
9717 : /************************************************************************/
9718 : /* CreateMaskBand() */
9719 : /************************************************************************/
9720 :
9721 : /**
9722 : * \brief Adds a mask band to the current band
9723 : *
9724 : * The default implementation of the CreateMaskBand() method is implemented
9725 : * based on similar rules to the .ovr handling implemented using the
9726 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9727 : * be created with the same basename as the original file, and it will have
9728 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9729 : * The mask images will be deflate compressed tiled images with the same
9730 : * block size as the original image if possible.
9731 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9732 : * level, where xx matches the band number of a band of the main dataset. The
9733 : * value of those items will be the one of the nFlagsIn parameter.
9734 : *
9735 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9736 : * it might be invalidated by CreateMaskBand(). So you have to call
9737 : * GetMaskBand() again.
9738 : *
9739 : * This method is the same as the C function GDALCreateMaskBand().
9740 : *
9741 : *
9742 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9743 : *
9744 : * @return CE_None on success or CE_Failure on an error.
9745 : *
9746 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9747 : * @see GDALDataset::CreateMaskBand()
9748 : *
9749 : */
9750 :
9751 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9752 :
9753 : {
9754 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9755 : {
9756 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9757 10 : if (eErr != CE_None)
9758 1 : return eErr;
9759 :
9760 9 : InvalidateMaskBand();
9761 :
9762 9 : return CE_None;
9763 : }
9764 :
9765 0 : ReportError(CE_Failure, CPLE_NotSupported,
9766 : "CreateMaskBand() not supported for this band.");
9767 :
9768 0 : return CE_Failure;
9769 : }
9770 :
9771 : /************************************************************************/
9772 : /* GDALCreateMaskBand() */
9773 : /************************************************************************/
9774 :
9775 : /**
9776 : * \brief Adds a mask band to the current band
9777 : *
9778 : * @see GDALRasterBand::CreateMaskBand()
9779 : */
9780 :
9781 36 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9782 :
9783 : {
9784 36 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9785 :
9786 36 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9787 36 : return poBand->CreateMaskBand(nFlags);
9788 : }
9789 :
9790 : /************************************************************************/
9791 : /* IsMaskBand() */
9792 : /************************************************************************/
9793 :
9794 : /**
9795 : * \brief Returns whether a band is a mask band.
9796 : *
9797 : * Mask band must be understood in the broad term: it can be a per-dataset
9798 : * mask band, an alpha band, or an implicit mask band.
9799 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9800 : *
9801 : * This method is the same as the C function GDALIsMaskBand().
9802 : *
9803 : * @return true if the band is a mask band.
9804 : *
9805 : * @see GDALDataset::CreateMaskBand()
9806 : *
9807 : * @since GDAL 3.5.0
9808 : *
9809 : */
9810 :
9811 450 : bool GDALRasterBand::IsMaskBand() const
9812 : {
9813 : // The GeoTIFF driver, among others, override this method to
9814 : // also handle external .msk bands.
9815 450 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9816 450 : GCI_AlphaBand;
9817 : }
9818 :
9819 : /************************************************************************/
9820 : /* GDALIsMaskBand() */
9821 : /************************************************************************/
9822 :
9823 : /**
9824 : * \brief Returns whether a band is a mask band.
9825 : *
9826 : * Mask band must be understood in the broad term: it can be a per-dataset
9827 : * mask band, an alpha band, or an implicit mask band.
9828 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9829 : *
9830 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9831 : *
9832 : * @return true if the band is a mask band.
9833 : *
9834 : * @see GDALRasterBand::IsMaskBand()
9835 : *
9836 : * @since GDAL 3.5.0
9837 : *
9838 : */
9839 :
9840 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9841 :
9842 : {
9843 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9844 :
9845 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9846 37 : return poBand->IsMaskBand();
9847 : }
9848 :
9849 : /************************************************************************/
9850 : /* GetMaskValueRange() */
9851 : /************************************************************************/
9852 :
9853 : /**
9854 : * \brief Returns the range of values that a mask band can take.
9855 : *
9856 : * @return the range of values that a mask band can take.
9857 : *
9858 : * @since GDAL 3.5.0
9859 : *
9860 : */
9861 :
9862 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9863 : {
9864 0 : return GMVR_UNKNOWN;
9865 : }
9866 :
9867 : /************************************************************************/
9868 : /* HasConflictingMaskSources() */
9869 : /************************************************************************/
9870 :
9871 : /**
9872 : * \brief Returns whether a raster band has conflicting mask sources.
9873 : *
9874 : * That is, if more than one of the following conditions is met:
9875 : * - it has a binary mask band (that is not an alpha band)
9876 : * - it has an external mask flags (.msk file)
9877 : * - it has a nodata value
9878 : * - it belongs to a dataset with the NODATA_VALUES metadata item set
9879 : * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
9880 : *
9881 : * @param[out] posDetailMessage Pointer to a string that will contain the
9882 : * details of the conflict.
9883 : * @param bMentionPrioritarySource Whether the mask source used should be
9884 : * mentioned in *posDetailMessage.
9885 : * @since GDAL 3.13.0
9886 : */
9887 :
9888 164 : bool GDALRasterBand::HasConflictingMaskSources(
9889 : std::string *posDetailMessage, bool bMentionPrioritarySource) const
9890 : {
9891 164 : const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
9892 : const bool bHasBinaryMaskBand =
9893 164 : ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
9894 186 : (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
9895 22 : (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
9896 164 : const bool bHasNoData = HasNoData();
9897 : const bool bHasNODATA_VALUES =
9898 164 : poDS && poDS->GetMetadataItem("NODATA_VALUES");
9899 : const bool bHasAlphaBand =
9900 324 : poDS &&
9901 160 : poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
9902 164 : GCI_AlphaBand;
9903 : const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
9904 164 : bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
9905 : const size_t nCount =
9906 164 : std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
9907 164 : if (nCount >= 2)
9908 : {
9909 23 : if (posDetailMessage)
9910 : {
9911 17 : *posDetailMessage = "Raster band ";
9912 17 : *posDetailMessage += std::to_string(nBand);
9913 17 : if (poDS && poDS->GetDescription()[0])
9914 : {
9915 11 : *posDetailMessage += " of dataset ";
9916 11 : *posDetailMessage += poDS->GetDescription();
9917 : }
9918 17 : *posDetailMessage += " has several conflicting mask sources:\n";
9919 17 : if (bHasExternalMask)
9920 1 : *posDetailMessage += "- internal binary mask band\n";
9921 17 : if (bHasExternalMask)
9922 1 : *posDetailMessage += "- external mask band (.msk)\n";
9923 17 : if (bHasNoData)
9924 13 : *posDetailMessage += "- nodata value\n";
9925 17 : if (bHasNODATA_VALUES)
9926 9 : *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
9927 17 : if (bHasAlphaBand)
9928 : *posDetailMessage +=
9929 7 : "- related to a raster band that is an alpha band\n";
9930 17 : if (bMentionPrioritarySource)
9931 : *posDetailMessage +=
9932 6 : "Only the first listed one will be taken into account.";
9933 : }
9934 23 : return true;
9935 : }
9936 141 : return false;
9937 : }
9938 :
9939 : /************************************************************************/
9940 : /* GetIndexColorTranslationTo() */
9941 : /************************************************************************/
9942 :
9943 : /**
9944 : * \brief Compute translation table for color tables.
9945 : *
9946 : * When the raster band has a palette index, it may be useful to compute
9947 : * the "translation" of this palette to the palette of another band.
9948 : * The translation tries to do exact matching first, and then approximate
9949 : * matching if no exact matching is possible.
9950 : * This method returns a table such that table[i] = j where i is an index
9951 : * of the 'this' rasterband and j the corresponding index for the reference
9952 : * rasterband.
9953 : *
9954 : * This method is thought as internal to GDAL and is used for drivers
9955 : * like RPFTOC.
9956 : *
9957 : * The implementation only supports 1-byte palette rasterbands.
9958 : *
9959 : * @param poReferenceBand the raster band
9960 : * @param pTranslationTable an already allocated translation table (at least 256
9961 : * bytes), or NULL to let the method allocate it
9962 : * @param pApproximateMatching a pointer to a flag that is set if the matching
9963 : * is approximate. May be NULL.
9964 : *
9965 : * @return a translation table if the two bands are palette index and that they
9966 : * do not match or NULL in other cases. The table must be freed with CPLFree if
9967 : * NULL was passed for pTranslationTable.
9968 : */
9969 :
9970 : unsigned char *
9971 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9972 : unsigned char *pTranslationTable,
9973 : int *pApproximateMatching)
9974 : {
9975 4 : if (poReferenceBand == nullptr)
9976 0 : return nullptr;
9977 :
9978 : // cppcheck-suppress knownConditionTrueFalse
9979 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9980 : // cppcheck-suppress knownConditionTrueFalse
9981 4 : GetColorInterpretation() == GCI_PaletteIndex &&
9982 12 : poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
9983 4 : GetRasterDataType() == GDT_UInt8)
9984 : {
9985 4 : const GDALColorTable *srcColorTable = GetColorTable();
9986 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9987 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
9988 : {
9989 4 : const int nEntries = srcColorTable->GetColorEntryCount();
9990 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
9991 :
9992 4 : int bHasNoDataValueSrc = FALSE;
9993 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9994 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9995 4 : dfNoDataValueSrc <= 255 &&
9996 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9997 0 : bHasNoDataValueSrc = FALSE;
9998 4 : const int noDataValueSrc =
9999 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10000 :
10001 4 : int bHasNoDataValueRef = FALSE;
10002 : const double dfNoDataValueRef =
10003 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10004 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10005 3 : dfNoDataValueRef <= 255 &&
10006 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10007 1 : bHasNoDataValueRef = FALSE;
10008 4 : const int noDataValueRef =
10009 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10010 :
10011 4 : bool samePalette = false;
10012 :
10013 4 : if (pApproximateMatching)
10014 3 : *pApproximateMatching = FALSE;
10015 :
10016 4 : if (nEntries == nRefEntries &&
10017 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
10018 3 : (bHasNoDataValueSrc == FALSE ||
10019 : noDataValueSrc == noDataValueRef))
10020 : {
10021 3 : samePalette = true;
10022 654 : for (int i = 0; i < nEntries; ++i)
10023 : {
10024 651 : if (noDataValueSrc == i)
10025 3 : continue;
10026 : const GDALColorEntry *entry =
10027 648 : srcColorTable->GetColorEntry(i);
10028 : const GDALColorEntry *entryRef =
10029 648 : destColorTable->GetColorEntry(i);
10030 648 : if (entry->c1 != entryRef->c1 ||
10031 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10032 : {
10033 0 : samePalette = false;
10034 : }
10035 : }
10036 : }
10037 :
10038 4 : if (!samePalette)
10039 : {
10040 1 : if (pTranslationTable == nullptr)
10041 : {
10042 : pTranslationTable = static_cast<unsigned char *>(
10043 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10044 1 : if (pTranslationTable == nullptr)
10045 1 : return nullptr;
10046 : }
10047 :
10048 : // Trying to remap the product palette on the subdataset
10049 : // palette.
10050 5 : for (int i = 0; i < nEntries; ++i)
10051 : {
10052 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10053 : noDataValueSrc == i)
10054 0 : continue;
10055 : const GDALColorEntry *entry =
10056 4 : srcColorTable->GetColorEntry(i);
10057 4 : bool bMatchFound = false;
10058 13 : for (int j = 0; j < nRefEntries; ++j)
10059 : {
10060 10 : if (bHasNoDataValueRef && noDataValueRef == j)
10061 0 : continue;
10062 : const GDALColorEntry *entryRef =
10063 10 : destColorTable->GetColorEntry(j);
10064 10 : if (entry->c1 == entryRef->c1 &&
10065 2 : entry->c2 == entryRef->c2 &&
10066 2 : entry->c3 == entryRef->c3)
10067 : {
10068 1 : pTranslationTable[i] =
10069 : static_cast<unsigned char>(j);
10070 1 : bMatchFound = true;
10071 1 : break;
10072 : }
10073 : }
10074 4 : if (!bMatchFound)
10075 : {
10076 : // No exact match. Looking for closest color now.
10077 3 : int best_j = 0;
10078 3 : int best_distance = 0;
10079 3 : if (pApproximateMatching)
10080 0 : *pApproximateMatching = TRUE;
10081 12 : for (int j = 0; j < nRefEntries; ++j)
10082 : {
10083 : const GDALColorEntry *entryRef =
10084 9 : destColorTable->GetColorEntry(j);
10085 9 : int distance = (entry->c1 - entryRef->c1) *
10086 9 : (entry->c1 - entryRef->c1) +
10087 9 : (entry->c2 - entryRef->c2) *
10088 9 : (entry->c2 - entryRef->c2) +
10089 9 : (entry->c3 - entryRef->c3) *
10090 9 : (entry->c3 - entryRef->c3);
10091 9 : if (j == 0 || distance < best_distance)
10092 : {
10093 7 : best_j = j;
10094 7 : best_distance = distance;
10095 : }
10096 : }
10097 3 : pTranslationTable[i] =
10098 : static_cast<unsigned char>(best_j);
10099 : }
10100 : }
10101 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
10102 0 : pTranslationTable[noDataValueSrc] =
10103 : static_cast<unsigned char>(noDataValueRef);
10104 :
10105 1 : return pTranslationTable;
10106 : }
10107 : }
10108 : }
10109 3 : return nullptr;
10110 : }
10111 :
10112 : /************************************************************************/
10113 : /* SetFlushBlockErr() */
10114 : /************************************************************************/
10115 :
10116 : /**
10117 : * \brief Store that an error occurred while writing a dirty block.
10118 : *
10119 : * This function stores the fact that an error occurred while writing a dirty
10120 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10121 : * flushed when the block cache get full, it is not convenient/possible to
10122 : * report that a dirty block could not be written correctly. This function
10123 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10124 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10125 : * places where the user can easily match the error with the relevant dataset.
10126 : */
10127 :
10128 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10129 : {
10130 0 : eFlushBlockErr = eErr;
10131 0 : }
10132 :
10133 : /************************************************************************/
10134 : /* IncDirtyBlocks() */
10135 : /************************************************************************/
10136 :
10137 : /**
10138 : * \brief Increment/decrement the number of dirty blocks
10139 : */
10140 :
10141 800682 : void GDALRasterBand::IncDirtyBlocks(int nInc)
10142 : {
10143 800682 : if (poBandBlockCache)
10144 800682 : poBandBlockCache->IncDirtyBlocks(nInc);
10145 800682 : }
10146 :
10147 : /************************************************************************/
10148 : /* ReportError() */
10149 : /************************************************************************/
10150 :
10151 : #ifndef DOXYGEN_XML
10152 : /**
10153 : * \brief Emits an error related to a raster band.
10154 : *
10155 : * This function is a wrapper for regular CPLError(). The only difference
10156 : * with CPLError() is that it prepends the error message with the dataset
10157 : * name and the band number.
10158 : *
10159 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10160 : * @param err_no the error number (CPLE_*) from cpl_error.h.
10161 : * @param fmt a printf() style format string. Any additional arguments
10162 : * will be treated as arguments to fill in this format in a manner
10163 : * similar to printf().
10164 : *
10165 : */
10166 :
10167 2499 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10168 : const char *fmt, ...) const
10169 : {
10170 : va_list args;
10171 :
10172 2499 : va_start(args, fmt);
10173 :
10174 2499 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
10175 2499 : pszDSName = CPLGetFilename(pszDSName);
10176 2499 : if (pszDSName[0] != '\0')
10177 : {
10178 2406 : CPLError(eErrClass, err_no, "%s",
10179 4812 : CPLString()
10180 2406 : .Printf("%s, band %d: ", pszDSName, GetBand())
10181 4812 : .append(CPLString().vPrintf(fmt, args))
10182 : .c_str());
10183 : }
10184 : else
10185 : {
10186 93 : CPLErrorV(eErrClass, err_no, fmt, args);
10187 : }
10188 :
10189 2499 : va_end(args);
10190 2499 : }
10191 : #endif
10192 :
10193 : /************************************************************************/
10194 : /* GetVirtualMemAuto() */
10195 : /************************************************************************/
10196 :
10197 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10198 : *
10199 : * Only supported on Linux and Unix systems with mmap() for now.
10200 : *
10201 : * This method allows creating a virtual memory object for a GDALRasterBand,
10202 : * that exposes the whole image data as a virtual array.
10203 : *
10204 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10205 : * specialized implementation, such as for raw files, may also directly use
10206 : * mechanisms of the operating system to create a view of the underlying file
10207 : * into virtual memory ( CPLVirtualMemFileMapNew() )
10208 : *
10209 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10210 : * offer a specialized implementation with direct file mapping, provided that
10211 : * some requirements are met :
10212 : * - for all drivers, the dataset must be backed by a "real" file in the file
10213 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10214 : * must match the native ordering of the CPU.
10215 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10216 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10217 : * the file in sequential order, and be equally spaced (which is generally the
10218 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10219 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10220 : *
10221 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
10222 : * CPLVirtualMemFree() must be called before the raster band object is
10223 : * destroyed.
10224 : *
10225 : * If p is such a pointer and base_type the type matching
10226 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10227 : * accessed with
10228 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10229 : *
10230 : * This method is the same as the C GDALGetVirtualMemAuto() function.
10231 : *
10232 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10233 : * read/write the band.
10234 : *
10235 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
10236 : * one pixel value in the buffer to the start of the next pixel value within a
10237 : * scanline.
10238 : *
10239 : * @param pnLineSpace Output parameter giving the byte offset from the start of
10240 : * one scanline in the buffer to the start of the next.
10241 : *
10242 : * @param papszOptions NULL terminated list of options.
10243 : * If a specialized implementation exists, defining
10244 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10245 : * used. On the contrary, defining
10246 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10247 : * being used (thus only allowing efficient implementations to be used). When
10248 : * requiring or falling back to the default implementation, the following
10249 : * options are available : CACHE_SIZE (in bytes, defaults to
10250 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10251 : * to FALSE)
10252 : *
10253 : * @return a virtual memory object that must be unreferenced by
10254 : * CPLVirtualMemFree(), or NULL in case of failure.
10255 : *
10256 : */
10257 :
10258 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10259 : int *pnPixelSpace,
10260 : GIntBig *pnLineSpace,
10261 : CSLConstList papszOptions)
10262 : {
10263 9 : const char *pszImpl = CSLFetchNameValueDef(
10264 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10265 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10266 8 : EQUAL(pszImpl, "FALSE"))
10267 : {
10268 1 : return nullptr;
10269 : }
10270 :
10271 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10272 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10273 8 : if (pnPixelSpace)
10274 8 : *pnPixelSpace = nPixelSpace;
10275 8 : if (pnLineSpace)
10276 8 : *pnLineSpace = nLineSpace;
10277 : const size_t nCacheSize =
10278 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10279 : const size_t nPageSizeHint =
10280 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10281 8 : const bool bSingleThreadUsage = CPLTestBool(
10282 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10283 8 : return GDALRasterBandGetVirtualMem(
10284 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10285 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10286 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10287 8 : papszOptions);
10288 : }
10289 :
10290 : /************************************************************************/
10291 : /* GDALGetVirtualMemAuto() */
10292 : /************************************************************************/
10293 :
10294 : /**
10295 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10296 : *
10297 : * @see GDALRasterBand::GetVirtualMemAuto()
10298 : */
10299 :
10300 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10301 : int *pnPixelSpace, GIntBig *pnLineSpace,
10302 : CSLConstList papszOptions)
10303 : {
10304 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10305 :
10306 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10307 :
10308 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10309 31 : const_cast<char **>(papszOptions));
10310 : }
10311 :
10312 : /************************************************************************/
10313 : /* GDALGetDataCoverageStatus() */
10314 : /************************************************************************/
10315 :
10316 : /**
10317 : * \brief Get the coverage status of a sub-window of the raster.
10318 : *
10319 : * Returns whether a sub-window of the raster contains only data, only empty
10320 : * blocks or a mix of both. This function can be used to determine quickly
10321 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10322 : * be sparse.
10323 : *
10324 : * Empty blocks are blocks that are generally not physically present in the
10325 : * file, and when read through GDAL, contain only pixels whose value is the
10326 : * nodata value when it is set, or whose value is 0 when the nodata value is
10327 : * not set.
10328 : *
10329 : * The query is done in an efficient way without reading the actual pixel
10330 : * values. If not possible, or not implemented at all by the driver,
10331 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10332 : * be returned.
10333 : *
10334 : * The values that can be returned by the function are the following,
10335 : * potentially combined with the binary or operator :
10336 : * <ul>
10337 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10338 : * GetDataCoverageStatus(). This flag should be returned together with
10339 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10340 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10341 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10342 : * the queried window. This is typically identified by the concept of missing
10343 : * block in formats that supports it.
10344 : * </li>
10345 : * </ul>
10346 : *
10347 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10348 : * should be interpreted more as hint of potential presence of data. For example
10349 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10350 : * nodata value), instead of using the missing block mechanism,
10351 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10352 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10353 : *
10354 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10355 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10356 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10357 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10358 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10359 : * the function will exit, so that you can potentially refine the requested area
10360 : * to find which particular region(s) have missing blocks.
10361 : *
10362 : * @see GDALRasterBand::GetDataCoverageStatus()
10363 : *
10364 : * @param hBand raster band
10365 : *
10366 : * @param nXOff The pixel offset to the top left corner of the region
10367 : * of the band to be queried. This would be zero to start from the left side.
10368 : *
10369 : * @param nYOff The line offset to the top left corner of the region
10370 : * of the band to be queried. This would be zero to start from the top.
10371 : *
10372 : * @param nXSize The width of the region of the band to be queried in pixels.
10373 : *
10374 : * @param nYSize The height of the region of the band to be queried in lines.
10375 : *
10376 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10377 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10378 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10379 : * as the computation of the coverage matches the mask, the computation will be
10380 : * stopped. *pdfDataPct will not be valid in that case.
10381 : *
10382 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10383 : * to the (approximate) percentage in [0,100] of pixels in the queried
10384 : * sub-window that have valid values. The implementation might not always be
10385 : * able to compute it, in which case it will be set to a negative value.
10386 : *
10387 : * @return a binary-or'ed combination of possible values
10388 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10389 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10390 : */
10391 :
10392 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10393 : int nYOff, int nXSize, int nYSize,
10394 : int nMaskFlagStop, double *pdfDataPct)
10395 : {
10396 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10397 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10398 :
10399 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10400 :
10401 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10402 29 : nMaskFlagStop, pdfDataPct);
10403 : }
10404 :
10405 : /************************************************************************/
10406 : /* GetDataCoverageStatus() */
10407 : /************************************************************************/
10408 :
10409 : /**
10410 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10411 : * int nYOff,
10412 : * int nXSize,
10413 : * int nYSize,
10414 : * int nMaskFlagStop,
10415 : * double* pdfDataPct)
10416 : * \brief Get the coverage status of a sub-window of the raster.
10417 : *
10418 : * Returns whether a sub-window of the raster contains only data, only empty
10419 : * blocks or a mix of both. This function can be used to determine quickly
10420 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10421 : * be sparse.
10422 : *
10423 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10424 : * value when it is set, or whose value is 0 when the nodata value is not set.
10425 : *
10426 : * The query is done in an efficient way without reading the actual pixel
10427 : * values. If not possible, or not implemented at all by the driver,
10428 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10429 : * be returned.
10430 : *
10431 : * The values that can be returned by the function are the following,
10432 : * potentially combined with the binary or operator :
10433 : * <ul>
10434 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10435 : * GetDataCoverageStatus(). This flag should be returned together with
10436 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10437 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10438 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10439 : * the queried window. This is typically identified by the concept of missing
10440 : * block in formats that supports it.
10441 : * </li>
10442 : * </ul>
10443 : *
10444 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10445 : * should be interpreted more as hint of potential presence of data. For example
10446 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10447 : * nodata value), instead of using the missing block mechanism,
10448 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10449 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10450 : *
10451 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10452 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10453 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10454 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10455 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10456 : * the function will exit, so that you can potentially refine the requested area
10457 : * to find which particular region(s) have missing blocks.
10458 : *
10459 : * @see GDALGetDataCoverageStatus()
10460 : *
10461 : * @param nXOff The pixel offset to the top left corner of the region
10462 : * of the band to be queried. This would be zero to start from the left side.
10463 : *
10464 : * @param nYOff The line offset to the top left corner of the region
10465 : * of the band to be queried. This would be zero to start from the top.
10466 : *
10467 : * @param nXSize The width of the region of the band to be queried in pixels.
10468 : *
10469 : * @param nYSize The height of the region of the band to be queried in lines.
10470 : *
10471 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10472 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10473 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10474 : * as the computation of the coverage matches the mask, the computation will be
10475 : * stopped. *pdfDataPct will not be valid in that case.
10476 : *
10477 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10478 : * to the (approximate) percentage in [0,100] of pixels in the queried
10479 : * sub-window that have valid values. The implementation might not always be
10480 : * able to compute it, in which case it will be set to a negative value.
10481 : *
10482 : * @return a binary-or'ed combination of possible values
10483 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10484 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10485 : */
10486 :
10487 : /**
10488 : * \brief Get the coverage status of a sub-window of the raster.
10489 : *
10490 : * Returns whether a sub-window of the raster contains only data, only empty
10491 : * blocks or a mix of both. This function can be used to determine quickly
10492 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10493 : * be sparse.
10494 : *
10495 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10496 : * value when it is set, or whose value is 0 when the nodata value is not set.
10497 : *
10498 : * The query is done in an efficient way without reading the actual pixel
10499 : * values. If not possible, or not implemented at all by the driver,
10500 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10501 : * be returned.
10502 : *
10503 : * The values that can be returned by the function are the following,
10504 : * potentially combined with the binary or operator :
10505 : * <ul>
10506 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10507 : * GetDataCoverageStatus(). This flag should be returned together with
10508 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10509 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10510 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10511 : * the queried window. This is typically identified by the concept of missing
10512 : * block in formats that supports it.
10513 : * </li>
10514 : * </ul>
10515 : *
10516 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10517 : * should be interpreted more as hint of potential presence of data. For example
10518 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10519 : * nodata value), instead of using the missing block mechanism,
10520 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10521 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10522 : *
10523 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10524 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10525 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10526 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10527 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10528 : * the function will exit, so that you can potentially refine the requested area
10529 : * to find which particular region(s) have missing blocks.
10530 : *
10531 : * @see GDALGetDataCoverageStatus()
10532 : *
10533 : * @param nXOff The pixel offset to the top left corner of the region
10534 : * of the band to be queried. This would be zero to start from the left side.
10535 : *
10536 : * @param nYOff The line offset to the top left corner of the region
10537 : * of the band to be queried. This would be zero to start from the top.
10538 : *
10539 : * @param nXSize The width of the region of the band to be queried in pixels.
10540 : *
10541 : * @param nYSize The height of the region of the band to be queried in lines.
10542 : *
10543 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10544 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10545 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10546 : * as the computation of the coverage matches the mask, the computation will be
10547 : * stopped. *pdfDataPct will not be valid in that case.
10548 : *
10549 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10550 : * to the (approximate) percentage in [0,100] of pixels in the queried
10551 : * sub-window that have valid values. The implementation might not always be
10552 : * able to compute it, in which case it will be set to a negative value.
10553 : *
10554 : * @return a binary-or'ed combination of possible values
10555 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10556 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10557 : */
10558 :
10559 4723 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10560 : int nYSize, int nMaskFlagStop,
10561 : double *pdfDataPct)
10562 : {
10563 4723 : if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10564 4723 : nYSize > nRasterYSize - nYOff)
10565 : {
10566 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10567 0 : if (pdfDataPct)
10568 0 : *pdfDataPct = 0.0;
10569 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10570 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10571 : }
10572 4723 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10573 4723 : pdfDataPct);
10574 : }
10575 :
10576 : /************************************************************************/
10577 : /* IGetDataCoverageStatus() */
10578 : /************************************************************************/
10579 :
10580 690 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10581 : int /*nXSize*/, int /*nYSize*/,
10582 : int /*nMaskFlagStop*/,
10583 : double *pdfDataPct)
10584 : {
10585 690 : if (pdfDataPct != nullptr)
10586 0 : *pdfDataPct = 100.0;
10587 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10588 690 : GDAL_DATA_COVERAGE_STATUS_DATA;
10589 : }
10590 :
10591 : //! @cond Doxygen_Suppress
10592 : /************************************************************************/
10593 : /* EnterReadWrite() */
10594 : /************************************************************************/
10595 :
10596 7818120 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10597 : {
10598 7818120 : if (poDS != nullptr)
10599 7050620 : return poDS->EnterReadWrite(eRWFlag);
10600 767502 : return FALSE;
10601 : }
10602 :
10603 : /************************************************************************/
10604 : /* LeaveReadWrite() */
10605 : /************************************************************************/
10606 :
10607 1135070 : void GDALRasterBand::LeaveReadWrite()
10608 : {
10609 1135070 : if (poDS != nullptr)
10610 1135070 : poDS->LeaveReadWrite();
10611 1135070 : }
10612 :
10613 : /************************************************************************/
10614 : /* InitRWLock() */
10615 : /************************************************************************/
10616 :
10617 3980450 : void GDALRasterBand::InitRWLock()
10618 : {
10619 3980450 : if (poDS != nullptr)
10620 3980050 : poDS->InitRWLock();
10621 3980450 : }
10622 :
10623 : //! @endcond
10624 :
10625 : // clang-format off
10626 :
10627 : /**
10628 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10629 : * \brief Set metadata.
10630 : *
10631 : * CAUTION: depending on the format, older values of the updated information
10632 : * might still be found in the file in a "ghost" state, even if no longer
10633 : * accessible through the GDAL API. This is for example the case of the GTiff
10634 : * format (this is not a exhaustive list)
10635 : *
10636 : * The C function GDALSetMetadata() does the same thing as this method.
10637 : *
10638 : * @param papszMetadata the metadata in name=value string list format to
10639 : * apply.
10640 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10641 : * domain.
10642 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10643 : * metadata has been accepted, but is likely not maintained persistently
10644 : * by the underlying object between sessions.
10645 : */
10646 :
10647 : /**
10648 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10649 : * \brief Set single metadata item.
10650 : *
10651 : * CAUTION: depending on the format, older values of the updated information
10652 : * might still be found in the file in a "ghost" state, even if no longer
10653 : * accessible through the GDAL API. This is for example the case of the GTiff
10654 : * format (this is not a exhaustive list)
10655 : *
10656 : * The C function GDALSetMetadataItem() does the same thing as this method.
10657 : *
10658 : * @param pszName the key for the metadata item to fetch.
10659 : * @param pszValue the value to assign to the key.
10660 : * @param pszDomain the domain to set within, use NULL for the default domain.
10661 : *
10662 : * @return CE_None on success, or an error code on failure.
10663 : */
10664 :
10665 : // clang-format on
10666 :
10667 : //! @cond Doxygen_Suppress
10668 : /************************************************************************/
10669 : /* EnablePixelTypeSignedByteWarning() */
10670 : /************************************************************************/
10671 :
10672 157381 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10673 : {
10674 157381 : m_bEnablePixelTypeSignedByteWarning = b;
10675 157381 : }
10676 :
10677 4920 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10678 : {
10679 4920 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10680 4920 : }
10681 :
10682 : //! @endcond
10683 :
10684 : /************************************************************************/
10685 : /* GetMetadataItem() */
10686 : /************************************************************************/
10687 :
10688 621986 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10689 : const char *pszDomain)
10690 : {
10691 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10692 621986 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10693 462880 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10694 322247 : EQUAL(pszName, "PIXELTYPE"))
10695 : {
10696 2 : CPLError(CE_Warning, CPLE_AppDefined,
10697 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10698 : "used to signal signed 8-bit raster. Change your code to "
10699 : "test for the new GDT_Int8 data type instead.");
10700 : }
10701 621986 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10702 : }
10703 :
10704 : /************************************************************************/
10705 : /* WindowIterator */
10706 : /************************************************************************/
10707 :
10708 : //! @cond Doxygen_Suppress
10709 :
10710 692 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10711 : int nRasterYSize,
10712 : int nBlockXSize, int nBlockYSize,
10713 692 : int nRow, int nCol)
10714 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10715 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10716 692 : m_col(nCol)
10717 : {
10718 692 : }
10719 :
10720 751 : bool GDALRasterBand::WindowIterator::operator==(
10721 : const WindowIterator &other) const
10722 : {
10723 310 : return m_row == other.m_row && m_col == other.m_col &&
10724 310 : m_nRasterXSize == other.m_nRasterXSize &&
10725 310 : m_nRasterYSize == other.m_nRasterYSize &&
10726 1371 : m_nBlockXSize == other.m_nBlockXSize &&
10727 1061 : m_nBlockYSize == other.m_nBlockYSize;
10728 : }
10729 :
10730 725 : bool GDALRasterBand::WindowIterator::operator!=(
10731 : const WindowIterator &other) const
10732 : {
10733 725 : return !(*this == other);
10734 : }
10735 :
10736 : GDALRasterBand::WindowIterator::value_type
10737 440 : GDALRasterBand::WindowIterator::operator*() const
10738 : {
10739 : GDALRasterWindow ret;
10740 440 : ret.nXOff = m_col * m_nBlockXSize;
10741 440 : ret.nYOff = m_row * m_nBlockYSize;
10742 440 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10743 440 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10744 :
10745 440 : return ret;
10746 : }
10747 :
10748 431 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10749 : {
10750 431 : m_col++;
10751 431 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10752 : {
10753 335 : m_col = 0;
10754 335 : m_row++;
10755 : }
10756 431 : return *this;
10757 : }
10758 :
10759 163 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10760 163 : const GDALRasterBand &band, size_t maxSize)
10761 163 : : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10762 163 : band.nBlockYSize, maxSize)
10763 : {
10764 163 : }
10765 :
10766 200 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10767 200 : const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10768 200 : : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10769 200 : std::min(band1.GetYSize(), band2.GetYSize()),
10770 200 : std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10771 200 : std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10772 600 : maxSize)
10773 : {
10774 400 : if (band1.GetXSize() != band2.GetXSize() ||
10775 200 : band1.GetYSize() != band2.GetYSize())
10776 : {
10777 0 : CPLError(CE_Warning, CPLE_AppDefined,
10778 : "WindowIteratorWrapper called on bands of different "
10779 : "dimensions. Selecting smallest one");
10780 : }
10781 200 : }
10782 :
10783 363 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10784 : int nRasterYSize,
10785 : int nBlockXSize,
10786 : int nBlockYSize,
10787 363 : size_t maxSize)
10788 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10789 363 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10790 : {
10791 : #ifdef CSA_BUILD
10792 : assert(this);
10793 : #endif
10794 363 : int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10795 363 : int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10796 :
10797 363 : if (nXSize < 1 || nYSize < 1)
10798 : {
10799 : // If invalid block size is reported, assume scanlines
10800 8 : nXSize = m_nRasterXSize;
10801 8 : nYSize = 1;
10802 : }
10803 :
10804 363 : if (maxSize == 0)
10805 : {
10806 69 : m_nBlockXSize = nXSize;
10807 69 : m_nBlockYSize = nYSize;
10808 69 : return;
10809 : }
10810 :
10811 294 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10812 294 : const double dfBlocksPerChunk =
10813 294 : static_cast<double>(maxSize) /
10814 294 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10815 :
10816 294 : if (dfBlocksPerChunk < dfBlocksPerRow)
10817 : {
10818 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10819 14 : m_nRasterXSize,
10820 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10821 14 : m_nBlockYSize = nYSize;
10822 : }
10823 : else
10824 : {
10825 280 : m_nBlockXSize = m_nRasterXSize;
10826 280 : m_nBlockYSize = static_cast<int>(std::min<double>(
10827 280 : m_nRasterYSize,
10828 280 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10829 : }
10830 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10831 : {
10832 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10833 : {
10834 : m_nBlockXSize = m_nRasterXSize;
10835 : m_nBlockYSize = 1;
10836 : }
10837 : }
10838 : }
10839 :
10840 : GDALRasterBand::WindowIterator
10841 332 : GDALRasterBand::WindowIteratorWrapper::begin() const
10842 : {
10843 332 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10844 332 : m_nBlockYSize, 0, 0);
10845 : }
10846 :
10847 : GDALRasterBand::WindowIterator
10848 332 : GDALRasterBand::WindowIteratorWrapper::end() const
10849 : {
10850 332 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10851 332 : m_nBlockYSize,
10852 332 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10853 : }
10854 :
10855 63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10856 : {
10857 63 : return static_cast<uint64_t>(
10858 63 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10859 63 : static_cast<uint64_t>(
10860 63 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10861 : }
10862 :
10863 : //! @endcond
10864 :
10865 : /** Return an object whose begin() and end() methods can be used to iterate
10866 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10867 : * band. The iteration order is from left to right, then from top to bottom.
10868 : *
10869 : \code{.cpp}
10870 : std::vector<double> pixelValues;
10871 : for (const auto& window : poBand->IterateWindows()) {
10872 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10873 : window.nXSize, window.nYSize);
10874 : // check eErr
10875 : }
10876 : \endcode
10877 : *
10878 : *
10879 : * @param maxSize The maximum number of pixels in each window. If set to
10880 : * zero (the default), or a number smaller than the block size,
10881 : * the window size will be the same as the block size.
10882 : * @since GDAL 3.12
10883 : */
10884 : GDALRasterBand::WindowIteratorWrapper
10885 163 : GDALRasterBand::IterateWindows(size_t maxSize) const
10886 : {
10887 163 : return WindowIteratorWrapper(*this, maxSize);
10888 : }
10889 :
10890 : /************************************************************************/
10891 : /* MayMultiBlockReadingBeMultiThreaded() */
10892 : /************************************************************************/
10893 :
10894 : /** Return whether a RasterIO(GF_Read) request spanning over multiple
10895 : * blocks may be accelerated internally using multi-threading.
10896 : *
10897 : * This can be used to determine the best chunk size to read a raster band.
10898 : *
10899 : * Note that such optimizations may require that the window is perfectly aligned
10900 : * on block boundaries and does not involve resampling or data type translation
10901 : * occurs, etc.
10902 : *
10903 : * @since GDAL 3.13
10904 : */
10905 0 : bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
10906 : {
10907 0 : return false;
10908 : }
10909 :
10910 : /************************************************************************/
10911 : /* GDALMDArrayFromRasterBand */
10912 : /************************************************************************/
10913 :
10914 : class GDALMDArrayFromRasterBand final : public GDALMDArray
10915 : {
10916 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10917 :
10918 : GDALDataset *m_poDS;
10919 : GDALRasterBand *m_poBand;
10920 : GDALExtendedDataType m_dt;
10921 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10922 : std::string m_osUnit;
10923 : std::vector<GByte> m_pabyNoData{};
10924 : std::shared_ptr<GDALMDArray> m_varX{};
10925 : std::shared_ptr<GDALMDArray> m_varY{};
10926 : std::string m_osFilename{};
10927 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
10928 :
10929 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10930 : const size_t *count, const GInt64 *arrayStep,
10931 : const GPtrDiff_t *bufferStride,
10932 : const GDALExtendedDataType &bufferDataType,
10933 : void *pBuffer) const;
10934 :
10935 : protected:
10936 36 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10937 72 : : GDALAbstractMDArray(std::string(),
10938 72 : std::string(poDS->GetDescription()) +
10939 : CPLSPrintf(" band %d", poBand->GetBand())),
10940 72 : GDALMDArray(std::string(),
10941 72 : std::string(poDS->GetDescription()) +
10942 : CPLSPrintf(" band %d", poBand->GetBand())),
10943 : m_poDS(poDS), m_poBand(poBand),
10944 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10945 180 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10946 : {
10947 36 : m_poDS->Reference();
10948 :
10949 36 : int bHasNoData = false;
10950 36 : if (m_poBand->GetRasterDataType() == GDT_Int64)
10951 : {
10952 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10953 0 : if (bHasNoData)
10954 : {
10955 0 : m_pabyNoData.resize(m_dt.GetSize());
10956 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10957 : m_dt.GetNumericDataType(), 0, 1);
10958 : }
10959 : }
10960 36 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10961 : {
10962 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10963 0 : if (bHasNoData)
10964 : {
10965 0 : m_pabyNoData.resize(m_dt.GetSize());
10966 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10967 : m_dt.GetNumericDataType(), 0, 1);
10968 : }
10969 : }
10970 : else
10971 : {
10972 36 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10973 36 : if (bHasNoData)
10974 : {
10975 1 : m_pabyNoData.resize(m_dt.GetSize());
10976 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10977 : m_dt.GetNumericDataType(), 0, 1);
10978 : }
10979 : }
10980 :
10981 36 : const int nXSize = poBand->GetXSize();
10982 36 : const int nYSize = poBand->GetYSize();
10983 :
10984 36 : auto poSRS = m_poDS->GetSpatialRef();
10985 72 : std::string osTypeY;
10986 72 : std::string osTypeX;
10987 72 : std::string osDirectionY;
10988 72 : std::string osDirectionX;
10989 36 : if (poSRS && poSRS->GetAxesCount() == 2)
10990 : {
10991 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10992 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
10993 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
10994 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
10995 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
10996 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10997 : {
10998 8 : if (mapping == std::vector<int>{1, 2})
10999 : {
11000 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11001 8 : osDirectionY = "NORTH";
11002 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11003 8 : osDirectionX = "EAST";
11004 : }
11005 : }
11006 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11007 : {
11008 16 : if (mapping == std::vector<int>{2, 1})
11009 : {
11010 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11011 16 : osDirectionY = "NORTH";
11012 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11013 16 : osDirectionX = "EAST";
11014 : }
11015 : }
11016 : }
11017 :
11018 180 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11019 : "/", "Y", osTypeY, osDirectionY, nYSize),
11020 72 : std::make_shared<GDALDimensionWeakIndexingVar>(
11021 108 : "/", "X", osTypeX, osDirectionX, nXSize)};
11022 :
11023 36 : GDALGeoTransform gt;
11024 36 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
11025 : {
11026 50 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
11027 50 : gt[0], gt[1], 0.5);
11028 25 : m_dims[1]->SetIndexingVariable(m_varX);
11029 :
11030 50 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
11031 50 : gt[3], gt[5], 0.5);
11032 25 : m_dims[0]->SetIndexingVariable(m_varY);
11033 : }
11034 36 : }
11035 :
11036 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11037 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11038 : const GDALExtendedDataType &bufferDataType,
11039 : void *pDstBuffer) const override;
11040 :
11041 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11042 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11043 : const GDALExtendedDataType &bufferDataType,
11044 : const void *pSrcBuffer) override
11045 : {
11046 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11047 : bufferStride, bufferDataType,
11048 1 : const_cast<void *>(pSrcBuffer));
11049 : }
11050 :
11051 : public:
11052 72 : ~GDALMDArrayFromRasterBand() override
11053 36 : {
11054 36 : m_poDS->ReleaseRef();
11055 72 : }
11056 :
11057 36 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11058 : GDALRasterBand *poBand)
11059 : {
11060 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11061 72 : new GDALMDArrayFromRasterBand(poDS, poBand)));
11062 36 : array->SetSelf(array);
11063 72 : return array;
11064 : }
11065 :
11066 5 : bool IsWritable() const override
11067 : {
11068 5 : return m_poDS->GetAccess() == GA_Update;
11069 : }
11070 :
11071 122 : const std::string &GetFilename() const override
11072 : {
11073 122 : return m_osFilename;
11074 : }
11075 :
11076 : const std::vector<std::shared_ptr<GDALDimension>> &
11077 345 : GetDimensions() const override
11078 : {
11079 345 : return m_dims;
11080 : }
11081 :
11082 158 : const GDALExtendedDataType &GetDataType() const override
11083 : {
11084 158 : return m_dt;
11085 : }
11086 :
11087 5 : const std::string &GetUnit() const override
11088 : {
11089 5 : return m_osUnit;
11090 : }
11091 :
11092 32 : const void *GetRawNoDataValue() const override
11093 : {
11094 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11095 : }
11096 :
11097 4 : double GetOffset(bool *pbHasOffset,
11098 : GDALDataType *peStorageType) const override
11099 : {
11100 4 : int bHasOffset = false;
11101 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
11102 4 : if (pbHasOffset)
11103 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11104 4 : if (peStorageType)
11105 1 : *peStorageType = GDT_Unknown;
11106 4 : return dfRes;
11107 : }
11108 :
11109 4 : double GetScale(bool *pbHasScale,
11110 : GDALDataType *peStorageType) const override
11111 : {
11112 4 : int bHasScale = false;
11113 4 : double dfRes = m_poBand->GetScale(&bHasScale);
11114 4 : if (pbHasScale)
11115 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
11116 4 : if (peStorageType)
11117 1 : *peStorageType = GDT_Unknown;
11118 4 : return dfRes;
11119 : }
11120 :
11121 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11122 : {
11123 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
11124 88 : if (!poSrcSRS)
11125 2 : return nullptr;
11126 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11127 :
11128 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11129 86 : constexpr int iYDim = 0;
11130 86 : constexpr int iXDim = 1;
11131 258 : for (auto &m : axisMapping)
11132 : {
11133 172 : if (m == 1)
11134 86 : m = iXDim + 1;
11135 86 : else if (m == 2)
11136 86 : m = iYDim + 1;
11137 : else
11138 0 : m = 0;
11139 : }
11140 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11141 86 : return poSRS;
11142 : }
11143 :
11144 32 : std::vector<GUInt64> GetBlockSize() const override
11145 : {
11146 32 : int nBlockXSize = 0;
11147 32 : int nBlockYSize = 0;
11148 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11149 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11150 32 : static_cast<GUInt64>(nBlockXSize)};
11151 : }
11152 :
11153 : std::vector<std::shared_ptr<GDALAttribute>>
11154 23 : GetAttributes(CSLConstList) const override
11155 : {
11156 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
11157 23 : auto papszMD = m_poBand->GetMetadata();
11158 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
11159 : {
11160 2 : char *pszKey = nullptr;
11161 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11162 2 : if (pszKey && pszValue)
11163 : {
11164 : res.emplace_back(
11165 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11166 : }
11167 2 : CPLFree(pszKey);
11168 : }
11169 23 : return res;
11170 : }
11171 :
11172 6 : int GetOverviewCount() const override
11173 : {
11174 6 : return m_poBand->GetOverviewCount();
11175 : }
11176 :
11177 4 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11178 : {
11179 4 : const int nOverviews = GetOverviewCount();
11180 4 : if (idx < 0 || idx >= nOverviews)
11181 2 : return nullptr;
11182 2 : m_apoOverviews.resize(nOverviews);
11183 2 : if (!m_apoOverviews[idx])
11184 : {
11185 1 : if (auto poOvrBand = m_poBand->GetOverview(idx))
11186 : {
11187 1 : if (auto poOvrDS = poOvrBand->GetDataset())
11188 : {
11189 1 : m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11190 : }
11191 : }
11192 : }
11193 2 : return m_apoOverviews[idx];
11194 : }
11195 : };
11196 :
11197 39 : bool GDALMDArrayFromRasterBand::IRead(
11198 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11199 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11200 : void *pDstBuffer) const
11201 : {
11202 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11203 39 : bufferDataType, pDstBuffer);
11204 : }
11205 :
11206 : /************************************************************************/
11207 : /* ReadWrite() */
11208 : /************************************************************************/
11209 :
11210 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
11211 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11212 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11213 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11214 : {
11215 40 : constexpr size_t iDimX = 1;
11216 40 : constexpr size_t iDimY = 0;
11217 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11218 : arrayStartIdx, count, arrayStep, bufferStride,
11219 40 : bufferDataType, pBuffer);
11220 : }
11221 :
11222 : /************************************************************************/
11223 : /* GDALMDRasterIOFromBand() */
11224 : /************************************************************************/
11225 :
11226 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11227 : size_t iDimX, size_t iDimY,
11228 : const GUInt64 *arrayStartIdx, const size_t *count,
11229 : const GInt64 *arrayStep,
11230 : const GPtrDiff_t *bufferStride,
11231 : const GDALExtendedDataType &bufferDataType,
11232 : void *pBuffer)
11233 : {
11234 73 : const auto eDT(bufferDataType.GetNumericDataType());
11235 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11236 73 : const int nX =
11237 73 : arrayStep[iDimX] > 0
11238 73 : ? static_cast<int>(arrayStartIdx[iDimX])
11239 2 : : static_cast<int>(arrayStartIdx[iDimX] -
11240 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
11241 73 : const int nY =
11242 73 : arrayStep[iDimY] > 0
11243 73 : ? static_cast<int>(arrayStartIdx[iDimY])
11244 6 : : static_cast<int>(arrayStartIdx[iDimY] -
11245 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
11246 73 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
11247 73 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
11248 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11249 73 : int nStrideXSign = 1;
11250 73 : if (arrayStep[iDimX] < 0)
11251 : {
11252 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11253 2 : nStrideXSign = -1;
11254 : }
11255 73 : int nStrideYSign = 1;
11256 73 : if (arrayStep[iDimY] < 0)
11257 : {
11258 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11259 6 : nStrideYSign = -1;
11260 : }
11261 :
11262 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11263 73 : static_cast<int>(count[iDimX]),
11264 73 : static_cast<int>(count[iDimY]), eDT,
11265 : static_cast<GSpacing>(
11266 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
11267 : static_cast<GSpacing>(
11268 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
11269 73 : nullptr) == CE_None;
11270 : }
11271 :
11272 : /************************************************************************/
11273 : /* AsMDArray() */
11274 : /************************************************************************/
11275 :
11276 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11277 : *
11278 : * The band must be linked to a GDALDataset. If this dataset is not already
11279 : * marked as shared, it will be, so that the returned array holds a reference
11280 : * to it.
11281 : *
11282 : * If the dataset has a geotransform attached, the X and Y dimensions of the
11283 : * returned array will have an associated indexing variable.
11284 : *
11285 : * This is the same as the C function GDALRasterBandAsMDArray().
11286 : *
11287 : * The "reverse" method is GDALMDArray::AsClassicDataset().
11288 : *
11289 : * @return a new array, or nullptr.
11290 : *
11291 : * @since GDAL 3.1
11292 : */
11293 35 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11294 : {
11295 35 : if (!poDS)
11296 : {
11297 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11298 0 : return nullptr;
11299 : }
11300 35 : if (!poDS->GetShared())
11301 : {
11302 33 : poDS->MarkAsShared();
11303 : }
11304 : return GDALMDArrayFromRasterBand::Create(
11305 35 : poDS, const_cast<GDALRasterBand *>(this));
11306 : }
11307 :
11308 : /************************************************************************/
11309 : /* InterpolateAtPoint() */
11310 : /************************************************************************/
11311 :
11312 : /**
11313 : * \brief Interpolates the value between pixels using a resampling algorithm,
11314 : * taking pixel/line coordinates as input.
11315 : *
11316 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11317 : * @param dfLine line coordinate as a double, where interpolation should be done.
11318 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11319 : * @param pdfRealValue pointer to real part of interpolated value
11320 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11321 : *
11322 : * @return CE_None on success, or an error code on failure.
11323 : * @since GDAL 3.10
11324 : */
11325 :
11326 168 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11327 : GDALRIOResampleAlg eInterpolation,
11328 : double *pdfRealValue,
11329 : double *pdfImagValue) const
11330 : {
11331 168 : if (eInterpolation != GRIORA_NearestNeighbour &&
11332 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11333 : eInterpolation != GRIORA_CubicSpline)
11334 : {
11335 2 : CPLError(CE_Failure, CPLE_AppDefined,
11336 : "Only nearest, bilinear, cubic and cubicspline interpolation "
11337 : "methods "
11338 : "allowed");
11339 :
11340 2 : return CE_Failure;
11341 : }
11342 :
11343 166 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11344 166 : if (!m_poPointsCache)
11345 86 : m_poPointsCache = new GDALDoublePointsCache();
11346 :
11347 : const bool res =
11348 166 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11349 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
11350 :
11351 166 : return res ? CE_None : CE_Failure;
11352 : }
11353 :
11354 : /************************************************************************/
11355 : /* GDALRasterInterpolateAtPoint() */
11356 : /************************************************************************/
11357 :
11358 : /**
11359 : * \brief Interpolates the value between pixels using
11360 : * a resampling algorithm
11361 : *
11362 : * @see GDALRasterBand::InterpolateAtPoint()
11363 : * @since GDAL 3.10
11364 : */
11365 :
11366 145 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11367 : double dfLine,
11368 : GDALRIOResampleAlg eInterpolation,
11369 : double *pdfRealValue, double *pdfImagValue)
11370 : {
11371 145 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11372 :
11373 145 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11374 145 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11375 145 : pdfRealValue, pdfImagValue);
11376 : }
11377 :
11378 : /************************************************************************/
11379 : /* InterpolateAtGeolocation() */
11380 : /************************************************************************/
11381 :
11382 : /**
11383 : * \brief Interpolates the value between pixels using a resampling algorithm,
11384 : * taking georeferenced coordinates as input.
11385 : *
11386 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11387 : * must be in the "natural" SRS of the dataset, that is the one returned by
11388 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11389 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11390 : * array (generally WGS 84) if there is a geolocation array.
11391 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11392 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11393 : * be a easting, and dfGeolocY a northing.
11394 : *
11395 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11396 : * expressed in that CRS, and that tuple must be conformant with the
11397 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11398 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11399 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11400 : * before calling this method, and in that case, dfGeolocX must be a longitude
11401 : * or an easting value, and dfGeolocX a latitude or a northing value.
11402 : *
11403 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11404 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11405 : * it for details on how that transformation is done.
11406 : *
11407 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11408 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11409 : * where interpolation should be done.
11410 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11411 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11412 : * where interpolation should be done.
11413 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11414 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11415 : * @param pdfRealValue pointer to real part of interpolated value
11416 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11417 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11418 : *
11419 : * @return CE_None on success, or an error code on failure.
11420 : * @since GDAL 3.11
11421 : */
11422 :
11423 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11424 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11425 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11426 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11427 : {
11428 : double dfPixel;
11429 : double dfLine;
11430 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11431 : &dfLine,
11432 15 : papszTransformerOptions) != CE_None)
11433 : {
11434 1 : return CE_Failure;
11435 : }
11436 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11437 14 : pdfImagValue);
11438 : }
11439 :
11440 : /************************************************************************/
11441 : /* GDALRasterInterpolateAtGeolocation() */
11442 : /************************************************************************/
11443 :
11444 : /**
11445 : * \brief Interpolates the value between pixels using a resampling algorithm,
11446 : * taking georeferenced coordinates as input.
11447 : *
11448 : * @see GDALRasterBand::InterpolateAtGeolocation()
11449 : * @since GDAL 3.11
11450 : */
11451 :
11452 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11453 : double dfGeolocX, double dfGeolocY,
11454 : OGRSpatialReferenceH hSRS,
11455 : GDALRIOResampleAlg eInterpolation,
11456 : double *pdfRealValue,
11457 : double *pdfImagValue,
11458 : CSLConstList papszTransformerOptions)
11459 : {
11460 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11461 :
11462 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11463 15 : return poBand->InterpolateAtGeolocation(
11464 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11465 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11466 : }
11467 :
11468 : /************************************************************************/
11469 : /* GDALRasterBand::SplitRasterIO() */
11470 : /************************************************************************/
11471 :
11472 : //! @cond Doxygen_Suppress
11473 :
11474 : /** Implements IRasterIO() by dividing the request in 2.
11475 : *
11476 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11477 : *
11478 : * Return CE_Warning if the split could not be done, CE_None in case of
11479 : * success and CE_Failure in case of error.
11480 : *
11481 : * @since 3.12
11482 : */
11483 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11484 : [[maybe_unused]] int nXSize,
11485 : [[maybe_unused]] int nYSize, void *pData,
11486 : int nBufXSize, int nBufYSize,
11487 : GDALDataType eBufType,
11488 : GSpacing nPixelSpace, GSpacing nLineSpace,
11489 : GDALRasterIOExtraArg *psExtraArg)
11490 : {
11491 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11492 :
11493 999 : GByte *pabyData = static_cast<GByte *>(pData);
11494 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11495 : {
11496 : GDALRasterIOExtraArg sArg;
11497 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11498 499 : const int nHalfHeight = nBufYSize / 2;
11499 :
11500 499 : sArg.pfnProgress = GDALScaledProgress;
11501 499 : sArg.pProgressData = GDALCreateScaledProgress(
11502 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11503 499 : if (sArg.pProgressData == nullptr)
11504 499 : sArg.pfnProgress = nullptr;
11505 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11506 : pabyData, nBufXSize, nHalfHeight, eBufType,
11507 499 : nPixelSpace, nLineSpace, &sArg);
11508 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11509 :
11510 499 : if (eErr == CE_None)
11511 : {
11512 499 : sArg.pfnProgress = GDALScaledProgress;
11513 499 : sArg.pProgressData = GDALCreateScaledProgress(
11514 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11515 499 : if (sArg.pProgressData == nullptr)
11516 499 : sArg.pfnProgress = nullptr;
11517 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11518 : nBufYSize - nHalfHeight,
11519 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11520 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11521 499 : nLineSpace, &sArg);
11522 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11523 : }
11524 499 : return eErr;
11525 : }
11526 500 : else if (nBufXSize >= 2)
11527 : {
11528 : GDALRasterIOExtraArg sArg;
11529 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11530 500 : const int nHalfWidth = nBufXSize / 2;
11531 :
11532 500 : sArg.pfnProgress = GDALScaledProgress;
11533 500 : sArg.pProgressData = GDALCreateScaledProgress(
11534 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11535 500 : if (sArg.pProgressData == nullptr)
11536 500 : sArg.pfnProgress = nullptr;
11537 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11538 : pabyData, nHalfWidth, nBufYSize, eBufType,
11539 500 : nPixelSpace, nLineSpace, &sArg);
11540 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11541 :
11542 500 : if (eErr == CE_None)
11543 : {
11544 500 : sArg.pfnProgress = GDALScaledProgress;
11545 500 : sArg.pProgressData = GDALCreateScaledProgress(
11546 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11547 500 : if (sArg.pProgressData == nullptr)
11548 500 : sArg.pfnProgress = nullptr;
11549 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11550 : nBufXSize - nHalfWidth, nBufYSize,
11551 500 : pabyData + nHalfWidth * nPixelSpace,
11552 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11553 500 : nPixelSpace, nLineSpace, &sArg);
11554 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11555 : }
11556 500 : return eErr;
11557 : }
11558 :
11559 0 : return CE_Warning;
11560 : }
11561 :
11562 : //! @endcond
11563 :
11564 : /************************************************************************/
11565 : /* ThrowIfNotSameDimensions() */
11566 : /************************************************************************/
11567 :
11568 : //! @cond Doxygen_Suppress
11569 : /* static */
11570 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11571 : const GDALRasterBand &second)
11572 : {
11573 320 : if (first.GetXSize() != second.GetXSize() ||
11574 151 : first.GetYSize() != second.GetYSize())
11575 : {
11576 36 : throw std::runtime_error("Bands do not have the same dimensions");
11577 : }
11578 133 : }
11579 :
11580 : //! @endcond
11581 :
11582 : /************************************************************************/
11583 : /* GDALRasterBandUnaryOp() */
11584 : /************************************************************************/
11585 :
11586 : /** Apply a unary operation on this band.
11587 : *
11588 : * The resulting band is lazy evaluated. A reference is taken on the input
11589 : * dataset.
11590 : *
11591 : * @since 3.12
11592 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11593 : */
11594 : GDALComputedRasterBandH
11595 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11596 : GDALRasterAlgebraUnaryOperation eOp)
11597 : {
11598 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11599 6 : GDALComputedRasterBand::Operation cppOp{};
11600 6 : switch (eOp)
11601 : {
11602 2 : case GRAUO_LOGICAL_NOT:
11603 : return new GDALComputedRasterBand(
11604 : GDALComputedRasterBand::Operation::OP_NE,
11605 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11606 1 : case GRAUO_ABS:
11607 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11608 1 : break;
11609 1 : case GRAUO_SQRT:
11610 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11611 1 : break;
11612 1 : case GRAUO_LOG:
11613 : #ifndef HAVE_MUPARSER
11614 : CPLError(
11615 : CE_Failure, CPLE_NotSupported,
11616 : "log(band) not available on a GDAL build without muparser");
11617 : return nullptr;
11618 : #else
11619 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11620 1 : break;
11621 : #endif
11622 1 : case GRAUO_LOG10:
11623 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11624 1 : break;
11625 : }
11626 : return new GDALComputedRasterBand(cppOp,
11627 4 : *(GDALRasterBand::FromHandle(hBand)));
11628 : }
11629 :
11630 : /************************************************************************/
11631 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11632 : /************************************************************************/
11633 :
11634 : static GDALComputedRasterBand::Operation
11635 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11636 : GDALRasterAlgebraBinaryOperation eOp)
11637 : {
11638 120 : switch (eOp)
11639 : {
11640 26 : case GRABO_ADD:
11641 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11642 2 : case GRABO_SUB:
11643 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11644 24 : case GRABO_MUL:
11645 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11646 3 : case GRABO_DIV:
11647 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11648 6 : case GRABO_GT:
11649 6 : return GDALComputedRasterBand::Operation::OP_GT;
11650 8 : case GRABO_GE:
11651 8 : return GDALComputedRasterBand::Operation::OP_GE;
11652 6 : case GRABO_LT:
11653 6 : return GDALComputedRasterBand::Operation::OP_LT;
11654 6 : case GRABO_LE:
11655 6 : return GDALComputedRasterBand::Operation::OP_LE;
11656 6 : case GRABO_EQ:
11657 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11658 6 : case GRABO_NE:
11659 6 : break;
11660 12 : case GRABO_LOGICAL_AND:
11661 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11662 12 : case GRABO_LOGICAL_OR:
11663 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11664 3 : case GRABO_POW:
11665 3 : return GDALComputedRasterBand::Operation::OP_POW;
11666 : }
11667 6 : return GDALComputedRasterBand::Operation::OP_NE;
11668 : }
11669 :
11670 : /************************************************************************/
11671 : /* GDALRasterBandBinaryOpBand() */
11672 : /************************************************************************/
11673 :
11674 : /** Apply a binary operation on this band with another one.
11675 : *
11676 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11677 : * "hBand1 - hBand2".
11678 : *
11679 : * The resulting band is lazy evaluated. A reference is taken on both input
11680 : * datasets.
11681 : *
11682 : * @since 3.12
11683 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11684 : */
11685 : GDALComputedRasterBandH
11686 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11687 : GDALRasterAlgebraBinaryOperation eOp,
11688 : GDALRasterBandH hOtherBand)
11689 : {
11690 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11691 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11692 : #ifndef HAVE_MUPARSER
11693 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11694 : {
11695 : CPLError(
11696 : CE_Failure, CPLE_NotSupported,
11697 : "Band comparison operators not available on a GDAL build without "
11698 : "muparser");
11699 : return nullptr;
11700 : }
11701 : else if (eOp == GRABO_POW)
11702 : {
11703 : CPLError(
11704 : CE_Failure, CPLE_NotSupported,
11705 : "pow(band, band) not available on a GDAL build without muparser");
11706 : return nullptr;
11707 : }
11708 : #endif
11709 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11710 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11711 : try
11712 : {
11713 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11714 : }
11715 13 : catch (const std::exception &e)
11716 : {
11717 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11718 13 : return nullptr;
11719 : }
11720 : return new GDALComputedRasterBand(
11721 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11722 44 : secondBand);
11723 : }
11724 :
11725 : /************************************************************************/
11726 : /* GDALRasterBandBinaryOpDouble() */
11727 : /************************************************************************/
11728 :
11729 : /** Apply a binary operation on this band with a constant
11730 : *
11731 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11732 : * "hBand - constant".
11733 : *
11734 : * The resulting band is lazy evaluated. A reference is taken on the input
11735 : * dataset.
11736 : *
11737 : * @since 3.12
11738 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11739 : */
11740 : GDALComputedRasterBandH
11741 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11742 : GDALRasterAlgebraBinaryOperation eOp,
11743 : double constant)
11744 : {
11745 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11746 : #ifndef HAVE_MUPARSER
11747 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11748 : {
11749 : CPLError(
11750 : CE_Failure, CPLE_NotSupported,
11751 : "Band comparison operators not available on a GDAL build without "
11752 : "muparser");
11753 : return nullptr;
11754 : }
11755 : #endif
11756 : return new GDALComputedRasterBand(
11757 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11758 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11759 : }
11760 :
11761 : /************************************************************************/
11762 : /* GDALRasterBandBinaryOpDoubleToBand() */
11763 : /************************************************************************/
11764 :
11765 : /** Apply a binary operation on the constant with this band
11766 : *
11767 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11768 : * "constant - hBand".
11769 : *
11770 : * The resulting band is lazy evaluated. A reference is taken on the input
11771 : * dataset.
11772 : *
11773 : * @since 3.12
11774 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11775 : */
11776 : GDALComputedRasterBandH
11777 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11778 : GDALRasterAlgebraBinaryOperation eOp,
11779 : GDALRasterBandH hBand)
11780 : {
11781 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11782 : #ifndef HAVE_MUPARSER
11783 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11784 : {
11785 : CPLError(
11786 : CE_Failure, CPLE_NotSupported,
11787 : "Band comparison operators not available on a GDAL build without "
11788 : "muparser");
11789 : return nullptr;
11790 : }
11791 : #endif
11792 18 : switch (eOp)
11793 : {
11794 15 : case GRABO_ADD:
11795 : case GRABO_MUL:
11796 : {
11797 : return new GDALComputedRasterBand(
11798 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11799 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11800 : }
11801 :
11802 2 : case GRABO_DIV:
11803 : case GRABO_GT:
11804 : case GRABO_GE:
11805 : case GRABO_LT:
11806 : case GRABO_LE:
11807 : case GRABO_EQ:
11808 : case GRABO_NE:
11809 : case GRABO_LOGICAL_AND:
11810 : case GRABO_LOGICAL_OR:
11811 : case GRABO_POW:
11812 : {
11813 : return new GDALComputedRasterBand(
11814 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11815 2 : *(GDALRasterBand::FromHandle(hBand)));
11816 : }
11817 :
11818 1 : case GRABO_SUB:
11819 : {
11820 1 : break;
11821 : }
11822 : }
11823 :
11824 : return new GDALComputedRasterBand(
11825 : GDALComputedRasterBand::Operation::OP_ADD,
11826 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11827 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11828 1 : constant);
11829 : }
11830 :
11831 : /************************************************************************/
11832 : /* operator+() */
11833 : /************************************************************************/
11834 :
11835 : /** Add this band with another one.
11836 : *
11837 : * The resulting band is lazy evaluated. A reference is taken on both input
11838 : * datasets.
11839 : *
11840 : * @since 3.12
11841 : * @throw std::runtime_error if both bands do not have the same dimensions.
11842 : */
11843 : GDALComputedRasterBand
11844 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11845 : {
11846 8 : ThrowIfNotSameDimensions(*this, other);
11847 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11848 7 : *this, other);
11849 : }
11850 :
11851 : /************************************************************************/
11852 : /* operator+() */
11853 : /************************************************************************/
11854 :
11855 : /** Add this band with a constant.
11856 : *
11857 : * The resulting band is lazy evaluated. A reference is taken on the input
11858 : * dataset.
11859 : *
11860 : * @since 3.12
11861 : */
11862 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11863 : {
11864 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11865 13 : *this, constant);
11866 : }
11867 :
11868 : /************************************************************************/
11869 : /* operator+() */
11870 : /************************************************************************/
11871 :
11872 : /** Add a band with a constant.
11873 : *
11874 : * The resulting band is lazy evaluated. A reference is taken on the input
11875 : * dataset.
11876 : *
11877 : * @since 3.12
11878 : */
11879 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11880 : {
11881 1 : return other + constant;
11882 : }
11883 :
11884 : /************************************************************************/
11885 : /* operator-() */
11886 : /************************************************************************/
11887 :
11888 : /** Return a band whose value is the opposite value of the band for each
11889 : * pixel.
11890 : *
11891 : * The resulting band is lazy evaluated. A reference is taken on the input
11892 : * dataset.
11893 : *
11894 : * @since 3.12
11895 : */
11896 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
11897 : {
11898 2 : return 0 - *this;
11899 : }
11900 :
11901 : /************************************************************************/
11902 : /* operator-() */
11903 : /************************************************************************/
11904 :
11905 : /** Subtract this band with another one.
11906 : *
11907 : * The resulting band is lazy evaluated. A reference is taken on both input
11908 : * datasets.
11909 : *
11910 : * @since 3.12
11911 : * @throw std::runtime_error if both bands do not have the same dimensions.
11912 : */
11913 : GDALComputedRasterBand
11914 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
11915 : {
11916 2 : ThrowIfNotSameDimensions(*this, other);
11917 : return GDALComputedRasterBand(
11918 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11919 : }
11920 :
11921 : /************************************************************************/
11922 : /* operator-() */
11923 : /************************************************************************/
11924 :
11925 : /** Subtract this band with a constant.
11926 : *
11927 : * The resulting band is lazy evaluated. A reference is taken on the input
11928 : * dataset.
11929 : *
11930 : * @since 3.12
11931 : */
11932 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11933 : {
11934 : return GDALComputedRasterBand(
11935 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11936 : }
11937 :
11938 : /************************************************************************/
11939 : /* operator-() */
11940 : /************************************************************************/
11941 :
11942 : /** Subtract a constant with a band.
11943 : *
11944 : * The resulting band is lazy evaluated. A reference is taken on the input
11945 : * dataset.
11946 : *
11947 : * @since 3.12
11948 : */
11949 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11950 : {
11951 6 : return other * (-1.0) + constant;
11952 : }
11953 :
11954 : /************************************************************************/
11955 : /* operator*() */
11956 : /************************************************************************/
11957 :
11958 : /** Multiply this band with another one.
11959 : *
11960 : * The resulting band is lazy evaluated. A reference is taken on both input
11961 : * datasets.
11962 : *
11963 : * @since 3.12
11964 : * @throw std::runtime_error if both bands do not have the same dimensions.
11965 : */
11966 : GDALComputedRasterBand
11967 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
11968 : {
11969 2 : ThrowIfNotSameDimensions(*this, other);
11970 : return GDALComputedRasterBand(
11971 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11972 : }
11973 :
11974 : /************************************************************************/
11975 : /* operator*() */
11976 : /************************************************************************/
11977 :
11978 : /** Multiply this band by a constant.
11979 : *
11980 : * The resulting band is lazy evaluated. A reference is taken on the input
11981 : * dataset.
11982 : *
11983 : * @since 3.12
11984 : */
11985 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11986 : {
11987 : return GDALComputedRasterBand(
11988 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11989 : }
11990 :
11991 : /************************************************************************/
11992 : /* operator*() */
11993 : /************************************************************************/
11994 :
11995 : /** Multiply a band with a constant.
11996 : *
11997 : * The resulting band is lazy evaluated. A reference is taken on the input
11998 : * dataset.
11999 : *
12000 : * @since 3.12
12001 : */
12002 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12003 : {
12004 2 : return other * constant;
12005 : }
12006 :
12007 : /************************************************************************/
12008 : /* operator/() */
12009 : /************************************************************************/
12010 :
12011 : /** Divide this band with another one.
12012 : *
12013 : * The resulting band is lazy evaluated. A reference is taken on both input
12014 : * datasets.
12015 : *
12016 : * @since 3.12
12017 : * @throw std::runtime_error if both bands do not have the same dimensions.
12018 : */
12019 : GDALComputedRasterBand
12020 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
12021 : {
12022 2 : ThrowIfNotSameDimensions(*this, other);
12023 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12024 2 : *this, other);
12025 : }
12026 :
12027 : /************************************************************************/
12028 : /* operator/() */
12029 : /************************************************************************/
12030 :
12031 : /** Divide this band by a constant.
12032 : *
12033 : * The resulting band is lazy evaluated. A reference is taken on the input
12034 : * dataset.
12035 : *
12036 : * @since 3.12
12037 : */
12038 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12039 : {
12040 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12041 0 : *this, constant);
12042 : }
12043 :
12044 : /************************************************************************/
12045 : /* operator/() */
12046 : /************************************************************************/
12047 :
12048 : /** Divide a constant by a band.
12049 : *
12050 : * The resulting band is lazy evaluated. A reference is taken on the input
12051 : * dataset.
12052 : *
12053 : * @since 3.12
12054 : */
12055 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12056 : {
12057 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12058 1 : constant, other);
12059 : }
12060 :
12061 : /************************************************************************/
12062 : /* ThrowIfNotMuparser() */
12063 : /************************************************************************/
12064 :
12065 : #ifndef HAVE_MUPARSER
12066 : static GDALComputedRasterBand ThrowIfNotMuparser()
12067 : {
12068 : throw std::runtime_error("Operator not available on a "
12069 : "GDAL build without muparser");
12070 : }
12071 : #endif
12072 :
12073 : /************************************************************************/
12074 : /* operator>() */
12075 : /************************************************************************/
12076 :
12077 : /** Return a band whose value is 1 if the pixel value of the left operand
12078 : * is greater than the pixel value of the right operand.
12079 : *
12080 : * The resulting band is lazy evaluated. A reference is taken on the input
12081 : * dataset.
12082 : *
12083 : * @since 3.12
12084 : */
12085 : GDALComputedRasterBand
12086 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
12087 : {
12088 : #ifndef HAVE_MUPARSER
12089 : (void)other;
12090 : return ThrowIfNotMuparser();
12091 : #else
12092 3 : ThrowIfNotSameDimensions(*this, other);
12093 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12094 2 : *this, other);
12095 : #endif
12096 : }
12097 :
12098 : /************************************************************************/
12099 : /* operator>() */
12100 : /************************************************************************/
12101 :
12102 : /** Return a band whose value is 1 if the pixel value of the left operand
12103 : * is greater than the constant.
12104 : *
12105 : * The resulting band is lazy evaluated. A reference is taken on the input
12106 : * dataset.
12107 : *
12108 : * @since 3.12
12109 : */
12110 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12111 : {
12112 : #ifndef HAVE_MUPARSER
12113 : (void)constant;
12114 : return ThrowIfNotMuparser();
12115 : #else
12116 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12117 3 : *this, constant);
12118 : #endif
12119 : }
12120 :
12121 : /************************************************************************/
12122 : /* operator>() */
12123 : /************************************************************************/
12124 :
12125 : /** Return a band whose value is 1 if the constant is greater than the pixel
12126 : * value of the right operand.
12127 : *
12128 : * The resulting band is lazy evaluated. A reference is taken on the input
12129 : * dataset.
12130 : *
12131 : * @since 3.12
12132 : */
12133 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12134 : {
12135 : #ifndef HAVE_MUPARSER
12136 : (void)constant;
12137 : (void)other;
12138 : return ThrowIfNotMuparser();
12139 : #else
12140 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12141 2 : constant, other);
12142 : #endif
12143 : }
12144 :
12145 : /************************************************************************/
12146 : /* operator>=() */
12147 : /************************************************************************/
12148 :
12149 : /** Return a band whose value is 1 if the pixel value of the left operand
12150 : * is greater or equal to the pixel value of the right operand.
12151 : *
12152 : * The resulting band is lazy evaluated. A reference is taken on the input
12153 : * dataset.
12154 : *
12155 : * @since 3.12
12156 : */
12157 : GDALComputedRasterBand
12158 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
12159 : {
12160 : #ifndef HAVE_MUPARSER
12161 : (void)other;
12162 : return ThrowIfNotMuparser();
12163 : #else
12164 4 : ThrowIfNotSameDimensions(*this, other);
12165 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12166 3 : *this, other);
12167 : #endif
12168 : }
12169 :
12170 : /************************************************************************/
12171 : /* operator>=() */
12172 : /************************************************************************/
12173 :
12174 : /** Return a band whose value is 1 if the pixel value of the left operand
12175 : * is greater or equal to the constant.
12176 : *
12177 : * The resulting band is lazy evaluated. A reference is taken on the input
12178 : * dataset.
12179 : *
12180 : * @since 3.12
12181 : */
12182 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12183 : {
12184 : #ifndef HAVE_MUPARSER
12185 : (void)constant;
12186 : return ThrowIfNotMuparser();
12187 : #else
12188 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12189 3 : *this, constant);
12190 : #endif
12191 : }
12192 :
12193 : /************************************************************************/
12194 : /* operator>=() */
12195 : /************************************************************************/
12196 :
12197 : /** Return a band whose value is 1 if the constant is greater or equal to
12198 : * the pixel value of the right operand.
12199 : *
12200 : * The resulting band is lazy evaluated. A reference is taken on the input
12201 : * dataset.
12202 : *
12203 : * @since 3.12
12204 : */
12205 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12206 : {
12207 : #ifndef HAVE_MUPARSER
12208 : (void)constant;
12209 : (void)other;
12210 : return ThrowIfNotMuparser();
12211 : #else
12212 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12213 2 : constant, other);
12214 : #endif
12215 : }
12216 :
12217 : /************************************************************************/
12218 : /* operator<() */
12219 : /************************************************************************/
12220 :
12221 : /** Return a band whose value is 1 if the pixel value of the left operand
12222 : * is lesser than the pixel value of the right operand.
12223 : *
12224 : * The resulting band is lazy evaluated. A reference is taken on the input
12225 : * dataset.
12226 : *
12227 : * @since 3.12
12228 : */
12229 : GDALComputedRasterBand
12230 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
12231 : {
12232 : #ifndef HAVE_MUPARSER
12233 : (void)other;
12234 : return ThrowIfNotMuparser();
12235 : #else
12236 3 : ThrowIfNotSameDimensions(*this, other);
12237 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12238 2 : *this, other);
12239 : #endif
12240 : }
12241 :
12242 : /************************************************************************/
12243 : /* operator<() */
12244 : /************************************************************************/
12245 :
12246 : /** Return a band whose value is 1 if the pixel value of the left operand
12247 : * is lesser than the constant.
12248 : *
12249 : * The resulting band is lazy evaluated. A reference is taken on the input
12250 : * dataset.
12251 : *
12252 : * @since 3.12
12253 : */
12254 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12255 : {
12256 : #ifndef HAVE_MUPARSER
12257 : (void)constant;
12258 : return ThrowIfNotMuparser();
12259 : #else
12260 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12261 3 : *this, constant);
12262 : #endif
12263 : }
12264 :
12265 : /************************************************************************/
12266 : /* operator<() */
12267 : /************************************************************************/
12268 :
12269 : /** Return a band whose value is 1 if the constant is lesser than the pixel
12270 : * value of the right operand.
12271 : *
12272 : * The resulting band is lazy evaluated. A reference is taken on the input
12273 : * dataset.
12274 : *
12275 : * @since 3.12
12276 : */
12277 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12278 : {
12279 : #ifndef HAVE_MUPARSER
12280 : (void)constant;
12281 : (void)other;
12282 : return ThrowIfNotMuparser();
12283 : #else
12284 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12285 2 : constant, other);
12286 : #endif
12287 : }
12288 :
12289 : /************************************************************************/
12290 : /* operator<=() */
12291 : /************************************************************************/
12292 :
12293 : /** Return a band whose value is 1 if the pixel value of the left operand
12294 : * is lesser or equal to the pixel value of the right operand.
12295 : *
12296 : * The resulting band is lazy evaluated. A reference is taken on the input
12297 : * dataset.
12298 : *
12299 : * @since 3.12
12300 : */
12301 : GDALComputedRasterBand
12302 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
12303 : {
12304 : #ifndef HAVE_MUPARSER
12305 : (void)other;
12306 : return ThrowIfNotMuparser();
12307 : #else
12308 4 : ThrowIfNotSameDimensions(*this, other);
12309 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12310 3 : *this, other);
12311 : #endif
12312 : }
12313 :
12314 : /************************************************************************/
12315 : /* operator<=() */
12316 : /************************************************************************/
12317 :
12318 : /** Return a band whose value is 1 if the pixel value of the left operand
12319 : * is lesser or equal to the constant.
12320 : *
12321 : * The resulting band is lazy evaluated. A reference is taken on the input
12322 : * dataset.
12323 : *
12324 : * @since 3.12
12325 : */
12326 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12327 : {
12328 : #ifndef HAVE_MUPARSER
12329 : (void)constant;
12330 : return ThrowIfNotMuparser();
12331 : #else
12332 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12333 3 : *this, constant);
12334 : #endif
12335 : }
12336 :
12337 : /************************************************************************/
12338 : /* operator<=() */
12339 : /************************************************************************/
12340 :
12341 : /** Return a band whose value is 1 if the constant is lesser or equal to
12342 : * the pixel value of the right operand.
12343 : *
12344 : * The resulting band is lazy evaluated. A reference is taken on the input
12345 : * dataset.
12346 : *
12347 : * @since 3.12
12348 : */
12349 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12350 : {
12351 : #ifndef HAVE_MUPARSER
12352 : (void)constant;
12353 : (void)other;
12354 : return ThrowIfNotMuparser();
12355 : #else
12356 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12357 2 : constant, other);
12358 : #endif
12359 : }
12360 :
12361 : /************************************************************************/
12362 : /* operator==() */
12363 : /************************************************************************/
12364 :
12365 : /** Return a band whose value is 1 if the pixel value of the left operand
12366 : * is equal to the pixel value of the right operand.
12367 : *
12368 : * The resulting band is lazy evaluated. A reference is taken on the input
12369 : * dataset.
12370 : *
12371 : * @since 3.12
12372 : */
12373 : GDALComputedRasterBand
12374 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
12375 : {
12376 : #ifndef HAVE_MUPARSER
12377 : (void)other;
12378 : return ThrowIfNotMuparser();
12379 : #else
12380 3 : ThrowIfNotSameDimensions(*this, other);
12381 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12382 2 : *this, other);
12383 : #endif
12384 : }
12385 :
12386 : /************************************************************************/
12387 : /* operator==() */
12388 : /************************************************************************/
12389 :
12390 : /** Return a band whose value is 1 if the pixel value of the left operand
12391 : * is equal to the constant.
12392 : *
12393 : * The resulting band is lazy evaluated. A reference is taken on the input
12394 : * dataset.
12395 : *
12396 : * @since 3.12
12397 : */
12398 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12399 : {
12400 : #ifndef HAVE_MUPARSER
12401 : (void)constant;
12402 : return ThrowIfNotMuparser();
12403 : #else
12404 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12405 8 : *this, constant);
12406 : #endif
12407 : }
12408 :
12409 : /************************************************************************/
12410 : /* operator==() */
12411 : /************************************************************************/
12412 :
12413 : /** Return a band whose value is 1 if the constant is equal to
12414 : * the pixel value of the right operand.
12415 : *
12416 : * The resulting band is lazy evaluated. A reference is taken on the input
12417 : * dataset.
12418 : *
12419 : * @since 3.12
12420 : */
12421 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12422 : {
12423 : #ifndef HAVE_MUPARSER
12424 : (void)constant;
12425 : (void)other;
12426 : return ThrowIfNotMuparser();
12427 : #else
12428 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12429 2 : constant, other);
12430 : #endif
12431 : }
12432 :
12433 : /************************************************************************/
12434 : /* operator!=() */
12435 : /************************************************************************/
12436 :
12437 : /** Return a band whose value is 1 if the pixel value of the left operand
12438 : * is different from the pixel value of the right operand.
12439 : *
12440 : * The resulting band is lazy evaluated. A reference is taken on the input
12441 : * dataset.
12442 : *
12443 : * @since 3.12
12444 : */
12445 : GDALComputedRasterBand
12446 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12447 : {
12448 : #ifndef HAVE_MUPARSER
12449 : (void)other;
12450 : return ThrowIfNotMuparser();
12451 : #else
12452 3 : ThrowIfNotSameDimensions(*this, other);
12453 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12454 2 : *this, other);
12455 : #endif
12456 : }
12457 :
12458 : /************************************************************************/
12459 : /* operator!=() */
12460 : /************************************************************************/
12461 :
12462 : /** Return a band whose value is 1 if the pixel value of the left operand
12463 : * is different from the constant.
12464 : *
12465 : * The resulting band is lazy evaluated. A reference is taken on the input
12466 : * dataset.
12467 : *
12468 : * @since 3.12
12469 : */
12470 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12471 : {
12472 : #ifndef HAVE_MUPARSER
12473 : (void)constant;
12474 : return ThrowIfNotMuparser();
12475 : #else
12476 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12477 6 : *this, constant);
12478 : #endif
12479 : }
12480 :
12481 : /************************************************************************/
12482 : /* operator!=() */
12483 : /************************************************************************/
12484 :
12485 : /** Return a band whose value is 1 if the constant is different from
12486 : * the pixel value of the right operand.
12487 : *
12488 : * The resulting band is lazy evaluated. A reference is taken on the input
12489 : * dataset.
12490 : *
12491 : * @since 3.12
12492 : */
12493 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12494 : {
12495 : #ifndef HAVE_MUPARSER
12496 : (void)constant;
12497 : (void)other;
12498 : return ThrowIfNotMuparser();
12499 : #else
12500 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12501 2 : constant, other);
12502 : #endif
12503 : }
12504 :
12505 : #if defined(__GNUC__)
12506 : #pragma GCC diagnostic push
12507 : #pragma GCC diagnostic ignored "-Weffc++"
12508 : #endif
12509 :
12510 : /************************************************************************/
12511 : /* operator&&() */
12512 : /************************************************************************/
12513 :
12514 : /** Return a band whose value is 1 if the pixel value of the left and right
12515 : * operands is true.
12516 : *
12517 : * The resulting band is lazy evaluated. A reference is taken on the input
12518 : * dataset.
12519 : *
12520 : * @since 3.12
12521 : */
12522 : GDALComputedRasterBand
12523 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12524 : {
12525 : #ifndef HAVE_MUPARSER
12526 : (void)other;
12527 : return ThrowIfNotMuparser();
12528 : #else
12529 3 : ThrowIfNotSameDimensions(*this, other);
12530 : return GDALComputedRasterBand(
12531 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12532 : #endif
12533 : }
12534 :
12535 : /************************************************************************/
12536 : /* operator&&() */
12537 : /************************************************************************/
12538 :
12539 : /** Return a band whose value is 1 if the pixel value of the left operand
12540 : * is true, as well as the constant
12541 : *
12542 : * The resulting band is lazy evaluated. A reference is taken on the input
12543 : * dataset.
12544 : *
12545 : * @since 3.12
12546 : */
12547 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12548 : {
12549 : #ifndef HAVE_MUPARSER
12550 : (void)constant;
12551 : return ThrowIfNotMuparser();
12552 : #else
12553 : return GDALComputedRasterBand(
12554 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12555 : #endif
12556 : }
12557 :
12558 : /************************************************************************/
12559 : /* operator&&() */
12560 : /************************************************************************/
12561 :
12562 : /** Return a band whose value is 1 if the constant is true, as well as
12563 : * the pixel value of the right operand.
12564 : *
12565 : * The resulting band is lazy evaluated. A reference is taken on the input
12566 : * dataset.
12567 : *
12568 : * @since 3.12
12569 : */
12570 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12571 : {
12572 : #ifndef HAVE_MUPARSER
12573 : (void)constant;
12574 : (void)other;
12575 : return ThrowIfNotMuparser();
12576 : #else
12577 : return GDALComputedRasterBand(
12578 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12579 : #endif
12580 : }
12581 :
12582 : /************************************************************************/
12583 : /* operator||() */
12584 : /************************************************************************/
12585 :
12586 : /** Return a band whose value is 1 if the pixel value of the left or right
12587 : * operands is true.
12588 : *
12589 : * The resulting band is lazy evaluated. A reference is taken on the input
12590 : * dataset.
12591 : *
12592 : * @since 3.12
12593 : */
12594 : GDALComputedRasterBand
12595 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12596 : {
12597 : #ifndef HAVE_MUPARSER
12598 : (void)other;
12599 : return ThrowIfNotMuparser();
12600 : #else
12601 4 : ThrowIfNotSameDimensions(*this, other);
12602 : return GDALComputedRasterBand(
12603 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12604 : #endif
12605 : }
12606 :
12607 : /************************************************************************/
12608 : /* operator||() */
12609 : /************************************************************************/
12610 :
12611 : /** Return a band whose value is 1 if the pixel value of the left operand
12612 : * is true, or if the constant is true
12613 : *
12614 : * The resulting band is lazy evaluated. A reference is taken on the input
12615 : * dataset.
12616 : *
12617 : * @since 3.12
12618 : */
12619 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12620 : {
12621 : #ifndef HAVE_MUPARSER
12622 : (void)constant;
12623 : return ThrowIfNotMuparser();
12624 : #else
12625 : return GDALComputedRasterBand(
12626 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12627 : #endif
12628 : }
12629 :
12630 : /************************************************************************/
12631 : /* operator||() */
12632 : /************************************************************************/
12633 :
12634 : /** Return a band whose value is 1 if the constant is true, or
12635 : * the pixel value of the right operand is true
12636 : *
12637 : * The resulting band is lazy evaluated. A reference is taken on the input
12638 : * dataset.
12639 : *
12640 : * @since 3.12
12641 : */
12642 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12643 : {
12644 : #ifndef HAVE_MUPARSER
12645 : (void)constant;
12646 : (void)other;
12647 : return ThrowIfNotMuparser();
12648 : #else
12649 : return GDALComputedRasterBand(
12650 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12651 : #endif
12652 : }
12653 :
12654 : #if defined(__GNUC__)
12655 : #pragma GCC diagnostic pop
12656 : #endif
12657 :
12658 : /************************************************************************/
12659 : /* operator!() */
12660 : /************************************************************************/
12661 :
12662 : /** Return a band whose value is the logical negation of the pixel value
12663 : *
12664 : * The resulting band is lazy evaluated. A reference is taken on the input
12665 : * dataset.
12666 : *
12667 : * @since 3.12
12668 : */
12669 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12670 : {
12671 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12672 2 : *this, true);
12673 : }
12674 :
12675 : namespace gdal
12676 : {
12677 :
12678 : /************************************************************************/
12679 : /* IfThenElse() */
12680 : /************************************************************************/
12681 :
12682 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12683 : * is not zero, or the one from elseBand otherwise.
12684 : *
12685 : * Variants of this method exits where thenBand and/or elseBand can be double
12686 : * values.
12687 : *
12688 : * The resulting band is lazy evaluated. A reference is taken on the input
12689 : * datasets.
12690 : *
12691 : * This method is the same as the C function GDALRasterBandIfThenElse()
12692 : *
12693 : * @since 3.12
12694 : */
12695 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12696 : const GDALRasterBand &thenBand,
12697 : const GDALRasterBand &elseBand)
12698 : {
12699 : #ifndef HAVE_MUPARSER
12700 : (void)condBand;
12701 : (void)thenBand;
12702 : (void)elseBand;
12703 : return ThrowIfNotMuparser();
12704 : #else
12705 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12706 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12707 : return GDALComputedRasterBand(
12708 : GDALComputedRasterBand::Operation::OP_TERNARY,
12709 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12710 : #endif
12711 : }
12712 :
12713 : //! @cond Doxygen_Suppress
12714 :
12715 : /************************************************************************/
12716 : /* IfThenElse() */
12717 : /************************************************************************/
12718 :
12719 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12720 : * is not zero, or the one from elseBand otherwise.
12721 : *
12722 : * The resulting band is lazy evaluated. A reference is taken on the input
12723 : * datasets.
12724 : *
12725 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12726 : * with thenBand = (condBand * 0) + thenValue
12727 : *
12728 : * @since 3.12
12729 : */
12730 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12731 : double thenValue,
12732 : const GDALRasterBand &elseBand)
12733 : {
12734 : #ifndef HAVE_MUPARSER
12735 : (void)condBand;
12736 : (void)thenValue;
12737 : (void)elseBand;
12738 : return ThrowIfNotMuparser();
12739 : #else
12740 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12741 : auto thenBand =
12742 1 : (condBand * 0)
12743 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12744 1 : thenValue;
12745 : return GDALComputedRasterBand(
12746 : GDALComputedRasterBand::Operation::OP_TERNARY,
12747 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12748 : #endif
12749 : }
12750 :
12751 : /************************************************************************/
12752 : /* IfThenElse() */
12753 : /************************************************************************/
12754 :
12755 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12756 : * is not zero, or the one from elseValue otherwise.
12757 : *
12758 : * The resulting band is lazy evaluated. A reference is taken on the input
12759 : * datasets.
12760 : *
12761 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12762 : * with elseBand = (condBand * 0) + elseValue
12763 :
12764 : * @since 3.12
12765 : */
12766 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12767 : const GDALRasterBand &thenBand,
12768 : double elseValue)
12769 : {
12770 : #ifndef HAVE_MUPARSER
12771 : (void)condBand;
12772 : (void)thenBand;
12773 : (void)elseValue;
12774 : return ThrowIfNotMuparser();
12775 : #else
12776 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12777 : auto elseBand =
12778 1 : (condBand * 0)
12779 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12780 1 : elseValue;
12781 : return GDALComputedRasterBand(
12782 : GDALComputedRasterBand::Operation::OP_TERNARY,
12783 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12784 : #endif
12785 : }
12786 :
12787 : /************************************************************************/
12788 : /* IfThenElse() */
12789 : /************************************************************************/
12790 :
12791 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12792 : * is not zero, or the one from elseValue otherwise.
12793 : *
12794 : * The resulting band is lazy evaluated. A reference is taken on the input
12795 : * datasets.
12796 : *
12797 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12798 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12799 : *
12800 : * @since 3.12
12801 : */
12802 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12803 : double thenValue, double elseValue)
12804 : {
12805 : #ifndef HAVE_MUPARSER
12806 : (void)condBand;
12807 : (void)thenValue;
12808 : (void)elseValue;
12809 : return ThrowIfNotMuparser();
12810 : #else
12811 : auto thenBand =
12812 3 : (condBand * 0)
12813 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12814 6 : thenValue;
12815 : auto elseBand =
12816 3 : (condBand * 0)
12817 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12818 3 : elseValue;
12819 : return GDALComputedRasterBand(
12820 : GDALComputedRasterBand::Operation::OP_TERNARY,
12821 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12822 : #endif
12823 : }
12824 :
12825 : //! @endcond
12826 :
12827 : } // namespace gdal
12828 :
12829 : /************************************************************************/
12830 : /* GDALRasterBandIfThenElse() */
12831 : /************************************************************************/
12832 :
12833 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12834 : * is not zero, or the one from hElseBand otherwise.
12835 : *
12836 : * The resulting band is lazy evaluated. A reference is taken on the input
12837 : * datasets.
12838 : *
12839 : * This function is the same as the C++ method gdal::IfThenElse()
12840 : *
12841 : * @since 3.12
12842 : */
12843 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12844 : GDALRasterBandH hThenBand,
12845 : GDALRasterBandH hElseBand)
12846 : {
12847 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12848 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12849 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12850 : #ifndef HAVE_MUPARSER
12851 : CPLError(CE_Failure, CPLE_NotSupported,
12852 : "Band comparison operators not available on a GDAL build without "
12853 : "muparser");
12854 : return nullptr;
12855 : #else
12856 :
12857 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12858 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12859 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12860 : try
12861 : {
12862 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12863 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12864 : }
12865 2 : catch (const std::exception &e)
12866 : {
12867 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12868 2 : return nullptr;
12869 : }
12870 : return new GDALComputedRasterBand(
12871 : GDALComputedRasterBand::Operation::OP_TERNARY,
12872 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12873 : #endif
12874 : }
12875 :
12876 : /************************************************************************/
12877 : /* GDALRasterBand::AsType() */
12878 : /************************************************************************/
12879 :
12880 : /** Cast this band to another type.
12881 : *
12882 : * The resulting band is lazy evaluated. A reference is taken on the input
12883 : * dataset.
12884 : *
12885 : * This method is the same as the C function GDALRasterBandAsDataType()
12886 : *
12887 : * @since 3.12
12888 : */
12889 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12890 : {
12891 10 : if (dt == GDT_Unknown)
12892 : {
12893 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12894 : }
12895 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12896 9 : *this, dt);
12897 : }
12898 :
12899 : /************************************************************************/
12900 : /* GDALRasterBandAsDataType() */
12901 : /************************************************************************/
12902 :
12903 : /** Cast this band to another type.
12904 : *
12905 : * The resulting band is lazy evaluated. A reference is taken on the input
12906 : * dataset.
12907 : *
12908 : * This function is the same as the C++ method GDALRasterBand::AsType()
12909 : *
12910 : * @since 3.12
12911 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12912 : */
12913 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12914 : GDALDataType eDT)
12915 : {
12916 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
12917 16 : if (eDT == GDT_Unknown)
12918 : {
12919 1 : CPLError(CE_Failure, CPLE_NotSupported,
12920 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12921 1 : return nullptr;
12922 : }
12923 : return new GDALComputedRasterBand(
12924 : GDALComputedRasterBand::Operation::OP_CAST,
12925 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
12926 : }
12927 :
12928 : /************************************************************************/
12929 : /* GetBandVector() */
12930 : /************************************************************************/
12931 :
12932 : static std::vector<const GDALRasterBand *>
12933 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12934 : {
12935 10 : std::vector<const GDALRasterBand *> bands;
12936 27 : for (size_t i = 0; i < nBandCount; ++i)
12937 : {
12938 20 : if (i > 0)
12939 : {
12940 10 : GDALRasterBand::ThrowIfNotSameDimensions(
12941 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
12942 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
12943 : }
12944 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12945 : }
12946 7 : return bands;
12947 : }
12948 :
12949 : /************************************************************************/
12950 : /* GDALOperationOnNBands() */
12951 : /************************************************************************/
12952 :
12953 : static GDALComputedRasterBandH
12954 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12955 : GDALRasterBandH *pahBands)
12956 : {
12957 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
12958 11 : if (nBandCount == 0)
12959 : {
12960 1 : CPLError(CE_Failure, CPLE_AppDefined,
12961 : "At least one band should be passed");
12962 1 : return nullptr;
12963 : }
12964 :
12965 20 : std::vector<const GDALRasterBand *> bands;
12966 : try
12967 : {
12968 10 : bands = GetBandVector(nBandCount, pahBands);
12969 : }
12970 3 : catch (const std::exception &e)
12971 : {
12972 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12973 3 : return nullptr;
12974 : }
12975 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12976 : }
12977 :
12978 : /************************************************************************/
12979 : /* GDALMaximumOfNBands() */
12980 : /************************************************************************/
12981 :
12982 : /** Return a band whose each pixel value is the maximum of the corresponding
12983 : * pixel values in the input bands.
12984 : *
12985 : * The resulting band is lazy evaluated. A reference is taken on input
12986 : * datasets.
12987 : *
12988 : * This function is the same as the C ++ method gdal::max()
12989 : *
12990 : * @since 3.12
12991 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12992 : */
12993 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12994 : GDALRasterBandH *pahBands)
12995 : {
12996 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12997 4 : nBandCount, pahBands);
12998 : }
12999 :
13000 : /************************************************************************/
13001 : /* gdal::max() */
13002 : /************************************************************************/
13003 :
13004 : namespace gdal
13005 : {
13006 : /** Return a band whose each pixel value is the maximum of the corresponding
13007 : * pixel values in the inputs (bands or constants)
13008 : *
13009 : * The resulting band is lazy evaluated. A reference is taken on input
13010 : * datasets.
13011 : *
13012 : * Two or more bands can be passed.
13013 : *
13014 : * This method is the same as the C function GDALMaximumOfNBands()
13015 : *
13016 : * @since 3.12
13017 : * @throw std::runtime_error if bands do not have the same dimensions.
13018 : */
13019 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
13020 : const GDALRasterBand &second)
13021 : {
13022 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13023 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13024 1 : first, second);
13025 : }
13026 : } // namespace gdal
13027 :
13028 : /************************************************************************/
13029 : /* GDALRasterBandMaxConstant() */
13030 : /************************************************************************/
13031 :
13032 : /** Return a band whose each pixel value is the maximum of the corresponding
13033 : * pixel values in the input band and the constant.
13034 : *
13035 : * The resulting band is lazy evaluated. A reference is taken on the input
13036 : * dataset.
13037 : *
13038 : * This function is the same as the C ++ method gdal::max()
13039 : *
13040 : * @since 3.12
13041 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13042 : */
13043 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13044 : double dfConstant)
13045 : {
13046 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13047 : GDALComputedRasterBand::Operation::OP_MAX,
13048 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13049 6 : dfConstant));
13050 : }
13051 :
13052 : /************************************************************************/
13053 : /* GDALMinimumOfNBands() */
13054 : /************************************************************************/
13055 :
13056 : /** Return a band whose each pixel value is the minimum of the corresponding
13057 : * pixel values in the input bands.
13058 : *
13059 : * The resulting band is lazy evaluated. A reference is taken on input
13060 : * datasets.
13061 : *
13062 : * This function is the same as the C ++ method gdal::min()
13063 : *
13064 : * @since 3.12
13065 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13066 : */
13067 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13068 : GDALRasterBandH *pahBands)
13069 : {
13070 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13071 4 : nBandCount, pahBands);
13072 : }
13073 :
13074 : /************************************************************************/
13075 : /* gdal::min() */
13076 : /************************************************************************/
13077 :
13078 : namespace gdal
13079 : {
13080 : /** Return a band whose each pixel value is the minimum of the corresponding
13081 : * pixel values in the inputs (bands or constants)
13082 : *
13083 : * The resulting band is lazy evaluated. A reference is taken on input
13084 : * datasets.
13085 : *
13086 : * Two or more bands can be passed.
13087 : *
13088 : * This method is the same as the C function GDALMinimumOfNBands()
13089 : *
13090 : * @since 3.12
13091 : * @throw std::runtime_error if bands do not have the same dimensions.
13092 : */
13093 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
13094 : const GDALRasterBand &second)
13095 : {
13096 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13097 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13098 0 : first, second);
13099 : }
13100 : } // namespace gdal
13101 :
13102 : /************************************************************************/
13103 : /* GDALRasterBandMinConstant() */
13104 : /************************************************************************/
13105 :
13106 : /** Return a band whose each pixel value is the minimum of the corresponding
13107 : * pixel values in the input band and the constant.
13108 : *
13109 : * The resulting band is lazy evaluated. A reference is taken on the input
13110 : * dataset.
13111 : *
13112 : * This function is the same as the C ++ method gdal::min()
13113 : *
13114 : * @since 3.12
13115 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13116 : */
13117 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13118 : double dfConstant)
13119 : {
13120 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13121 : GDALComputedRasterBand::Operation::OP_MIN,
13122 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13123 6 : dfConstant));
13124 : }
13125 :
13126 : /************************************************************************/
13127 : /* GDALMeanOfNBands() */
13128 : /************************************************************************/
13129 :
13130 : /** Return a band whose each pixel value is the arithmetic mean of the
13131 : * corresponding pixel values in the input bands.
13132 : *
13133 : * The resulting band is lazy evaluated. A reference is taken on input
13134 : * datasets.
13135 : *
13136 : * This function is the same as the C ++ method gdal::mean()
13137 : *
13138 : * @since 3.12
13139 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13140 : */
13141 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13142 : GDALRasterBandH *pahBands)
13143 : {
13144 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13145 3 : nBandCount, pahBands);
13146 : }
13147 :
13148 : /************************************************************************/
13149 : /* gdal::mean() */
13150 : /************************************************************************/
13151 :
13152 : namespace gdal
13153 : {
13154 :
13155 : /** Return a band whose each pixel value is the arithmetic mean of the
13156 : * corresponding pixel values in the input bands.
13157 : *
13158 : * The resulting band is lazy evaluated. A reference is taken on input
13159 : * datasets.
13160 : *
13161 : * Two or more bands can be passed.
13162 : *
13163 : * This method is the same as the C function GDALMeanOfNBands()
13164 : *
13165 : * @since 3.12
13166 : * @throw std::runtime_error if bands do not have the same dimensions.
13167 : */
13168 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
13169 : const GDALRasterBand &second)
13170 : {
13171 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13172 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13173 0 : first, second);
13174 : }
13175 : } // namespace gdal
13176 :
13177 : /************************************************************************/
13178 : /* gdal::abs() */
13179 : /************************************************************************/
13180 :
13181 : namespace gdal
13182 : {
13183 :
13184 : /** Return a band whose each pixel value is the absolute value (or module
13185 : * for complex data type) of the corresponding pixel value in the input band.
13186 : *
13187 : * The resulting band is lazy evaluated. A reference is taken on input
13188 : * datasets.
13189 : *
13190 : * @since 3.12
13191 : */
13192 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
13193 : {
13194 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13195 1 : band);
13196 : }
13197 : } // namespace gdal
13198 :
13199 : /************************************************************************/
13200 : /* gdal::fabs() */
13201 : /************************************************************************/
13202 :
13203 : namespace gdal
13204 : {
13205 :
13206 : /** Return a band whose each pixel value is the absolute value (or module
13207 : * for complex data type) of the corresponding pixel value in the input band.
13208 : *
13209 : * The resulting band is lazy evaluated. A reference is taken on input
13210 : * datasets.
13211 : *
13212 : * @since 3.12
13213 : */
13214 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
13215 : {
13216 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13217 1 : band);
13218 : }
13219 : } // namespace gdal
13220 :
13221 : /************************************************************************/
13222 : /* gdal::sqrt() */
13223 : /************************************************************************/
13224 :
13225 : namespace gdal
13226 : {
13227 :
13228 : /** Return a band whose each pixel value is the square root of the
13229 : * corresponding pixel value in the input band.
13230 : *
13231 : * The resulting band is lazy evaluated. A reference is taken on input
13232 : * datasets.
13233 : *
13234 : * @since 3.12
13235 : */
13236 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13237 : {
13238 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13239 1 : band);
13240 : }
13241 : } // namespace gdal
13242 :
13243 : /************************************************************************/
13244 : /* gdal::log() */
13245 : /************************************************************************/
13246 :
13247 : namespace gdal
13248 : {
13249 :
13250 : /** Return a band whose each pixel value is the natural logarithm of the
13251 : * corresponding pixel value in the input band.
13252 : *
13253 : * The resulting band is lazy evaluated. A reference is taken on input
13254 : * datasets.
13255 : *
13256 : * @since 3.12
13257 : */
13258 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
13259 : {
13260 : #ifndef HAVE_MUPARSER
13261 : (void)band;
13262 : return ThrowIfNotMuparser();
13263 : #else
13264 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13265 1 : band);
13266 : #endif
13267 : }
13268 : } // namespace gdal
13269 :
13270 : /************************************************************************/
13271 : /* gdal::log10() */
13272 : /************************************************************************/
13273 :
13274 : namespace gdal
13275 : {
13276 :
13277 : /** Return a band whose each pixel value is the logarithm base 10 of the
13278 : * corresponding pixel value in the input band.
13279 : *
13280 : * The resulting band is lazy evaluated. A reference is taken on input
13281 : * datasets.
13282 : *
13283 : * @since 3.12
13284 : */
13285 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
13286 : {
13287 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13288 1 : band);
13289 : }
13290 : } // namespace gdal
13291 :
13292 : /************************************************************************/
13293 : /* gdal::pow() */
13294 : /************************************************************************/
13295 :
13296 : namespace gdal
13297 : {
13298 :
13299 : #ifndef DOXYGEN_SKIP
13300 : /** Return a band whose each pixel value is the constant raised to the power of
13301 : * the corresponding pixel value in the input band.
13302 : *
13303 : * The resulting band is lazy evaluated. A reference is taken on input
13304 : * datasets.
13305 : *
13306 : * @since 3.12
13307 : */
13308 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13309 : {
13310 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13311 1 : constant, band);
13312 : }
13313 : #endif
13314 :
13315 : } // namespace gdal
13316 :
13317 : /************************************************************************/
13318 : /* gdal::pow() */
13319 : /************************************************************************/
13320 :
13321 : namespace gdal
13322 : {
13323 :
13324 : /** Return a band whose each pixel value is the the corresponding pixel value
13325 : * in the input band raised to the power of the constant.
13326 : *
13327 : * The resulting band is lazy evaluated. A reference is taken on input
13328 : * datasets.
13329 : *
13330 : * @since 3.12
13331 : */
13332 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13333 : {
13334 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13335 1 : band, constant);
13336 : }
13337 : } // namespace gdal
13338 :
13339 : /************************************************************************/
13340 : /* gdal::pow() */
13341 : /************************************************************************/
13342 :
13343 : namespace gdal
13344 : {
13345 :
13346 : #ifndef DOXYGEN_SKIP
13347 : /** Return a band whose each pixel value is the the corresponding pixel value
13348 : * in the input band1 raised to the power of the corresponding pixel value
13349 : * in the input band2
13350 : *
13351 : * The resulting band is lazy evaluated. A reference is taken on input
13352 : * datasets.
13353 : *
13354 : * @since 3.12
13355 : * @throw std::runtime_error if bands do not have the same dimensions.
13356 : */
13357 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
13358 : const GDALRasterBand &band2)
13359 : {
13360 : #ifndef HAVE_MUPARSER
13361 : (void)band1;
13362 : (void)band2;
13363 : return ThrowIfNotMuparser();
13364 : #else
13365 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13366 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13367 1 : band1, band2);
13368 : #endif
13369 : }
13370 : #endif
13371 : } // namespace gdal
|