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 <type_traits>
31 :
32 : #include "cpl_conv.h"
33 : #include "cpl_error.h"
34 : #include "cpl_float.h"
35 : #include "cpl_progress.h"
36 : #include "cpl_string.h"
37 : #include "cpl_virtualmem.h"
38 : #include "cpl_vsi.h"
39 : #include "gdal.h"
40 : #include "gdal_abstractbandblockcache.h"
41 : #include "gdalantirecursion.h"
42 : #include "gdal_rat.h"
43 : #include "gdal_rasterband.h"
44 : #include "gdal_priv_templates.hpp"
45 : #include "gdal_interpolateatpoint.h"
46 : #include "gdal_minmax_element.hpp"
47 : #include "gdalmultidim_priv.h"
48 :
49 : #if defined(__AVX2__) || defined(__FMA__)
50 : #include <immintrin.h>
51 : #endif
52 :
53 : /************************************************************************/
54 : /* GDALRasterBand() */
55 : /************************************************************************/
56 :
57 : /*! Constructor. Applications should never create GDALRasterBands directly. */
58 :
59 1571430 : GDALRasterBand::GDALRasterBand()
60 : : GDALRasterBand(
61 1571430 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
62 : {
63 1571260 : }
64 :
65 : /** Constructor. Applications should never create GDALRasterBands directly.
66 : * @param bForceCachedIOIn Whether cached IO should be forced.
67 : */
68 1848710 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
69 1848710 : : bForceCachedIO(bForceCachedIOIn)
70 :
71 : {
72 1848510 : }
73 :
74 : /************************************************************************/
75 : /* ~GDALRasterBand() */
76 : /************************************************************************/
77 :
78 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
79 : instead destroy the GDALDataset. */
80 :
81 1848700 : GDALRasterBand::~GDALRasterBand()
82 :
83 : {
84 1848710 : if (poDS && poDS->IsMarkedSuppressOnClose())
85 : {
86 501 : if (poBandBlockCache)
87 438 : poBandBlockCache->DisableDirtyBlockWriting();
88 : }
89 1848710 : GDALRasterBand::FlushCache(true);
90 :
91 1848710 : delete poBandBlockCache;
92 :
93 1848710 : if (static_cast<GIntBig>(nBlockReads) >
94 1848710 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
95 223 : nBand == 1 && poDS != nullptr)
96 : {
97 326 : CPLDebug(
98 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
99 163 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
100 163 : poDS->GetDescription());
101 : }
102 :
103 1848710 : InvalidateMaskBand();
104 1848700 : nBand = -nBand;
105 :
106 1848700 : delete m_poPointsCache;
107 1848710 : }
108 :
109 : /************************************************************************/
110 : /* RasterIO() */
111 : /************************************************************************/
112 :
113 : /**
114 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
115 : * int nXOff, int nYOff, int nXSize, int nYSize,
116 : * void * pData, int nBufXSize, int nBufYSize,
117 : * GDALDataType eBufType,
118 : * GSpacing nPixelSpace,
119 : * GSpacing nLineSpace,
120 : * GDALRasterIOExtraArg* psExtraArg )
121 : * \brief Read/write a region of image data for this band.
122 : *
123 : * This method allows reading a region of a GDALRasterBand into a buffer,
124 : * or writing data from a buffer into a region of a GDALRasterBand. It
125 : * automatically takes care of data type translation if the data type
126 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
127 : * The method also takes care of image decimation / replication if the
128 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
129 : * region being accessed (nXSize x nYSize).
130 : *
131 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
132 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
133 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
134 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
135 : * Or use nLineSpace and a possibly shifted pData value.
136 : *
137 : * The nPixelSpace and nLineSpace parameters allow reading into or
138 : * writing from unusually organized buffers. This is primarily used
139 : * for buffers containing more than one bands raster data in interleaved
140 : * format.
141 : *
142 : * Some formats may efficiently implement decimation into a buffer by
143 : * reading from lower resolution overview images. The logic of the default
144 : * implementation in the base class GDALRasterBand is the following one. It
145 : * computes a target_downscaling_factor from the window of interest and buffer
146 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
147 : * It then walks through overviews and will select the first one whose
148 : * downscaling factor is greater than target_downscaling_factor / 1.2.
149 : *
150 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
151 : * The relationship between target_downscaling_factor and the select overview
152 : * level is the following one:
153 : *
154 : * target_downscaling_factor | selected_overview
155 : * ------------------------- | -----------------
156 : * ]0, 2 / 1.2] | full resolution band
157 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
158 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
159 : * ]8 / 1.2, infinity[ | 8x downsampled band
160 : *
161 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
162 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
163 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
164 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
165 : * this oversampling threshold defaults to 1. Consequently if there are overviews
166 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
167 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
168 : *
169 : * For highest performance full resolution data access, read and write
170 : * on "block boundaries" as returned by GetBlockSize(), or use the
171 : * ReadBlock() and WriteBlock() methods.
172 : *
173 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
174 : * functions.
175 : *
176 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
177 : * write a region of data.
178 : *
179 : * @param nXOff The pixel offset to the top left corner of the region
180 : * of the band to be accessed. This would be zero to start from the left side.
181 : *
182 : * @param nYOff The line offset to the top left corner of the region
183 : * of the band to be accessed. This would be zero to start from the top.
184 : *
185 : * @param nXSize The width of the region of the band to be accessed in pixels.
186 : *
187 : * @param nYSize The height of the region of the band to be accessed in lines.
188 : *
189 : * @param pData The buffer into which the data should be read, or from which
190 : * it should be written. This buffer must contain at least nBufXSize *
191 : * nBufYSize words of type eBufType. It is organized in left to right,
192 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
193 : * and nLineSpace parameters.
194 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
195 : * temporarily modified during the execution of this method (and eventually
196 : * restored back to its original content), so it is not safe to use a buffer
197 : * stored in a read-only section of the calling program.
198 : *
199 : * @param nBufXSize the width of the buffer image into which the desired region
200 : * is to be read, or from which it is to be written.
201 : *
202 : * @param nBufYSize the height of the buffer image into which the desired region
203 : * is to be read, or from which it is to be written.
204 : *
205 : * @param eBufType the type of the pixel values in the pData data buffer. The
206 : * pixel values will automatically be translated to/from the GDALRasterBand
207 : * data type as needed. Most driver implementations will use GDALCopyWords64()
208 : * to perform data type translation.
209 : *
210 : * @param nPixelSpace The byte offset from the start of one pixel value in
211 : * pData to the start of the next pixel value within a scanline. If defaulted
212 : * (0) the size of the datatype eBufType is used.
213 : *
214 : * @param nLineSpace The byte offset from the start of one scanline in
215 : * pData to the start of the next. If defaulted (0) the size of the datatype
216 : * eBufType * nBufXSize is used.
217 : *
218 : * @param psExtraArg Pointer to a GDALRasterIOExtraArg
219 : * structure with additional arguments to specify resampling and progress
220 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
221 : * configuration option can also be defined to override the default resampling
222 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
223 : *
224 : * @return CE_Failure if the access fails, otherwise CE_None.
225 : */
226 :
227 : /**
228 : * \brief Read/write a region of image data for this band.
229 : *
230 : * This method allows reading a region of a GDALRasterBand into a buffer,
231 : * or writing data from a buffer into a region of a GDALRasterBand. It
232 : * automatically takes care of data type translation if the data type
233 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
234 : * The method also takes care of image decimation / replication if the
235 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
236 : * region being accessed (nXSize x nYSize).
237 : *
238 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
239 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
240 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
241 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
242 : * Or use nLineSpace and a possibly shifted pData value.
243 : *
244 : * The nPixelSpace and nLineSpace parameters allow reading into or
245 : * writing from unusually organized buffers. This is primarily used
246 : * for buffers containing more than one bands raster data in interleaved
247 : * format.
248 : *
249 : * Some formats may efficiently implement decimation into a buffer by
250 : * reading from lower resolution overview images. The logic of the default
251 : * implementation in the base class GDALRasterBand is the following one. It
252 : * computes a target_downscaling_factor from the window of interest and buffer
253 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
254 : * It then walks through overviews and will select the first one whose
255 : * downscaling factor is greater than target_downscaling_factor / 1.2.
256 : *
257 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
258 : * The relationship between target_downscaling_factor and the select overview
259 : * level is the following one:
260 : *
261 : * target_downscaling_factor | selected_overview
262 : * ------------------------- | -----------------
263 : * ]0, 2 / 1.2] | full resolution band
264 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
265 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
266 : * ]8 / 1.2, infinity[ | 8x downsampled band
267 : *
268 : * For highest performance full resolution data access, read and write
269 : * on "block boundaries" as returned by GetBlockSize(), or use the
270 : * ReadBlock() and WriteBlock() methods.
271 : *
272 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
273 : * functions.
274 : *
275 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
276 : * more convenient to use for most common use cases.
277 : *
278 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
279 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
280 : * instance of this dataset) concurrently from several threads.
281 : *
282 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
283 : * write a region of data.
284 : *
285 : * @param nXOff The pixel offset to the top left corner of the region
286 : * of the band to be accessed. This would be zero to start from the left side.
287 : *
288 : * @param nYOff The line offset to the top left corner of the region
289 : * of the band to be accessed. This would be zero to start from the top.
290 : *
291 : * @param nXSize The width of the region of the band to be accessed in pixels.
292 : *
293 : * @param nYSize The height of the region of the band to be accessed in lines.
294 : *
295 : * @param[in,out] pData The buffer into which the data should be read, or from
296 : * which it should be written. This buffer must contain at least nBufXSize *
297 : * nBufYSize words of type eBufType. It is organized in left to right,
298 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
299 : * and nLineSpace parameters.
300 : *
301 : * @param nBufXSize the width of the buffer image into which the desired region
302 : * is to be read, or from which it is to be written.
303 : *
304 : * @param nBufYSize the height of the buffer image into which the desired region
305 : * is to be read, or from which it is to be written.
306 : *
307 : * @param eBufType the type of the pixel values in the pData data buffer. The
308 : * pixel values will automatically be translated to/from the GDALRasterBand
309 : * data type as needed.
310 : *
311 : * @param nPixelSpace The byte offset from the start of one pixel value in
312 : * pData to the start of the next pixel value within a scanline. If defaulted
313 : * (0) the size of the datatype eBufType is used.
314 : *
315 : * @param nLineSpace The byte offset from the start of one scanline in
316 : * pData to the start of the next. If defaulted (0) the size of the datatype
317 : * eBufType * nBufXSize is used.
318 : *
319 : * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
320 : * structure with additional arguments to specify resampling and progress
321 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
322 : * configuration option can also be defined to override the default resampling
323 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
324 : *
325 : * @return CE_Failure if the access fails, otherwise CE_None.
326 : *
327 : * @see GDALRasterBand::ReadRaster()
328 : */
329 :
330 4411870 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
331 : int nXSize, int nYSize, void *pData,
332 : int nBufXSize, int nBufYSize,
333 : GDALDataType eBufType, GSpacing nPixelSpace,
334 : GSpacing nLineSpace,
335 : GDALRasterIOExtraArg *psExtraArg)
336 :
337 : {
338 : GDALRasterIOExtraArg sExtraArg;
339 4411870 : if (psExtraArg == nullptr)
340 : {
341 3814690 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
342 3814690 : psExtraArg = &sExtraArg;
343 : }
344 597182 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
345 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
346 : {
347 0 : ReportError(CE_Failure, CPLE_AppDefined,
348 : "Unhandled version of GDALRasterIOExtraArg");
349 0 : return CE_Failure;
350 : }
351 :
352 4411870 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
353 : nBufYSize);
354 :
355 4411860 : if (CPL_UNLIKELY(nullptr == pData))
356 : {
357 0 : ReportError(CE_Failure, CPLE_AppDefined,
358 : "The buffer into which the data should be read is null");
359 0 : return CE_Failure;
360 : }
361 :
362 : /* -------------------------------------------------------------------- */
363 : /* Some size values are "noop". Lets just return to avoid */
364 : /* stressing lower level functions. */
365 : /* -------------------------------------------------------------------- */
366 4411860 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
367 : nBufYSize < 1))
368 : {
369 2 : CPLDebug("GDAL",
370 : "RasterIO() skipped for odd window or buffer size.\n"
371 : " Window = (%d,%d)x%dx%d\n"
372 : " Buffer = %dx%d\n",
373 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
374 :
375 2 : return CE_None;
376 : }
377 :
378 4411860 : if (eRWFlag == GF_Write)
379 : {
380 365664 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
381 : {
382 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
383 : "An error occurred while writing a dirty block "
384 : "from GDALRasterBand::RasterIO");
385 0 : CPLErr eErr = eFlushBlockErr;
386 0 : eFlushBlockErr = CE_None;
387 0 : return eErr;
388 : }
389 365664 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
390 : {
391 7 : return CE_Failure;
392 : }
393 : }
394 :
395 : /* -------------------------------------------------------------------- */
396 : /* If pixel and line spacing are defaulted assign reasonable */
397 : /* value assuming a packed buffer. */
398 : /* -------------------------------------------------------------------- */
399 4411880 : if (nPixelSpace == 0)
400 : {
401 4013880 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
402 : }
403 :
404 4412060 : if (nLineSpace == 0)
405 : {
406 4003940 : nLineSpace = nPixelSpace * nBufXSize;
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Do some validation of parameters. */
411 : /* -------------------------------------------------------------------- */
412 4412060 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
413 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
414 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
415 : {
416 15 : ReportError(CE_Failure, CPLE_IllegalArg,
417 : "Access window out of range in RasterIO(). Requested\n"
418 : "(%d,%d) of size %dx%d on raster of %dx%d.",
419 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
420 15 : return CE_Failure;
421 : }
422 :
423 4412050 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
424 : {
425 0 : ReportError(
426 : CE_Failure, CPLE_IllegalArg,
427 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
428 : eRWFlag);
429 0 : return CE_Failure;
430 : }
431 4412050 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
432 : {
433 2 : ReportError(CE_Failure, CPLE_IllegalArg,
434 : "Illegal GDT_Unknown/GDT_TypeCount argument");
435 2 : return CE_Failure;
436 : }
437 :
438 4412050 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
439 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
440 4410790 : nLineSpace, psExtraArg);
441 : }
442 :
443 : /************************************************************************/
444 : /* RasterIOInternal() */
445 : /************************************************************************/
446 :
447 4411420 : CPLErr GDALRasterBand::RasterIOInternal(
448 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
449 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
450 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
451 : {
452 : /* -------------------------------------------------------------------- */
453 : /* Call the format specific function. */
454 : /* -------------------------------------------------------------------- */
455 :
456 4411420 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
457 :
458 : CPLErr eErr;
459 4411110 : if (bForceCachedIO)
460 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
461 : pData, nBufXSize, nBufYSize, eBufType,
462 : nPixelSpace, nLineSpace, psExtraArg);
463 : else
464 : eErr =
465 4411670 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
466 4411090 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
467 :
468 4411700 : if (bCallLeaveReadWrite)
469 600800 : LeaveReadWrite();
470 :
471 4411500 : return eErr;
472 : }
473 :
474 : /************************************************************************/
475 : /* GDALRasterIO() */
476 : /************************************************************************/
477 :
478 : /**
479 : * \brief Read/write a region of image data for this band.
480 : *
481 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
482 : * resolution, progress callback, etc. are needed)
483 : *
484 : * @see GDALRasterBand::RasterIO()
485 : */
486 :
487 3402530 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
488 : int nXOff, int nYOff, int nXSize, int nYSize,
489 : void *pData, int nBufXSize, int nBufYSize,
490 : GDALDataType eBufType, int nPixelSpace,
491 : int nLineSpace)
492 :
493 : {
494 3402530 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
495 :
496 3402530 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
497 :
498 3402530 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
499 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
500 3400850 : nLineSpace, nullptr));
501 : }
502 :
503 : /************************************************************************/
504 : /* GDALRasterIOEx() */
505 : /************************************************************************/
506 :
507 : /**
508 : * \brief Read/write a region of image data for this band.
509 : *
510 : * @see GDALRasterBand::RasterIO()
511 : */
512 :
513 40383 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
514 : int nXOff, int nYOff, int nXSize, int nYSize,
515 : void *pData, int nBufXSize, int nBufYSize,
516 : GDALDataType eBufType, GSpacing nPixelSpace,
517 : GSpacing nLineSpace,
518 : GDALRasterIOExtraArg *psExtraArg)
519 :
520 : {
521 40383 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
522 :
523 40383 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
524 :
525 40383 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
526 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
527 40378 : nLineSpace, psExtraArg));
528 : }
529 :
530 : /************************************************************************/
531 : /* GetGDTFromCppType() */
532 : /************************************************************************/
533 :
534 : namespace
535 : {
536 : template <class T> struct GetGDTFromCppType;
537 :
538 : #define DEFINE_GetGDTFromCppType(T, eDT) \
539 : template <> struct GetGDTFromCppType<T> \
540 : { \
541 : static constexpr GDALDataType GDT = eDT; \
542 : }
543 :
544 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
545 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
546 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
547 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
548 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
549 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
550 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
551 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
552 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
553 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
554 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
555 : // Not allowed by C++ standard
556 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
557 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
558 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
559 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
560 : } // namespace
561 :
562 : /************************************************************************/
563 : /* ReadRaster() */
564 : /************************************************************************/
565 :
566 : // clang-format off
567 : /** Read a region of image data for this band.
568 : *
569 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
570 : * for common use cases, like reading a whole band.
571 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
572 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
573 : * float, double, std::complex<float|double>.
574 : *
575 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
576 : * and can allocate memory automatically.
577 : *
578 : * To read a whole band (assuming it fits into memory), as an array of double:
579 : *
580 : \code{.cpp}
581 : double* myArray = static_cast<double*>(
582 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
583 : // TODO: check here that myArray != nullptr
584 : const size_t nArrayEltCount =
585 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
586 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
587 : {
588 : // do something
589 : }
590 : VSIFree(myArray)
591 : \endcode
592 : *
593 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
594 : *
595 : \code{.cpp}
596 : double* myArray = static_cast<double*>(
597 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
598 : // TODO: check here that myArray != nullptr
599 : const size_t nArrayEltCount = 128 * 128;
600 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
601 : {
602 : // do something
603 : }
604 : VSIFree(myArray)
605 : \endcode
606 : *
607 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
608 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
609 : * instance of this dataset) concurrently from several threads.
610 : *
611 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
612 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
613 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
614 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
615 : * Or use nLineSpace and a possibly shifted pData value.
616 : *
617 : * @param[out] pData The buffer into which the data should be written.
618 : * This buffer must contain at least nBufXSize *
619 : * nBufYSize words of type T. It is organized in left to right,
620 : * top to bottom pixel order, and fully packed.
621 : * The type of the buffer does not need to be the one of GetDataType(). The
622 : * method will perform data type translation (with potential rounding, clamping)
623 : * if needed.
624 : *
625 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
626 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
627 : * return in error if it is not. If set to zero, then pData is trusted to be
628 : * large enough.
629 : *
630 : * @param dfXOff The pixel offset to the top left corner of the region
631 : * of the band to be accessed. This would be zero to start from the left side.
632 : * Defaults to 0.
633 : *
634 : * @param dfYOff The line offset to the top left corner of the region
635 : * of the band to be accessed. This would be zero to start from the top.
636 : * Defaults to 0.
637 : *
638 : * @param dfXSize The width of the region of the band to be accessed in pixels.
639 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
640 : * dfXSize is set to the band width.
641 : *
642 : * @param dfYSize The height of the region of the band to be accessed in lines.
643 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
644 : * dfYSize is set to the band height.
645 : *
646 : * @param nBufXSize the width of the buffer image into which the desired region
647 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
648 : * then nBufXSize is initialized with dfXSize.
649 : *
650 : * @param nBufYSize the height of the buffer image into which the desired region
651 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
652 : * then nBufYSize is initialized with dfYSize.
653 : *
654 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
655 : *
656 : * @param pfnProgress Progress function. May be nullptr.
657 : *
658 : * @param pProgressData User data of pfnProgress. May be nullptr.
659 : *
660 : * @return CE_Failure if the access fails, otherwise CE_None.
661 : *
662 : * @see GDALRasterBand::RasterIO()
663 : * @since GDAL 3.10
664 : */
665 : // clang-format on
666 :
667 : template <class T>
668 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
669 : double dfXOff, double dfYOff, double dfXSize,
670 : double dfYSize, size_t nBufXSize,
671 : size_t nBufYSize,
672 : GDALRIOResampleAlg eResampleAlg,
673 : GDALProgressFunc pfnProgress,
674 : void *pProgressData) const
675 : {
676 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
677 : {
678 2 : return CE_Failure;
679 : }
680 :
681 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
682 : {
683 16 : dfXSize = nRasterXSize;
684 16 : dfYSize = nRasterYSize;
685 : }
686 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
687 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
688 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
689 2 : dfYOff + dfYSize > INT_MAX)
690 : {
691 0 : return CE_Failure;
692 : }
693 :
694 : GDALRasterIOExtraArg sExtraArg;
695 18 : sExtraArg.nVersion = 1;
696 18 : sExtraArg.eResampleAlg = eResampleAlg;
697 18 : sExtraArg.pfnProgress = pfnProgress;
698 18 : sExtraArg.pProgressData = pProgressData;
699 18 : sExtraArg.bFloatingPointWindowValidity = true;
700 18 : sExtraArg.dfXOff = dfXOff;
701 18 : sExtraArg.dfYOff = dfYOff;
702 18 : sExtraArg.dfXSize = dfXSize;
703 18 : sExtraArg.dfYSize = dfYSize;
704 18 : const int nXOff = static_cast<int>(dfXOff);
705 18 : const int nYOff = static_cast<int>(dfYOff);
706 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
707 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
708 18 : if (nBufXSize == 0 && nBufYSize == 0)
709 : {
710 17 : if (static_cast<int>(dfXSize) == dfXSize &&
711 17 : static_cast<int>(dfYSize) == dfYSize)
712 : {
713 17 : nBufXSize = static_cast<int>(dfXSize);
714 17 : nBufYSize = static_cast<int>(dfYSize);
715 : }
716 : else
717 : {
718 0 : CPLError(CE_Failure, CPLE_AppDefined,
719 : "nBufXSize and nBufYSize must be provided if dfXSize or "
720 : "dfYSize is not an integer value");
721 0 : return CE_Failure;
722 : }
723 : }
724 18 : if (nBufXSize == 0 || nBufYSize == 0)
725 : {
726 0 : CPLDebug("GDAL",
727 : "RasterIO() skipped for odd window or buffer size.\n"
728 : " Window = (%d,%d)x%dx%d\n"
729 : " Buffer = %dx%d\n",
730 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
731 : static_cast<int>(nBufYSize));
732 :
733 0 : return CE_None;
734 : }
735 :
736 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
737 : {
738 1 : CPLError(CE_Failure, CPLE_AppDefined,
739 : "Provided array is not large enough");
740 1 : return CE_Failure;
741 : }
742 :
743 17 : constexpr GSpacing nPixelSpace = sizeof(T);
744 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
745 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
746 :
747 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
748 :
749 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
750 : static_cast<int>(nBufXSize),
751 : static_cast<int>(nBufYSize), eBufType,
752 17 : nPixelSpace, nLineSpace, &sExtraArg);
753 : }
754 :
755 : //! @cond Doxygen_Suppress
756 :
757 : #define INSTANTIATE_READ_RASTER(T) \
758 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
759 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
760 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
761 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
762 : void *pProgressData) const;
763 :
764 : INSTANTIATE_READ_RASTER(uint8_t)
765 : INSTANTIATE_READ_RASTER(int8_t)
766 : INSTANTIATE_READ_RASTER(uint16_t)
767 : INSTANTIATE_READ_RASTER(int16_t)
768 : INSTANTIATE_READ_RASTER(uint32_t)
769 : INSTANTIATE_READ_RASTER(int32_t)
770 : INSTANTIATE_READ_RASTER(uint64_t)
771 : INSTANTIATE_READ_RASTER(int64_t)
772 : INSTANTIATE_READ_RASTER(GFloat16)
773 : INSTANTIATE_READ_RASTER(float)
774 : INSTANTIATE_READ_RASTER(double)
775 : // Not allowed by C++ standard
776 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
777 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
778 : INSTANTIATE_READ_RASTER(std::complex<float>)
779 : INSTANTIATE_READ_RASTER(std::complex<double>)
780 :
781 : //! @endcond
782 :
783 : /************************************************************************/
784 : /* ReadRaster() */
785 : /************************************************************************/
786 :
787 : /** Read a region of image data for this band.
788 : *
789 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
790 : * for common use cases, like reading a whole band.
791 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
792 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
793 : * float, double, std::complex<float|double>.
794 : *
795 : * To read a whole band (assuming it fits into memory), as a vector of double:
796 : *
797 : \code
798 : std::vector<double> myArray;
799 : if (poBand->ReadRaster(myArray) == CE_None)
800 : {
801 : // do something
802 : }
803 : \endcode
804 : *
805 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
806 : *
807 : \code{.cpp}
808 : std::vector<double> myArray;
809 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
810 : {
811 : // do something
812 : }
813 : \endcode
814 : *
815 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
816 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
817 : * instance of this dataset) concurrently from several threads.
818 : *
819 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
820 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
821 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
822 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
823 : * Or use nLineSpace and a possibly shifted pData value.
824 : *
825 : * @param[out] vData The vector into which the data should be written.
826 : * The vector will be resized, if needed, to contain at least nBufXSize *
827 : * nBufYSize values. The values in the vector are organized in left to right,
828 : * top to bottom pixel order, and fully packed.
829 : * The type of the vector does not need to be the one of GetDataType(). The
830 : * method will perform data type translation (with potential rounding, clamping)
831 : * if needed.
832 : *
833 : * @param dfXOff The pixel offset to the top left corner of the region
834 : * of the band to be accessed. This would be zero to start from the left side.
835 : * Defaults to 0.
836 : *
837 : * @param dfYOff The line offset to the top left corner of the region
838 : * of the band to be accessed. This would be zero to start from the top.
839 : * Defaults to 0.
840 : *
841 : * @param dfXSize The width of the region of the band to be accessed in pixels.
842 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
843 : * dfXSize is set to the band width.
844 : *
845 : * @param dfYSize The height of the region of the band to be accessed in lines.
846 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
847 : * dfYSize is set to the band height.
848 : *
849 : * @param nBufXSize the width of the buffer image into which the desired region
850 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
851 : * then nBufXSize is initialized with dfXSize.
852 : *
853 : * @param nBufYSize the height of the buffer image into which the desired region
854 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
855 : * then nBufYSize is initialized with dfYSize.
856 : *
857 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
858 : *
859 : * @param pfnProgress Progress function. May be nullptr.
860 : *
861 : * @param pProgressData User data of pfnProgress. May be nullptr.
862 : *
863 : * @return CE_Failure if the access fails, otherwise CE_None.
864 : *
865 : * @see GDALRasterBand::RasterIO()
866 : * @since GDAL 3.10
867 : */
868 : template <class T>
869 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
870 : double dfYOff, double dfXSize, double dfYSize,
871 : size_t nBufXSize, size_t nBufYSize,
872 : GDALRIOResampleAlg eResampleAlg,
873 : GDALProgressFunc pfnProgress,
874 : void *pProgressData) const
875 : {
876 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
877 : {
878 2 : return CE_Failure;
879 : }
880 :
881 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
882 : {
883 13 : dfXSize = nRasterXSize;
884 13 : dfYSize = nRasterYSize;
885 : }
886 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
887 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
888 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
889 7 : dfYOff + dfYSize > INT_MAX)
890 : {
891 0 : return CE_Failure;
892 : }
893 :
894 : GDALRasterIOExtraArg sExtraArg;
895 20 : sExtraArg.nVersion = 1;
896 20 : sExtraArg.eResampleAlg = eResampleAlg;
897 20 : sExtraArg.pfnProgress = pfnProgress;
898 20 : sExtraArg.pProgressData = pProgressData;
899 20 : sExtraArg.bFloatingPointWindowValidity = true;
900 20 : sExtraArg.dfXOff = dfXOff;
901 20 : sExtraArg.dfYOff = dfYOff;
902 20 : sExtraArg.dfXSize = dfXSize;
903 20 : sExtraArg.dfYSize = dfYSize;
904 20 : const int nXOff = static_cast<int>(dfXOff);
905 20 : const int nYOff = static_cast<int>(dfYOff);
906 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
907 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
908 20 : if (nBufXSize == 0 && nBufYSize == 0)
909 : {
910 16 : if (static_cast<int>(dfXSize) == dfXSize &&
911 15 : static_cast<int>(dfYSize) == dfYSize)
912 : {
913 15 : nBufXSize = static_cast<int>(dfXSize);
914 15 : nBufYSize = static_cast<int>(dfYSize);
915 : }
916 : else
917 : {
918 1 : CPLError(CE_Failure, CPLE_AppDefined,
919 : "nBufXSize and nBufYSize must be provided if "
920 : "dfXSize or dfYSize is not an integer value");
921 1 : return CE_Failure;
922 : }
923 : }
924 19 : if (nBufXSize == 0 || nBufYSize == 0)
925 : {
926 0 : CPLDebug("GDAL",
927 : "RasterIO() skipped for odd window or buffer size.\n"
928 : " Window = (%d,%d)x%dx%d\n"
929 : " Buffer = %dx%d\n",
930 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
931 : static_cast<int>(nBufYSize));
932 :
933 0 : return CE_None;
934 : }
935 :
936 : if constexpr (SIZEOF_VOIDP < 8)
937 : {
938 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
939 : {
940 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
941 : return CE_Failure;
942 : }
943 : }
944 :
945 19 : if (vData.size() < nBufXSize * nBufYSize)
946 : {
947 : try
948 : {
949 17 : vData.resize(nBufXSize * nBufYSize);
950 : }
951 1 : catch (const std::exception &)
952 : {
953 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
954 1 : return CE_Failure;
955 : }
956 : }
957 :
958 18 : constexpr GSpacing nPixelSpace = sizeof(T);
959 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
960 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
961 :
962 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
963 :
964 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
965 : vData.data(), static_cast<int>(nBufXSize),
966 : static_cast<int>(nBufYSize), eBufType,
967 18 : nPixelSpace, nLineSpace, &sExtraArg);
968 : }
969 :
970 : //! @cond Doxygen_Suppress
971 :
972 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
973 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
974 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
975 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
976 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
977 : void *pProgressData) const;
978 :
979 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
981 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
982 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
983 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
984 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
985 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
986 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
988 : INSTANTIATE_READ_RASTER_VECTOR(float)
989 : INSTANTIATE_READ_RASTER_VECTOR(double)
990 : // Not allowed by C++ standard
991 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
992 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
993 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
994 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
995 :
996 : //! @endcond
997 :
998 : /************************************************************************/
999 : /* ReadBlock() */
1000 : /************************************************************************/
1001 :
1002 : /**
1003 : * \brief Read a block of image data efficiently.
1004 : *
1005 : * This method accesses a "natural" block from the raster band without
1006 : * resampling, or data type conversion. For a more generalized, but
1007 : * potentially less efficient access use RasterIO().
1008 : *
1009 : * This method is the same as the C GDALReadBlock() function.
1010 : *
1011 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1012 : * block oriented data without an extra copy into an application buffer.
1013 : *
1014 : * The following code would efficiently compute a histogram of eight bit
1015 : * raster data. Note that the final block may be partial ... data beyond
1016 : * the edge of the underlying raster band in these edge blocks is of an
1017 : * undetermined value.
1018 : *
1019 : \code{.cpp}
1020 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1021 :
1022 : {
1023 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1024 :
1025 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1026 :
1027 : int nXBlockSize, nYBlockSize;
1028 :
1029 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1030 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1031 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1032 :
1033 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1034 :
1035 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1036 : {
1037 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1038 : {
1039 : int nXValid, nYValid;
1040 :
1041 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1042 :
1043 : // Compute the portion of the block that is valid
1044 : // for partial edge blocks.
1045 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1046 :
1047 : // Collect the histogram counts.
1048 : for( int iY = 0; iY < nYValid; iY++ )
1049 : {
1050 : for( int iX = 0; iX < nXValid; iX++ )
1051 : {
1052 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1053 : }
1054 : }
1055 : }
1056 : }
1057 : }
1058 : \endcode
1059 : *
1060 : * @param nXBlockOff the horizontal block offset, with zero indicating
1061 : * the left most block, 1 the next block and so forth.
1062 : *
1063 : * @param nYBlockOff the vertical block offset, with zero indicating
1064 : * the top most block, 1 the next block and so forth.
1065 : *
1066 : * @param pImage the buffer into which the data will be read. The buffer
1067 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1068 : * of type GetRasterDataType().
1069 : *
1070 : * @return CE_None on success or CE_Failure on an error.
1071 : */
1072 :
1073 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1074 :
1075 : {
1076 : /* -------------------------------------------------------------------- */
1077 : /* Validate arguments. */
1078 : /* -------------------------------------------------------------------- */
1079 894 : CPLAssert(pImage != nullptr);
1080 :
1081 894 : if (!InitBlockInfo())
1082 0 : return CE_Failure;
1083 :
1084 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1085 : {
1086 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1087 : "Illegal nXBlockOff value (%d) in "
1088 : "GDALRasterBand::ReadBlock()\n",
1089 : nXBlockOff);
1090 :
1091 0 : return (CE_Failure);
1092 : }
1093 :
1094 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1095 : {
1096 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1097 : "Illegal nYBlockOff value (%d) in "
1098 : "GDALRasterBand::ReadBlock()\n",
1099 : nYBlockOff);
1100 :
1101 0 : return (CE_Failure);
1102 : }
1103 :
1104 : /* -------------------------------------------------------------------- */
1105 : /* Invoke underlying implementation method. */
1106 : /* -------------------------------------------------------------------- */
1107 :
1108 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1109 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1110 894 : if (bCallLeaveReadWrite)
1111 4 : LeaveReadWrite();
1112 894 : return eErr;
1113 : }
1114 :
1115 : /************************************************************************/
1116 : /* GDALReadBlock() */
1117 : /************************************************************************/
1118 :
1119 : /**
1120 : * \brief Read a block of image data efficiently.
1121 : *
1122 : * @see GDALRasterBand::ReadBlock()
1123 : */
1124 :
1125 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1126 : void *pData)
1127 :
1128 : {
1129 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1130 :
1131 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1132 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1133 : }
1134 :
1135 : /************************************************************************/
1136 : /* IReadBlock() */
1137 : /************************************************************************/
1138 :
1139 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1140 : * ) \brief Read a block of data.
1141 : *
1142 : * Default internal implementation ... to be overridden by
1143 : * subclasses that support reading.
1144 : * @param nBlockXOff Block X Offset
1145 : * @param nBlockYOff Block Y Offset
1146 : * @param pData Pixel buffer into which to place read data.
1147 : * @return CE_None on success or CE_Failure on an error.
1148 : */
1149 :
1150 : /************************************************************************/
1151 : /* IWriteBlock() */
1152 : /************************************************************************/
1153 :
1154 : /**
1155 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1156 : * Write a block of data.
1157 : *
1158 : * Default internal implementation ... to be overridden by
1159 : * subclasses that support writing.
1160 : * @param nBlockXOff Block X Offset
1161 : * @param nBlockYOff Block Y Offset
1162 : * @param pData Pixel buffer to write
1163 : * @return CE_None on success or CE_Failure on an error.
1164 : */
1165 :
1166 : /**/
1167 : /**/
1168 :
1169 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1170 : void * /*pData*/)
1171 :
1172 : {
1173 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1174 0 : ReportError(CE_Failure, CPLE_NotSupported,
1175 : "WriteBlock() not supported for this dataset.");
1176 :
1177 0 : return (CE_Failure);
1178 : }
1179 :
1180 : /************************************************************************/
1181 : /* WriteBlock() */
1182 : /************************************************************************/
1183 :
1184 : /**
1185 : * \brief Write a block of image data efficiently.
1186 : *
1187 : * This method accesses a "natural" block from the raster band without
1188 : * resampling, or data type conversion. For a more generalized, but
1189 : * potentially less efficient access use RasterIO().
1190 : *
1191 : * This method is the same as the C GDALWriteBlock() function.
1192 : *
1193 : * See ReadBlock() for an example of block oriented data access.
1194 : *
1195 : * @param nXBlockOff the horizontal block offset, with zero indicating
1196 : * the left most block, 1 the next block and so forth.
1197 : *
1198 : * @param nYBlockOff the vertical block offset, with zero indicating
1199 : * the left most block, 1 the next block and so forth.
1200 : *
1201 : * @param pImage the buffer from which the data will be written. The buffer
1202 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1203 : * of type GetRasterDataType(). Note that the content of the buffer might be
1204 : * temporarily modified during the execution of this method (and eventually
1205 : * restored back to its original content), so it is not safe to use a buffer
1206 : * stored in a read-only section of the calling program.
1207 : *
1208 : * @return CE_None on success or CE_Failure on an error.
1209 : */
1210 :
1211 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1212 :
1213 : {
1214 : /* -------------------------------------------------------------------- */
1215 : /* Validate arguments. */
1216 : /* -------------------------------------------------------------------- */
1217 4883 : CPLAssert(pImage != nullptr);
1218 :
1219 4883 : if (!InitBlockInfo())
1220 0 : return CE_Failure;
1221 :
1222 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1223 : {
1224 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1225 : "Illegal nXBlockOff value (%d) in "
1226 : "GDALRasterBand::WriteBlock()\n",
1227 : nXBlockOff);
1228 :
1229 0 : return (CE_Failure);
1230 : }
1231 :
1232 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1233 : {
1234 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1235 : "Illegal nYBlockOff value (%d) in "
1236 : "GDALRasterBand::WriteBlock()\n",
1237 : nYBlockOff);
1238 :
1239 0 : return (CE_Failure);
1240 : }
1241 :
1242 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1243 : {
1244 0 : return CE_Failure;
1245 : }
1246 :
1247 4883 : if (eFlushBlockErr != CE_None)
1248 : {
1249 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1250 : "An error occurred while writing a dirty block "
1251 : "from GDALRasterBand::WriteBlock");
1252 0 : CPLErr eErr = eFlushBlockErr;
1253 0 : eFlushBlockErr = CE_None;
1254 0 : return eErr;
1255 : }
1256 :
1257 : /* -------------------------------------------------------------------- */
1258 : /* Invoke underlying implementation method. */
1259 : /* -------------------------------------------------------------------- */
1260 :
1261 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1262 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1263 4883 : if (bCallLeaveReadWrite)
1264 4883 : LeaveReadWrite();
1265 :
1266 4883 : return eErr;
1267 : }
1268 :
1269 : /************************************************************************/
1270 : /* GDALWriteBlock() */
1271 : /************************************************************************/
1272 :
1273 : /**
1274 : * \brief Write a block of image data efficiently.
1275 : *
1276 : * @see GDALRasterBand::WriteBlock()
1277 : */
1278 :
1279 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1280 : void *pData)
1281 :
1282 : {
1283 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1284 :
1285 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1286 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1287 : }
1288 :
1289 : /************************************************************************/
1290 : /* EmitErrorMessageIfWriteNotSupported() */
1291 : /************************************************************************/
1292 :
1293 : /**
1294 : * Emit an error message if a write operation to this band is not supported.
1295 : *
1296 : * The base implementation will emit an error message if the access mode is
1297 : * read-only. Derived classes may implement it to provide a custom message.
1298 : *
1299 : * @param pszCaller Calling function.
1300 : * @return true if an error message has been emitted.
1301 : */
1302 639349 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1303 : const char *pszCaller) const
1304 : {
1305 639349 : if (eAccess == GA_ReadOnly)
1306 : {
1307 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1308 : "%s: attempt to write to dataset opened in read-only mode.",
1309 : pszCaller);
1310 :
1311 4 : return true;
1312 : }
1313 639345 : return false;
1314 : }
1315 :
1316 : /************************************************************************/
1317 : /* GetActualBlockSize() */
1318 : /************************************************************************/
1319 : /**
1320 : * \brief Fetch the actual block size for a given block offset.
1321 : *
1322 : * Handles partial blocks at the edges of the raster and returns the true
1323 : * number of pixels
1324 : *
1325 : * @param nXBlockOff the horizontal block offset for which to calculate the
1326 : * number of valid pixels, with zero indicating the left most block, 1 the next
1327 : * block and so forth.
1328 : *
1329 : * @param nYBlockOff the vertical block offset, with zero indicating
1330 : * the top most block, 1 the next block and so forth.
1331 : *
1332 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1333 : * the x direction will be stored
1334 : *
1335 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1336 : * the y direction will be stored
1337 : *
1338 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1339 : *
1340 : */
1341 52035 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1342 : int *pnXValid, int *pnYValid) const
1343 : {
1344 104069 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1345 104067 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1346 104064 : nYBlockOff < 0 || nBlockYSize == 0 ||
1347 52032 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1348 : {
1349 6 : return CE_Failure;
1350 : }
1351 :
1352 52029 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1353 52029 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1354 :
1355 52029 : *pnXValid = nBlockXSize;
1356 52029 : *pnYValid = nBlockYSize;
1357 :
1358 52029 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1359 : {
1360 50397 : *pnXValid = nRasterXSize - nXPixelOff;
1361 : }
1362 :
1363 52029 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1364 : {
1365 3772 : *pnYValid = nRasterYSize - nYPixelOff;
1366 : }
1367 :
1368 52029 : return CE_None;
1369 : }
1370 :
1371 : /************************************************************************/
1372 : /* GDALGetActualBlockSize() */
1373 : /************************************************************************/
1374 :
1375 : /**
1376 : * \brief Retrieve the actual block size for a given block offset.
1377 : *
1378 : * @see GDALRasterBand::GetActualBlockSize()
1379 : */
1380 :
1381 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1382 : int nYBlockOff, int *pnXValid,
1383 : int *pnYValid)
1384 :
1385 : {
1386 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1387 :
1388 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1389 : return (
1390 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1391 : }
1392 :
1393 : /************************************************************************/
1394 : /* GetSuggestedBlockAccessPattern() */
1395 : /************************************************************************/
1396 :
1397 : /**
1398 : * \brief Return the suggested/most efficient access pattern to blocks
1399 : * (for read operations).
1400 : *
1401 : * While all GDAL drivers have to expose a block size, not all can guarantee
1402 : * efficient random access (GSBAP_RANDOM) to any block.
1403 : * Some drivers for example decompress sequentially a compressed stream from
1404 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1405 : * case best performance will be achieved while reading blocks in that order.
1406 : * (accessing blocks in random access in such rasters typically causes the
1407 : * decoding to be re-initialized from the start if accessing blocks in
1408 : * a non-sequential order)
1409 : *
1410 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1411 : * returned by drivers that expose a somewhat artificial block size, because
1412 : * they can extract any part of a raster, but in a rather inefficient way.
1413 : *
1414 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1415 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1416 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1417 : * most efficient strategy is to read as many pixels as possible in the less
1418 : * RasterIO() operations.
1419 : *
1420 : * The return of this method is for example used to determine the swath size
1421 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1422 : *
1423 : * @since GDAL 3.6
1424 : */
1425 :
1426 : GDALSuggestedBlockAccessPattern
1427 2409 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1428 : {
1429 2409 : return GSBAP_UNKNOWN;
1430 : }
1431 :
1432 : /************************************************************************/
1433 : /* GetRasterDataType() */
1434 : /************************************************************************/
1435 :
1436 : /**
1437 : * \brief Fetch the pixel data type for this band.
1438 : *
1439 : * This method is the same as the C function GDALGetRasterDataType().
1440 : *
1441 : * @return the data type of pixels for this band.
1442 : */
1443 :
1444 8953660 : GDALDataType GDALRasterBand::GetRasterDataType() const
1445 :
1446 : {
1447 8953660 : return eDataType;
1448 : }
1449 :
1450 : /************************************************************************/
1451 : /* GDALGetRasterDataType() */
1452 : /************************************************************************/
1453 :
1454 : /**
1455 : * \brief Fetch the pixel data type for this band.
1456 : *
1457 : * @see GDALRasterBand::GetRasterDataType()
1458 : */
1459 :
1460 905666 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1461 :
1462 : {
1463 905666 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1464 :
1465 905666 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1466 905666 : return poBand->GetRasterDataType();
1467 : }
1468 :
1469 : /************************************************************************/
1470 : /* GetBlockSize() */
1471 : /************************************************************************/
1472 :
1473 : /**
1474 : * \brief Fetch the "natural" block size of this band.
1475 : *
1476 : * GDAL contains a concept of the natural block size of rasters so that
1477 : * applications can organized data access efficiently for some file formats.
1478 : * The natural block size is the block size that is most efficient for
1479 : * accessing the format. For many formats this is simple a whole scanline
1480 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1481 : *
1482 : * However, for tiled images this will typically be the tile size.
1483 : *
1484 : * Note that the X and Y block sizes don't have to divide the image size
1485 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1486 : * See ReadBlock() for an example of code dealing with these issues.
1487 : *
1488 : * This method is the same as the C function GDALGetBlockSize().
1489 : *
1490 : * @param pnXSize integer to put the X block size into or NULL.
1491 : *
1492 : * @param pnYSize integer to put the Y block size into or NULL.
1493 : */
1494 :
1495 5543050 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1496 :
1497 : {
1498 5543050 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1499 : {
1500 329 : ReportError(CE_Failure, CPLE_AppDefined,
1501 329 : "Invalid block dimension : %d * %d", nBlockXSize,
1502 329 : nBlockYSize);
1503 4 : if (pnXSize != nullptr)
1504 4 : *pnXSize = 0;
1505 4 : if (pnYSize != nullptr)
1506 4 : *pnYSize = 0;
1507 : }
1508 : else
1509 : {
1510 5542720 : if (pnXSize != nullptr)
1511 5542570 : *pnXSize = nBlockXSize;
1512 5542720 : if (pnYSize != nullptr)
1513 5542920 : *pnYSize = nBlockYSize;
1514 : }
1515 5542730 : }
1516 :
1517 : /************************************************************************/
1518 : /* GDALGetBlockSize() */
1519 : /************************************************************************/
1520 :
1521 : /**
1522 : * \brief Fetch the "natural" block size of this band.
1523 : *
1524 : * @see GDALRasterBand::GetBlockSize()
1525 : */
1526 :
1527 41134 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1528 : int *pnYSize)
1529 :
1530 : {
1531 41134 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1532 :
1533 41134 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1534 41134 : poBand->GetBlockSize(pnXSize, pnYSize);
1535 : }
1536 :
1537 : /************************************************************************/
1538 : /* InitBlockInfo() */
1539 : /************************************************************************/
1540 :
1541 : //! @cond Doxygen_Suppress
1542 3645560 : int GDALRasterBand::InitBlockInfo()
1543 :
1544 : {
1545 3645560 : if (poBandBlockCache != nullptr)
1546 3407030 : return poBandBlockCache->IsInitOK();
1547 :
1548 : /* Do some validation of raster and block dimensions in case the driver */
1549 : /* would have neglected to do it itself */
1550 238531 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1551 : {
1552 4 : ReportError(CE_Failure, CPLE_AppDefined,
1553 : "Invalid block dimension : %d * %d", nBlockXSize,
1554 : nBlockYSize);
1555 0 : return FALSE;
1556 : }
1557 :
1558 238527 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1559 : {
1560 5 : ReportError(CE_Failure, CPLE_AppDefined,
1561 : "Invalid raster dimension : %d * %d", nRasterXSize,
1562 : nRasterYSize);
1563 0 : return FALSE;
1564 : }
1565 :
1566 238522 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1567 238524 : if (nDataTypeSize == 0)
1568 : {
1569 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1570 0 : return FALSE;
1571 : }
1572 :
1573 : #if SIZEOF_VOIDP == 4
1574 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1575 : {
1576 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1577 : * multiplication in other cases */
1578 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1579 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1580 : {
1581 : ReportError(CE_Failure, CPLE_NotSupported,
1582 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1583 : nBlockYSize);
1584 : return FALSE;
1585 : }
1586 : }
1587 : #endif
1588 :
1589 238525 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1590 238525 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1591 :
1592 : const char *pszBlockStrategy =
1593 238525 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1594 238529 : bool bUseArray = true;
1595 238529 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1596 : {
1597 238489 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1598 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1599 : {
1600 238470 : GUIntBig nBlockCount =
1601 238470 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1602 238470 : if (poDS != nullptr)
1603 238266 : nBlockCount *= poDS->GetRasterCount();
1604 238470 : bUseArray = (nBlockCount < 1024 * 1024);
1605 : }
1606 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1607 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1608 : {
1609 0 : bUseArray = false;
1610 238489 : }
1611 : }
1612 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1613 40 : bUseArray = false;
1614 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1615 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1616 : pszBlockStrategy);
1617 :
1618 238529 : if (bUseArray)
1619 238458 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1620 : else
1621 : {
1622 71 : if (nBand == 1)
1623 26 : CPLDebug("GDAL", "Use hashset band block cache");
1624 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1625 : }
1626 238529 : if (poBandBlockCache == nullptr)
1627 0 : return FALSE;
1628 238529 : return poBandBlockCache->Init();
1629 : }
1630 :
1631 : //! @endcond
1632 :
1633 : /************************************************************************/
1634 : /* FlushCache() */
1635 : /************************************************************************/
1636 :
1637 : /**
1638 : * \brief Flush raster data cache.
1639 : *
1640 : * This call will recover memory used to cache data blocks for this raster
1641 : * band, and ensure that new requests are referred to the underlying driver.
1642 : *
1643 : * This method is the same as the C function GDALFlushRasterCache().
1644 : *
1645 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1646 : * @return CE_None on success.
1647 : */
1648 :
1649 5631370 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1650 :
1651 : {
1652 5748280 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1653 116915 : poBandBlockCache)
1654 3149 : poBandBlockCache->DisableDirtyBlockWriting();
1655 :
1656 5631560 : CPLErr eGlobalErr = eFlushBlockErr;
1657 :
1658 5631560 : if (eFlushBlockErr != CE_None)
1659 : {
1660 0 : ReportError(
1661 : eFlushBlockErr, CPLE_AppDefined,
1662 : "An error occurred while writing a dirty block from FlushCache");
1663 0 : eFlushBlockErr = CE_None;
1664 : }
1665 :
1666 5631560 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1667 4870700 : return eGlobalErr;
1668 :
1669 760867 : return poBandBlockCache->FlushCache();
1670 : }
1671 :
1672 : /************************************************************************/
1673 : /* GDALFlushRasterCache() */
1674 : /************************************************************************/
1675 :
1676 : /**
1677 : * \brief Flush raster data cache.
1678 : *
1679 : * @see GDALRasterBand::FlushCache()
1680 : */
1681 :
1682 487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1683 :
1684 : {
1685 487 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1686 :
1687 487 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1688 : }
1689 :
1690 : /************************************************************************/
1691 : /* DropCache() */
1692 : /************************************************************************/
1693 :
1694 : /**
1695 : * \brief Drop raster data cache : data in cache will be lost.
1696 : *
1697 : * This call will recover memory used to cache data blocks for this raster
1698 : * band, and ensure that new requests are referred to the underlying driver.
1699 : *
1700 : * This method is the same as the C function GDALDropRasterCache().
1701 : *
1702 : * @return CE_None on success.
1703 : * @since 3.9
1704 : */
1705 :
1706 1 : CPLErr GDALRasterBand::DropCache()
1707 :
1708 : {
1709 1 : CPLErr result = CE_None;
1710 :
1711 1 : if (poBandBlockCache)
1712 1 : poBandBlockCache->DisableDirtyBlockWriting();
1713 :
1714 1 : CPLErr eGlobalErr = eFlushBlockErr;
1715 :
1716 1 : if (eFlushBlockErr != CE_None)
1717 : {
1718 0 : ReportError(
1719 : eFlushBlockErr, CPLE_AppDefined,
1720 : "An error occurred while writing a dirty block from DropCache");
1721 0 : eFlushBlockErr = CE_None;
1722 : }
1723 :
1724 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1725 0 : result = eGlobalErr;
1726 : else
1727 1 : result = poBandBlockCache->FlushCache();
1728 :
1729 1 : if (poBandBlockCache)
1730 1 : poBandBlockCache->EnableDirtyBlockWriting();
1731 :
1732 1 : return result;
1733 : }
1734 :
1735 : /************************************************************************/
1736 : /* GDALDropRasterCache() */
1737 : /************************************************************************/
1738 :
1739 : /**
1740 : * \brief Drop raster data cache.
1741 : *
1742 : * @see GDALRasterBand::DropCache()
1743 : * @since 3.9
1744 : */
1745 :
1746 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1747 :
1748 : {
1749 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1750 :
1751 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1752 : }
1753 :
1754 : /************************************************************************/
1755 : /* UnreferenceBlock() */
1756 : /* */
1757 : /* Unreference the block from our array of blocks */
1758 : /* This method should only be called by */
1759 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1760 : /* the block cache mutex) */
1761 : /************************************************************************/
1762 :
1763 29626 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1764 : {
1765 : #ifdef notdef
1766 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1767 : {
1768 : if (poBandBlockCache == nullptr)
1769 : printf("poBandBlockCache == NULL\n"); /*ok*/
1770 : else
1771 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1772 : printf("caller = %s\n", pszCaller); /*ok*/
1773 : printf("GDALRasterBand: %p\n", this); /*ok*/
1774 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1775 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1776 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1777 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1778 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1779 : poBlock->DumpBlock();
1780 : if (GetDataset() != nullptr)
1781 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1782 : GDALRasterBlock::Verify();
1783 : abort();
1784 : }
1785 : #endif
1786 29626 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1787 29626 : return poBandBlockCache->UnreferenceBlock(poBlock);
1788 : }
1789 :
1790 : /************************************************************************/
1791 : /* AddBlockToFreeList() */
1792 : /* */
1793 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1794 : /* finished with a block about to be free'd, they pass it to that */
1795 : /* method. */
1796 : /************************************************************************/
1797 :
1798 : //! @cond Doxygen_Suppress
1799 29626 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1800 : {
1801 29626 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1802 29626 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1803 : }
1804 :
1805 : //! @endcond
1806 :
1807 : /************************************************************************/
1808 : /* HasDirtyBlocks() */
1809 : /************************************************************************/
1810 :
1811 : //! @cond Doxygen_Suppress
1812 17 : bool GDALRasterBand::HasDirtyBlocks() const
1813 : {
1814 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1815 : }
1816 :
1817 : //! @endcond
1818 :
1819 : /************************************************************************/
1820 : /* FlushBlock() */
1821 : /************************************************************************/
1822 :
1823 : /** Flush a block out of the block cache.
1824 : * @param nXBlockOff block x offset
1825 : * @param nYBlockOff blocky offset
1826 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1827 : * @return CE_None in case of success, an error code otherwise.
1828 : */
1829 2311 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1830 : int bWriteDirtyBlock)
1831 :
1832 : {
1833 2311 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1834 0 : return (CE_Failure);
1835 :
1836 : /* -------------------------------------------------------------------- */
1837 : /* Validate the request */
1838 : /* -------------------------------------------------------------------- */
1839 2311 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1840 : {
1841 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1842 : "Illegal nBlockXOff value (%d) in "
1843 : "GDALRasterBand::FlushBlock()\n",
1844 : nXBlockOff);
1845 :
1846 0 : return (CE_Failure);
1847 : }
1848 :
1849 2311 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1850 : {
1851 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1852 : "Illegal nBlockYOff value (%d) in "
1853 : "GDALRasterBand::FlushBlock()\n",
1854 : nYBlockOff);
1855 :
1856 0 : return (CE_Failure);
1857 : }
1858 :
1859 2311 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1860 2311 : bWriteDirtyBlock);
1861 : }
1862 :
1863 : /************************************************************************/
1864 : /* TryGetLockedBlockRef() */
1865 : /************************************************************************/
1866 :
1867 : /**
1868 : * \brief Try fetching block ref.
1869 : *
1870 : * This method will returned the requested block (locked) if it is already
1871 : * in the block cache for the layer. If not, nullptr is returned.
1872 : *
1873 : * If a non-NULL value is returned, then a lock for the block will have been
1874 : * acquired on behalf of the caller. It is absolutely imperative that the
1875 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1876 : * severe problems may result.
1877 : *
1878 : * @param nXBlockOff the horizontal block offset, with zero indicating
1879 : * the left most block, 1 the next block and so forth.
1880 : *
1881 : * @param nYBlockOff the vertical block offset, with zero indicating
1882 : * the top most block, 1 the next block and so forth.
1883 : *
1884 : * @return NULL if block not available, or locked block pointer.
1885 : */
1886 :
1887 10639000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1888 : int nYBlockOff)
1889 :
1890 : {
1891 10639000 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1892 172380 : return nullptr;
1893 :
1894 : /* -------------------------------------------------------------------- */
1895 : /* Validate the request */
1896 : /* -------------------------------------------------------------------- */
1897 10466700 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1898 : {
1899 22 : ReportError(CE_Failure, CPLE_IllegalArg,
1900 : "Illegal nBlockXOff value (%d) in "
1901 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1902 : nXBlockOff);
1903 :
1904 0 : return (nullptr);
1905 : }
1906 :
1907 10466600 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1908 : {
1909 20 : ReportError(CE_Failure, CPLE_IllegalArg,
1910 : "Illegal nBlockYOff value (%d) in "
1911 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1912 : nYBlockOff);
1913 :
1914 0 : return (nullptr);
1915 : }
1916 :
1917 10466600 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1918 : }
1919 :
1920 : /************************************************************************/
1921 : /* GetLockedBlockRef() */
1922 : /************************************************************************/
1923 :
1924 : /**
1925 : * \brief Fetch a pointer to an internally cached raster block.
1926 : *
1927 : * This method will returned the requested block (locked) if it is already
1928 : * in the block cache for the layer. If not, the block will be read from
1929 : * the driver, and placed in the layer block cached, then returned. If an
1930 : * error occurs reading the block from the driver, a NULL value will be
1931 : * returned.
1932 : *
1933 : * If a non-NULL value is returned, then a lock for the block will have been
1934 : * acquired on behalf of the caller. It is absolutely imperative that the
1935 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1936 : * severe problems may result.
1937 : *
1938 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1939 : * enable caching.
1940 : *
1941 : * @param nXBlockOff the horizontal block offset, with zero indicating
1942 : * the left most block, 1 the next block and so forth.
1943 : *
1944 : * @param nYBlockOff the vertical block offset, with zero indicating
1945 : * the top most block, 1 the next block and so forth.
1946 : *
1947 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1948 : * but not actually read from the source. This is useful when it will just
1949 : * be completely set and written back.
1950 : *
1951 : * @return pointer to the block object, or NULL on failure.
1952 : */
1953 :
1954 10329400 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1955 : int nYBlockOff,
1956 : int bJustInitialize)
1957 :
1958 : {
1959 : /* -------------------------------------------------------------------- */
1960 : /* Try and fetch from cache. */
1961 : /* -------------------------------------------------------------------- */
1962 10329400 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1963 :
1964 : /* -------------------------------------------------------------------- */
1965 : /* If we didn't find it in our memory cache, instantiate a */
1966 : /* block (potentially load from disk) and "adopt" it into the */
1967 : /* cache. */
1968 : /* -------------------------------------------------------------------- */
1969 10329500 : if (poBlock == nullptr)
1970 : {
1971 3368630 : if (!InitBlockInfo())
1972 0 : return (nullptr);
1973 :
1974 : /* --------------------------------------------------------------------
1975 : */
1976 : /* Validate the request */
1977 : /* --------------------------------------------------------------------
1978 : */
1979 3368620 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1980 : {
1981 13 : ReportError(CE_Failure, CPLE_IllegalArg,
1982 : "Illegal nBlockXOff value (%d) in "
1983 : "GDALRasterBand::GetLockedBlockRef()\n",
1984 : nXBlockOff);
1985 :
1986 0 : return (nullptr);
1987 : }
1988 :
1989 3368600 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1990 : {
1991 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1992 : "Illegal nBlockYOff value (%d) in "
1993 : "GDALRasterBand::GetLockedBlockRef()\n",
1994 : nYBlockOff);
1995 :
1996 0 : return (nullptr);
1997 : }
1998 :
1999 3368610 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2000 3368620 : if (poBlock == nullptr)
2001 0 : return nullptr;
2002 :
2003 3368620 : poBlock->AddLock();
2004 :
2005 : /* We need to temporarily drop the read-write lock in the following */
2006 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2007 : */
2008 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2009 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2010 : */
2011 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2012 : */
2013 : /* called and attempt at taking the lock on T2 (already taken).
2014 : * Similarly */
2015 : /* for T2 with D1, hence a deadlock situation (#6163) */
2016 : /* But this may open the door to other problems... */
2017 3368640 : if (poDS)
2018 3367900 : poDS->TemporarilyDropReadWriteLock();
2019 : /* allocate data space */
2020 3368630 : CPLErr eErr = poBlock->Internalize();
2021 3368660 : if (poDS)
2022 3367910 : poDS->ReacquireReadWriteLock();
2023 3368650 : if (eErr != CE_None)
2024 : {
2025 0 : poBlock->DropLock();
2026 0 : delete poBlock;
2027 0 : return nullptr;
2028 : }
2029 :
2030 3368650 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2031 : {
2032 0 : poBlock->DropLock();
2033 0 : delete poBlock;
2034 0 : return nullptr;
2035 : }
2036 :
2037 3368650 : if (!bJustInitialize)
2038 : {
2039 2882760 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2040 2882760 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2041 2882770 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2042 2882770 : if (bCallLeaveReadWrite)
2043 130213 : LeaveReadWrite();
2044 2882750 : if (eErr != CE_None)
2045 : {
2046 1161 : poBlock->DropLock();
2047 1161 : FlushBlock(nXBlockOff, nYBlockOff);
2048 1161 : ReportError(CE_Failure, CPLE_AppDefined,
2049 : "IReadBlock failed at X offset %d, Y offset %d%s",
2050 : nXBlockOff, nYBlockOff,
2051 1161 : (nErrorCounter != CPLGetErrorCounter())
2052 1159 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2053 : : "");
2054 1161 : return nullptr;
2055 : }
2056 :
2057 2881590 : nBlockReads++;
2058 2881590 : if (static_cast<GIntBig>(nBlockReads) ==
2059 2881590 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2060 223 : 1 &&
2061 223 : nBand == 1 && poDS != nullptr)
2062 : {
2063 163 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2064 163 : poDS->GetDescription());
2065 : }
2066 : }
2067 : }
2068 :
2069 10328400 : return poBlock;
2070 : }
2071 :
2072 : /************************************************************************/
2073 : /* Fill() */
2074 : /************************************************************************/
2075 :
2076 : /**
2077 : * \brief Fill this band with a constant value.
2078 : *
2079 : * GDAL makes no guarantees
2080 : * about what values pixels in newly created files are set to, so this
2081 : * method can be used to clear a band to a specified "default" value.
2082 : * The fill value is passed in as a double but this will be converted
2083 : * to the underlying type before writing to the file. An optional
2084 : * second argument allows the imaginary component of a complex
2085 : * constant value to be specified.
2086 : *
2087 : * This method is the same as the C function GDALFillRaster().
2088 : *
2089 : * @param dfRealValue Real component of fill value
2090 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2091 : *
2092 : * @return CE_Failure if the write fails, otherwise CE_None
2093 : */
2094 268829 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2095 : {
2096 :
2097 : // General approach is to construct a source block of the file's
2098 : // native type containing the appropriate value and then copy this
2099 : // to each block in the image via the RasterBlock cache. Using
2100 : // the cache means we avoid file I/O if it is not necessary, at the
2101 : // expense of some extra memcpy's (since we write to the
2102 : // RasterBlock cache, which is then at some point written to the
2103 : // underlying file, rather than simply directly to the underlying
2104 : // file.)
2105 :
2106 : // Check we can write to the file.
2107 268829 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2108 : {
2109 6 : return CE_Failure;
2110 : }
2111 :
2112 : // Make sure block parameters are set.
2113 268823 : if (!InitBlockInfo())
2114 0 : return CE_Failure;
2115 :
2116 : // Allocate the source block.
2117 268823 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2118 268823 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2119 268823 : auto blockByteSize = blockSize * elementSize;
2120 : unsigned char *srcBlock =
2121 268823 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2122 268823 : if (srcBlock == nullptr)
2123 : {
2124 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2125 : "GDALRasterBand::Fill(): Out of memory "
2126 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2127 : static_cast<GUIntBig>(blockByteSize));
2128 0 : return CE_Failure;
2129 : }
2130 :
2131 : // Initialize the source block.
2132 268823 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2133 268823 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2134 : elementSize, blockSize);
2135 :
2136 268823 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2137 :
2138 : // Write block to block cache
2139 872262 : for (int j = 0; j < nBlocksPerColumn; ++j)
2140 : {
2141 1501220 : for (int i = 0; i < nBlocksPerRow; ++i)
2142 : {
2143 897786 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2144 897786 : if (destBlock == nullptr)
2145 : {
2146 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2147 : "GDALRasterBand::Fill(): Error "
2148 : "while retrieving cache block.");
2149 0 : VSIFree(srcBlock);
2150 0 : return CE_Failure;
2151 : }
2152 897786 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2153 897786 : destBlock->MarkDirty();
2154 897786 : destBlock->DropLock();
2155 : }
2156 : }
2157 :
2158 268823 : if (bCallLeaveReadWrite)
2159 267647 : LeaveReadWrite();
2160 :
2161 : // Free up the source block
2162 268823 : VSIFree(srcBlock);
2163 :
2164 268823 : return CE_None;
2165 : }
2166 :
2167 : /************************************************************************/
2168 : /* GDALFillRaster() */
2169 : /************************************************************************/
2170 :
2171 : /**
2172 : * \brief Fill this band with a constant value.
2173 : *
2174 : * @see GDALRasterBand::Fill()
2175 : */
2176 268633 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2177 : double dfImaginaryValue)
2178 : {
2179 268633 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2180 :
2181 268633 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2182 268633 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2183 : }
2184 :
2185 : /************************************************************************/
2186 : /* GetAccess() */
2187 : /************************************************************************/
2188 :
2189 : /**
2190 : * \brief Find out if we have update permission for this band.
2191 : *
2192 : * This method is the same as the C function GDALGetRasterAccess().
2193 : *
2194 : * @return Either GA_Update or GA_ReadOnly.
2195 : */
2196 :
2197 2995 : GDALAccess GDALRasterBand::GetAccess()
2198 :
2199 : {
2200 2995 : return eAccess;
2201 : }
2202 :
2203 : /************************************************************************/
2204 : /* GDALGetRasterAccess() */
2205 : /************************************************************************/
2206 :
2207 : /**
2208 : * \brief Find out if we have update permission for this band.
2209 : *
2210 : * @see GDALRasterBand::GetAccess()
2211 : */
2212 :
2213 2337 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2214 :
2215 : {
2216 2337 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2217 :
2218 2337 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2219 2337 : return poBand->GetAccess();
2220 : }
2221 :
2222 : /************************************************************************/
2223 : /* GetCategoryNames() */
2224 : /************************************************************************/
2225 :
2226 : /**
2227 : * \brief Fetch the list of category names for this raster.
2228 : *
2229 : * The return list is a "StringList" in the sense of the CPL functions.
2230 : * That is a NULL terminated array of strings. Raster values without
2231 : * associated names will have an empty string in the returned list. The
2232 : * first entry in the list is for raster values of zero, and so on.
2233 : *
2234 : * The returned stringlist should not be altered or freed by the application.
2235 : * It may change on the next GDAL call, so please copy it if it is needed
2236 : * for any period of time.
2237 : *
2238 : * This method is the same as the C function GDALGetRasterCategoryNames().
2239 : *
2240 : * @return list of names, or NULL if none.
2241 : */
2242 :
2243 262 : char **GDALRasterBand::GetCategoryNames()
2244 :
2245 : {
2246 262 : return nullptr;
2247 : }
2248 :
2249 : /************************************************************************/
2250 : /* GDALGetRasterCategoryNames() */
2251 : /************************************************************************/
2252 :
2253 : /**
2254 : * \brief Fetch the list of category names for this raster.
2255 : *
2256 : * @see GDALRasterBand::GetCategoryNames()
2257 : */
2258 :
2259 198 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2260 :
2261 : {
2262 198 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2263 :
2264 198 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2265 198 : return poBand->GetCategoryNames();
2266 : }
2267 :
2268 : /************************************************************************/
2269 : /* SetCategoryNames() */
2270 : /************************************************************************/
2271 :
2272 : /**
2273 : * \fn GDALRasterBand::SetCategoryNames(char**)
2274 : * \brief Set the category names for this band.
2275 : *
2276 : * See the GetCategoryNames() method for more on the interpretation of
2277 : * category names.
2278 : *
2279 : * This method is the same as the C function GDALSetRasterCategoryNames().
2280 : *
2281 : * @param papszNames the NULL terminated StringList of category names. May
2282 : * be NULL to just clear the existing list.
2283 : *
2284 : * @return CE_None on success of CE_Failure on failure. If unsupported
2285 : * by the driver CE_Failure is returned, but no error message is reported.
2286 : */
2287 :
2288 : /**/
2289 : /**/
2290 :
2291 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2292 : {
2293 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2294 0 : ReportError(CE_Failure, CPLE_NotSupported,
2295 : "SetCategoryNames() not supported for this dataset.");
2296 :
2297 0 : return CE_Failure;
2298 : }
2299 :
2300 : /************************************************************************/
2301 : /* GDALSetCategoryNames() */
2302 : /************************************************************************/
2303 :
2304 : /**
2305 : * \brief Set the category names for this band.
2306 : *
2307 : * @see GDALRasterBand::SetCategoryNames()
2308 : */
2309 :
2310 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2311 : CSLConstList papszNames)
2312 :
2313 : {
2314 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2315 :
2316 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2317 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2318 : }
2319 :
2320 : /************************************************************************/
2321 : /* GetNoDataValue() */
2322 : /************************************************************************/
2323 :
2324 : /**
2325 : * \brief Fetch the no data value for this band.
2326 : *
2327 : * If there is no out of data value, an out of range value will generally
2328 : * be returned. The no data value for a band is generally a special marker
2329 : * value used to mark pixels that are not valid data. Such pixels should
2330 : * generally not be displayed, nor contribute to analysis operations.
2331 : *
2332 : * The no data value returned is 'raw', meaning that it has no offset and
2333 : * scale applied.
2334 : *
2335 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2336 : * lossy if the nodata value cannot exactly been represented by a double.
2337 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2338 : *
2339 : * This method is the same as the C function GDALGetRasterNoDataValue().
2340 : *
2341 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2342 : * is actually associated with this layer. May be NULL (default).
2343 : *
2344 : * @return the nodata value for this band.
2345 : */
2346 :
2347 13079 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2348 :
2349 : {
2350 13079 : if (pbSuccess != nullptr)
2351 13079 : *pbSuccess = FALSE;
2352 :
2353 13079 : return -1e10;
2354 : }
2355 :
2356 : /************************************************************************/
2357 : /* GDALGetRasterNoDataValue() */
2358 : /************************************************************************/
2359 :
2360 : /**
2361 : * \brief Fetch the no data value for this band.
2362 : *
2363 : * @see GDALRasterBand::GetNoDataValue()
2364 : */
2365 :
2366 414435 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2367 : int *pbSuccess)
2368 :
2369 : {
2370 414435 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2371 :
2372 414435 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2373 414435 : return poBand->GetNoDataValue(pbSuccess);
2374 : }
2375 :
2376 : /************************************************************************/
2377 : /* GetNoDataValueAsInt64() */
2378 : /************************************************************************/
2379 :
2380 : /**
2381 : * \brief Fetch the no data value for this band.
2382 : *
2383 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2384 : *
2385 : * If there is no out of data value, an out of range value will generally
2386 : * be returned. The no data value for a band is generally a special marker
2387 : * value used to mark pixels that are not valid data. Such pixels should
2388 : * generally not be displayed, nor contribute to analysis operations.
2389 : *
2390 : * The no data value returned is 'raw', meaning that it has no offset and
2391 : * scale applied.
2392 : *
2393 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2394 : *
2395 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2396 : * is actually associated with this layer. May be NULL (default).
2397 : *
2398 : * @return the nodata value for this band.
2399 : *
2400 : * @since GDAL 3.5
2401 : */
2402 :
2403 3 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2404 :
2405 : {
2406 3 : if (pbSuccess != nullptr)
2407 3 : *pbSuccess = FALSE;
2408 :
2409 3 : return std::numeric_limits<int64_t>::min();
2410 : }
2411 :
2412 : /************************************************************************/
2413 : /* GDALGetRasterNoDataValueAsInt64() */
2414 : /************************************************************************/
2415 :
2416 : /**
2417 : * \brief Fetch the no data value for this band.
2418 : *
2419 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2420 : *
2421 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2422 : *
2423 : * @since GDAL 3.5
2424 : */
2425 :
2426 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2427 : int *pbSuccess)
2428 :
2429 : {
2430 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2431 : std::numeric_limits<int64_t>::min());
2432 :
2433 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2434 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2435 : }
2436 :
2437 : /************************************************************************/
2438 : /* GetNoDataValueAsUInt64() */
2439 : /************************************************************************/
2440 :
2441 : /**
2442 : * \brief Fetch the no data value for this band.
2443 : *
2444 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2445 : *
2446 : * If there is no out of data value, an out of range value will generally
2447 : * be returned. The no data value for a band is generally a special marker
2448 : * value used to mark pixels that are not valid data. Such pixels should
2449 : * generally not be displayed, nor contribute to analysis operations.
2450 : *
2451 : * The no data value returned is 'raw', meaning that it has no offset and
2452 : * scale applied.
2453 : *
2454 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2455 : *
2456 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2457 : * is actually associated with this layer. May be NULL (default).
2458 : *
2459 : * @return the nodata value for this band.
2460 : *
2461 : * @since GDAL 3.5
2462 : */
2463 :
2464 2 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2465 :
2466 : {
2467 2 : if (pbSuccess != nullptr)
2468 2 : *pbSuccess = FALSE;
2469 :
2470 2 : return std::numeric_limits<uint64_t>::max();
2471 : }
2472 :
2473 : /************************************************************************/
2474 : /* GDALGetRasterNoDataValueAsUInt64() */
2475 : /************************************************************************/
2476 :
2477 : /**
2478 : * \brief Fetch the no data value for this band.
2479 : *
2480 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2481 : *
2482 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2483 : *
2484 : * @since GDAL 3.5
2485 : */
2486 :
2487 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2488 : int *pbSuccess)
2489 :
2490 : {
2491 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2492 : std::numeric_limits<uint64_t>::max());
2493 :
2494 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2495 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2496 : }
2497 :
2498 : /************************************************************************/
2499 : /* SetNoDataValueAsString() */
2500 : /************************************************************************/
2501 :
2502 : /**
2503 : * \brief Set the no data value for this band.
2504 : *
2505 : * Depending on drivers, changing the no data value may or may not have an
2506 : * effect on the pixel values of a raster that has just been created. It is
2507 : * thus advised to explicitly called Fill() if the intent is to initialize
2508 : * the raster to the nodata value.
2509 : * In any case, changing an existing no data value, when one already exists and
2510 : * the dataset exists or has been initialized, has no effect on the pixel whose
2511 : * value matched the previous nodata value.
2512 : *
2513 : * To clear the nodata value, use DeleteNoDataValue().
2514 : *
2515 : * @param pszNoData the value to set.
2516 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2517 : * If the value cannot be exactly represented on the output data
2518 : * type, *pbCannotBeExactlyRepresented will be set to true.
2519 : *
2520 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2521 : * by the driver, CE_Failure is returned but no error message will have
2522 : * been emitted.
2523 : *
2524 : * @since 3.11
2525 : */
2526 :
2527 : CPLErr
2528 123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2529 : bool *pbCannotBeExactlyRepresented)
2530 : {
2531 123 : if (pbCannotBeExactlyRepresented)
2532 123 : *pbCannotBeExactlyRepresented = false;
2533 123 : if (eDataType == GDT_Int64)
2534 : {
2535 8 : if (strchr(pszNoData, '.') ||
2536 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2537 : {
2538 2 : char *endptr = nullptr;
2539 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2540 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2541 2 : GDALIsValueExactAs<int64_t>(dfVal))
2542 : {
2543 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2544 : }
2545 : }
2546 : else
2547 : {
2548 : try
2549 : {
2550 7 : const auto val = std::stoll(pszNoData);
2551 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2552 : }
2553 2 : catch (const std::exception &)
2554 : {
2555 : }
2556 : }
2557 : }
2558 118 : else if (eDataType == GDT_UInt64)
2559 : {
2560 2 : if (strchr(pszNoData, '.') ||
2561 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2562 : {
2563 0 : char *endptr = nullptr;
2564 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2565 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2566 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2567 : {
2568 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2569 : }
2570 : }
2571 : else
2572 : {
2573 : try
2574 : {
2575 1 : const auto val = std::stoull(pszNoData);
2576 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2577 : }
2578 0 : catch (const std::exception &)
2579 : {
2580 : }
2581 : }
2582 : }
2583 117 : else if (eDataType == GDT_Float32)
2584 : {
2585 10 : char *endptr = nullptr;
2586 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2587 10 : if (endptr == pszNoData + strlen(pszNoData))
2588 : {
2589 10 : return SetNoDataValue(double(fVal));
2590 : }
2591 : }
2592 : else
2593 : {
2594 107 : char *endptr = nullptr;
2595 107 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2596 214 : if (endptr == pszNoData + strlen(pszNoData) &&
2597 107 : GDALIsValueExactAs(dfVal, eDataType))
2598 : {
2599 106 : return SetNoDataValue(dfVal);
2600 : }
2601 : }
2602 5 : if (pbCannotBeExactlyRepresented)
2603 5 : *pbCannotBeExactlyRepresented = true;
2604 5 : return CE_Failure;
2605 : }
2606 :
2607 : /************************************************************************/
2608 : /* SetNoDataValue() */
2609 : /************************************************************************/
2610 :
2611 : /**
2612 : * \fn GDALRasterBand::SetNoDataValue(double)
2613 : * \brief Set the no data value for this band.
2614 : *
2615 : * Depending on drivers, changing the no data value may or may not have an
2616 : * effect on the pixel values of a raster that has just been created. It is
2617 : * thus advised to explicitly called Fill() if the intent is to initialize
2618 : * the raster to the nodata value.
2619 : * In any case, changing an existing no data value, when one already exists and
2620 : * the dataset exists or has been initialized, has no effect on the pixel whose
2621 : * value matched the previous nodata value.
2622 : *
2623 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2624 : * be represented by a double, use SetNoDataValueAsInt64() or
2625 : * SetNoDataValueAsUInt64() instead.
2626 : *
2627 : * To clear the nodata value, use DeleteNoDataValue().
2628 : *
2629 : * This method is the same as the C function GDALSetRasterNoDataValue().
2630 : *
2631 : * @param dfNoData the value to set.
2632 : *
2633 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2634 : * by the driver, CE_Failure is returned but no error message will have
2635 : * been emitted.
2636 : */
2637 :
2638 : /**/
2639 : /**/
2640 :
2641 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2642 :
2643 : {
2644 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2645 0 : ReportError(CE_Failure, CPLE_NotSupported,
2646 : "SetNoDataValue() not supported for this dataset.");
2647 :
2648 0 : return CE_Failure;
2649 : }
2650 :
2651 : /************************************************************************/
2652 : /* GDALSetRasterNoDataValue() */
2653 : /************************************************************************/
2654 :
2655 : /**
2656 : * \brief Set the no data value for this band.
2657 : *
2658 : * Depending on drivers, changing the no data value may or may not have an
2659 : * effect on the pixel values of a raster that has just been created. It is
2660 : * thus advised to explicitly called Fill() if the intent is to initialize
2661 : * the raster to the nodata value.
2662 : * In any case, changing an existing no data value, when one already exists and
2663 : * the dataset exists or has been initialized, has no effect on the pixel whose
2664 : * value matched the previous nodata value.
2665 : *
2666 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2667 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2668 : * GDALSetRasterNoDataValueAsUInt64() instead.
2669 : *
2670 : * @see GDALRasterBand::SetNoDataValue()
2671 : */
2672 :
2673 968 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2674 : double dfValue)
2675 :
2676 : {
2677 968 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2678 :
2679 968 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2680 968 : return poBand->SetNoDataValue(dfValue);
2681 : }
2682 :
2683 : /************************************************************************/
2684 : /* SetNoDataValueAsInt64() */
2685 : /************************************************************************/
2686 :
2687 : /**
2688 : * \brief Set the no data value for this band.
2689 : *
2690 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2691 : *
2692 : * Depending on drivers, changing the no data value may or may not have an
2693 : * effect on the pixel values of a raster that has just been created. It is
2694 : * thus advised to explicitly called Fill() if the intent is to initialize
2695 : * the raster to the nodata value.
2696 : * In ay case, changing an existing no data value, when one already exists and
2697 : * the dataset exists or has been initialized, has no effect on the pixel whose
2698 : * value matched the previous nodata value.
2699 : *
2700 : * To clear the nodata value, use DeleteNoDataValue().
2701 : *
2702 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2703 : *
2704 : * @param nNoDataValue the value to set.
2705 : *
2706 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2707 : * by the driver, CE_Failure is returned but no error message will have
2708 : * been emitted.
2709 : *
2710 : * @since GDAL 3.5
2711 : */
2712 :
2713 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2714 :
2715 : {
2716 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2717 0 : ReportError(CE_Failure, CPLE_NotSupported,
2718 : "SetNoDataValueAsInt64() not supported for this dataset.");
2719 :
2720 0 : return CE_Failure;
2721 : }
2722 :
2723 : /************************************************************************/
2724 : /* GDALSetRasterNoDataValueAsInt64() */
2725 : /************************************************************************/
2726 :
2727 : /**
2728 : * \brief Set the no data value for this band.
2729 : *
2730 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2731 : *
2732 : * Depending on drivers, changing the no data value may or may not have an
2733 : * effect on the pixel values of a raster that has just been created. It is
2734 : * thus advised to explicitly called Fill() if the intent is to initialize
2735 : * the raster to the nodata value.
2736 : * In ay case, changing an existing no data value, when one already exists and
2737 : * the dataset exists or has been initialized, has no effect on the pixel whose
2738 : * value matched the previous nodata value.
2739 : *
2740 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2741 : *
2742 : * @since GDAL 3.5
2743 : */
2744 :
2745 22 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2746 : int64_t nValue)
2747 :
2748 : {
2749 22 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2750 :
2751 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2752 22 : return poBand->SetNoDataValueAsInt64(nValue);
2753 : }
2754 :
2755 : /************************************************************************/
2756 : /* SetNoDataValueAsUInt64() */
2757 : /************************************************************************/
2758 :
2759 : /**
2760 : * \brief Set the no data value for this band.
2761 : *
2762 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2763 : *
2764 : * Depending on drivers, changing the no data value may or may not have an
2765 : * effect on the pixel values of a raster that has just been created. It is
2766 : * thus advised to explicitly called Fill() if the intent is to initialize
2767 : * the raster to the nodata value.
2768 : * In ay case, changing an existing no data value, when one already exists and
2769 : * the dataset exists or has been initialized, has no effect on the pixel whose
2770 : * value matched the previous nodata value.
2771 : *
2772 : * To clear the nodata value, use DeleteNoDataValue().
2773 : *
2774 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2775 : *
2776 : * @param nNoDataValue the value to set.
2777 : *
2778 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2779 : * by the driver, CE_Failure is returned but no error message will have
2780 : * been emitted.
2781 : *
2782 : * @since GDAL 3.5
2783 : */
2784 :
2785 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2786 :
2787 : {
2788 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2789 0 : ReportError(CE_Failure, CPLE_NotSupported,
2790 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2791 :
2792 0 : return CE_Failure;
2793 : }
2794 :
2795 : /************************************************************************/
2796 : /* GDALSetRasterNoDataValueAsUInt64() */
2797 : /************************************************************************/
2798 :
2799 : /**
2800 : * \brief Set the no data value for this band.
2801 : *
2802 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2803 : *
2804 : * Depending on drivers, changing the no data value may or may not have an
2805 : * effect on the pixel values of a raster that has just been created. It is
2806 : * thus advised to explicitly called Fill() if the intent is to initialize
2807 : * the raster to the nodata value.
2808 : * In ay case, changing an existing no data value, when one already exists and
2809 : * the dataset exists or has been initialized, has no effect on the pixel whose
2810 : * value matched the previous nodata value.
2811 : *
2812 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2813 : *
2814 : * @since GDAL 3.5
2815 : */
2816 :
2817 20 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2818 : uint64_t nValue)
2819 :
2820 : {
2821 20 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2822 :
2823 20 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2824 20 : return poBand->SetNoDataValueAsUInt64(nValue);
2825 : }
2826 :
2827 : /************************************************************************/
2828 : /* DeleteNoDataValue() */
2829 : /************************************************************************/
2830 :
2831 : /**
2832 : * \brief Remove the no data value for this band.
2833 : *
2834 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2835 : *
2836 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2837 : * by the driver, CE_Failure is returned but no error message will have
2838 : * been emitted.
2839 : *
2840 : */
2841 :
2842 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2843 :
2844 : {
2845 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2846 0 : ReportError(CE_Failure, CPLE_NotSupported,
2847 : "DeleteNoDataValue() not supported for this dataset.");
2848 :
2849 0 : return CE_Failure;
2850 : }
2851 :
2852 : /************************************************************************/
2853 : /* GDALDeleteRasterNoDataValue() */
2854 : /************************************************************************/
2855 :
2856 : /**
2857 : * \brief Remove the no data value for this band.
2858 : *
2859 : * @see GDALRasterBand::DeleteNoDataValue()
2860 : *
2861 : */
2862 :
2863 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2864 :
2865 : {
2866 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2867 :
2868 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2869 53 : return poBand->DeleteNoDataValue();
2870 : }
2871 :
2872 : /************************************************************************/
2873 : /* GetMaximum() */
2874 : /************************************************************************/
2875 :
2876 : /**
2877 : * \brief Fetch the maximum value for this band.
2878 : *
2879 : * For file formats that don't know this intrinsically, the maximum supported
2880 : * value for the data type will generally be returned.
2881 : *
2882 : * This method is the same as the C function GDALGetRasterMaximum().
2883 : *
2884 : * @param pbSuccess pointer to a boolean to use to indicate if the
2885 : * returned value is a tight maximum or not. May be NULL (default).
2886 : *
2887 : * @return the maximum raster value (excluding no data pixels)
2888 : */
2889 :
2890 531 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2891 :
2892 : {
2893 531 : const char *pszValue = nullptr;
2894 :
2895 531 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2896 : {
2897 47 : if (pbSuccess != nullptr)
2898 42 : *pbSuccess = TRUE;
2899 :
2900 47 : return CPLAtofM(pszValue);
2901 : }
2902 :
2903 484 : if (pbSuccess != nullptr)
2904 480 : *pbSuccess = FALSE;
2905 :
2906 484 : switch (eDataType)
2907 : {
2908 333 : case GDT_Byte:
2909 : {
2910 333 : EnablePixelTypeSignedByteWarning(false);
2911 : const char *pszPixelType =
2912 333 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2913 333 : EnablePixelTypeSignedByteWarning(true);
2914 333 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2915 0 : return 127;
2916 :
2917 333 : return 255;
2918 : }
2919 :
2920 1 : case GDT_Int8:
2921 1 : return 127;
2922 :
2923 21 : case GDT_UInt16:
2924 21 : return 65535;
2925 :
2926 24 : case GDT_Int16:
2927 : case GDT_CInt16:
2928 24 : return 32767;
2929 :
2930 39 : case GDT_Int32:
2931 : case GDT_CInt32:
2932 39 : return 2147483647.0;
2933 :
2934 12 : case GDT_UInt32:
2935 12 : return 4294967295.0;
2936 :
2937 1 : case GDT_Int64:
2938 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2939 :
2940 1 : case GDT_UInt64:
2941 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2942 :
2943 0 : case GDT_Float16:
2944 : case GDT_CFloat16:
2945 0 : return 65504.0;
2946 :
2947 30 : case GDT_Float32:
2948 : case GDT_CFloat32:
2949 30 : return 4294967295.0; // Not actually accurate.
2950 :
2951 22 : case GDT_Float64:
2952 : case GDT_CFloat64:
2953 22 : return 4294967295.0; // Not actually accurate.
2954 :
2955 0 : case GDT_Unknown:
2956 : case GDT_TypeCount:
2957 0 : break;
2958 : }
2959 0 : return 4294967295.0; // Not actually accurate.
2960 : }
2961 :
2962 : /************************************************************************/
2963 : /* GDALGetRasterMaximum() */
2964 : /************************************************************************/
2965 :
2966 : /**
2967 : * \brief Fetch the maximum value for this band.
2968 : *
2969 : * @see GDALRasterBand::GetMaximum()
2970 : */
2971 :
2972 331 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2973 :
2974 : {
2975 331 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2976 :
2977 331 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2978 331 : return poBand->GetMaximum(pbSuccess);
2979 : }
2980 :
2981 : /************************************************************************/
2982 : /* GetMinimum() */
2983 : /************************************************************************/
2984 :
2985 : /**
2986 : * \brief Fetch the minimum value for this band.
2987 : *
2988 : * For file formats that don't know this intrinsically, the minimum supported
2989 : * value for the data type will generally be returned.
2990 : *
2991 : * This method is the same as the C function GDALGetRasterMinimum().
2992 : *
2993 : * @param pbSuccess pointer to a boolean to use to indicate if the
2994 : * returned value is a tight minimum or not. May be NULL (default).
2995 : *
2996 : * @return the minimum raster value (excluding no data pixels)
2997 : */
2998 :
2999 539 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3000 :
3001 : {
3002 539 : const char *pszValue = nullptr;
3003 :
3004 539 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3005 : {
3006 52 : if (pbSuccess != nullptr)
3007 47 : *pbSuccess = TRUE;
3008 :
3009 52 : return CPLAtofM(pszValue);
3010 : }
3011 :
3012 487 : if (pbSuccess != nullptr)
3013 483 : *pbSuccess = FALSE;
3014 :
3015 487 : switch (eDataType)
3016 : {
3017 336 : case GDT_Byte:
3018 : {
3019 336 : EnablePixelTypeSignedByteWarning(false);
3020 : const char *pszPixelType =
3021 336 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3022 336 : EnablePixelTypeSignedByteWarning(true);
3023 336 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3024 0 : return -128;
3025 :
3026 336 : return 0;
3027 : }
3028 :
3029 1 : case GDT_Int8:
3030 1 : return -128;
3031 :
3032 21 : case GDT_UInt16:
3033 21 : return 0;
3034 :
3035 24 : case GDT_Int16:
3036 : case GDT_CInt16:
3037 24 : return -32768;
3038 :
3039 39 : case GDT_Int32:
3040 : case GDT_CInt32:
3041 39 : return -2147483648.0;
3042 :
3043 12 : case GDT_UInt32:
3044 12 : return 0;
3045 :
3046 1 : case GDT_Int64:
3047 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3048 :
3049 1 : case GDT_UInt64:
3050 1 : return 0;
3051 :
3052 0 : case GDT_Float16:
3053 : case GDT_CFloat16:
3054 0 : return -65504.0;
3055 :
3056 30 : case GDT_Float32:
3057 : case GDT_CFloat32:
3058 30 : return -4294967295.0; // Not actually accurate.
3059 :
3060 22 : case GDT_Float64:
3061 : case GDT_CFloat64:
3062 22 : return -4294967295.0; // Not actually accurate.
3063 :
3064 0 : case GDT_Unknown:
3065 : case GDT_TypeCount:
3066 0 : break;
3067 : }
3068 0 : return -4294967295.0; // Not actually accurate.
3069 : }
3070 :
3071 : /************************************************************************/
3072 : /* GDALGetRasterMinimum() */
3073 : /************************************************************************/
3074 :
3075 : /**
3076 : * \brief Fetch the minimum value for this band.
3077 : *
3078 : * @see GDALRasterBand::GetMinimum()
3079 : */
3080 :
3081 341 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3082 :
3083 : {
3084 341 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3085 :
3086 341 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3087 341 : return poBand->GetMinimum(pbSuccess);
3088 : }
3089 :
3090 : /************************************************************************/
3091 : /* GetColorInterpretation() */
3092 : /************************************************************************/
3093 :
3094 : /**
3095 : * \brief How should this band be interpreted as color?
3096 : *
3097 : * GCI_Undefined is returned when the format doesn't know anything
3098 : * about the color interpretation.
3099 : *
3100 : * This method is the same as the C function
3101 : * GDALGetRasterColorInterpretation().
3102 : *
3103 : * @return color interpretation value for band.
3104 : */
3105 :
3106 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3107 :
3108 : {
3109 163 : return GCI_Undefined;
3110 : }
3111 :
3112 : /************************************************************************/
3113 : /* GDALGetRasterColorInterpretation() */
3114 : /************************************************************************/
3115 :
3116 : /**
3117 : * \brief How should this band be interpreted as color?
3118 : *
3119 : * @see GDALRasterBand::GetColorInterpretation()
3120 : */
3121 :
3122 : GDALColorInterp CPL_STDCALL
3123 5680 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3124 :
3125 : {
3126 5680 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3127 :
3128 5680 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3129 5680 : return poBand->GetColorInterpretation();
3130 : }
3131 :
3132 : /************************************************************************/
3133 : /* SetColorInterpretation() */
3134 : /************************************************************************/
3135 :
3136 : /**
3137 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3138 : * \brief Set color interpretation of a band.
3139 : *
3140 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3141 : *
3142 : * @param eColorInterp the new color interpretation to apply to this band.
3143 : *
3144 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3145 : */
3146 :
3147 : /**/
3148 : /**/
3149 :
3150 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3151 :
3152 : {
3153 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3154 3 : ReportError(CE_Failure, CPLE_NotSupported,
3155 : "SetColorInterpretation() not supported for this dataset.");
3156 3 : return CE_Failure;
3157 : }
3158 :
3159 : /************************************************************************/
3160 : /* GDALSetRasterColorInterpretation() */
3161 : /************************************************************************/
3162 :
3163 : /**
3164 : * \brief Set color interpretation of a band.
3165 : *
3166 : * @see GDALRasterBand::SetColorInterpretation()
3167 : */
3168 :
3169 1857 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3170 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3171 :
3172 : {
3173 1857 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3174 :
3175 1857 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3176 1857 : return poBand->SetColorInterpretation(eColorInterp);
3177 : }
3178 :
3179 : /************************************************************************/
3180 : /* GetColorTable() */
3181 : /************************************************************************/
3182 :
3183 : /**
3184 : * \brief Fetch the color table associated with band.
3185 : *
3186 : * If there is no associated color table, the return result is NULL. The
3187 : * returned color table remains owned by the GDALRasterBand, and can't
3188 : * be depended on for long, nor should it ever be modified by the caller.
3189 : *
3190 : * This method is the same as the C function GDALGetRasterColorTable().
3191 : *
3192 : * @return internal color table, or NULL.
3193 : */
3194 :
3195 213 : GDALColorTable *GDALRasterBand::GetColorTable()
3196 :
3197 : {
3198 213 : return nullptr;
3199 : }
3200 :
3201 : /************************************************************************/
3202 : /* GDALGetRasterColorTable() */
3203 : /************************************************************************/
3204 :
3205 : /**
3206 : * \brief Fetch the color table associated with band.
3207 : *
3208 : * @see GDALRasterBand::GetColorTable()
3209 : */
3210 :
3211 1984 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3212 :
3213 : {
3214 1984 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3215 :
3216 1984 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3217 1984 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3218 : }
3219 :
3220 : /************************************************************************/
3221 : /* SetColorTable() */
3222 : /************************************************************************/
3223 :
3224 : /**
3225 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3226 : * \brief Set the raster color table.
3227 : *
3228 : * The driver will make a copy of all desired data in the colortable. It
3229 : * remains owned by the caller after the call.
3230 : *
3231 : * This method is the same as the C function GDALSetRasterColorTable().
3232 : *
3233 : * @param poCT the color table to apply. This may be NULL to clear the color
3234 : * table (where supported).
3235 : *
3236 : * @return CE_None on success, or CE_Failure on failure. If the action is
3237 : * unsupported by the driver, a value of CE_Failure is returned, but no
3238 : * error is issued.
3239 : */
3240 :
3241 : /**/
3242 : /**/
3243 :
3244 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3245 :
3246 : {
3247 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3248 0 : ReportError(CE_Failure, CPLE_NotSupported,
3249 : "SetColorTable() not supported for this dataset.");
3250 0 : return CE_Failure;
3251 : }
3252 :
3253 : /************************************************************************/
3254 : /* GDALSetRasterColorTable() */
3255 : /************************************************************************/
3256 :
3257 : /**
3258 : * \brief Set the raster color table.
3259 : *
3260 : * @see GDALRasterBand::SetColorTable()
3261 : */
3262 :
3263 78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3264 : GDALColorTableH hCT)
3265 :
3266 : {
3267 78 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3268 :
3269 78 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3270 78 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3271 : }
3272 :
3273 : /************************************************************************/
3274 : /* HasArbitraryOverviews() */
3275 : /************************************************************************/
3276 :
3277 : /**
3278 : * \brief Check for arbitrary overviews.
3279 : *
3280 : * This returns TRUE if the underlying datastore can compute arbitrary
3281 : * overviews efficiently, such as is the case with OGDI over a network.
3282 : * Datastores with arbitrary overviews don't generally have any fixed
3283 : * overviews, but the RasterIO() method can be used in downsampling mode
3284 : * to get overview data efficiently.
3285 : *
3286 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3287 : *
3288 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3289 : * FALSE.
3290 : */
3291 :
3292 267 : int GDALRasterBand::HasArbitraryOverviews()
3293 :
3294 : {
3295 267 : return FALSE;
3296 : }
3297 :
3298 : /************************************************************************/
3299 : /* GDALHasArbitraryOverviews() */
3300 : /************************************************************************/
3301 :
3302 : /**
3303 : * \brief Check for arbitrary overviews.
3304 : *
3305 : * @see GDALRasterBand::HasArbitraryOverviews()
3306 : */
3307 :
3308 188 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3309 :
3310 : {
3311 188 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3312 :
3313 188 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3314 188 : return poBand->HasArbitraryOverviews();
3315 : }
3316 :
3317 : /************************************************************************/
3318 : /* GetOverviewCount() */
3319 : /************************************************************************/
3320 :
3321 : /**
3322 : * \brief Return the number of overview layers available.
3323 : *
3324 : * This method is the same as the C function GDALGetOverviewCount().
3325 : *
3326 : * @return overview count, zero if none.
3327 : */
3328 :
3329 1066270 : int GDALRasterBand::GetOverviewCount()
3330 :
3331 : {
3332 1722930 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3333 656661 : poDS->AreOverviewsEnabled())
3334 656661 : return poDS->oOvManager.GetOverviewCount(nBand);
3335 :
3336 409606 : return 0;
3337 : }
3338 :
3339 : /************************************************************************/
3340 : /* GDALGetOverviewCount() */
3341 : /************************************************************************/
3342 :
3343 : /**
3344 : * \brief Return the number of overview layers available.
3345 : *
3346 : * @see GDALRasterBand::GetOverviewCount()
3347 : */
3348 :
3349 3295 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3350 :
3351 : {
3352 3295 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3353 :
3354 3295 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3355 3295 : return poBand->GetOverviewCount();
3356 : }
3357 :
3358 : /************************************************************************/
3359 : /* GetOverview() */
3360 : /************************************************************************/
3361 :
3362 : /**
3363 : * \brief Fetch overview raster band object.
3364 : *
3365 : * This method is the same as the C function GDALGetOverview().
3366 : *
3367 : * @param i overview index between 0 and GetOverviewCount()-1.
3368 : *
3369 : * @return overview GDALRasterBand.
3370 : */
3371 :
3372 942 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3373 :
3374 : {
3375 1732 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3376 790 : poDS->AreOverviewsEnabled())
3377 790 : return poDS->oOvManager.GetOverview(nBand, i);
3378 :
3379 152 : return nullptr;
3380 : }
3381 :
3382 : /************************************************************************/
3383 : /* GDALGetOverview() */
3384 : /************************************************************************/
3385 :
3386 : /**
3387 : * \brief Fetch overview raster band object.
3388 : *
3389 : * @see GDALRasterBand::GetOverview()
3390 : */
3391 :
3392 5641 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3393 :
3394 : {
3395 5641 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3396 :
3397 5641 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3398 5641 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3399 : }
3400 :
3401 : /************************************************************************/
3402 : /* GetRasterSampleOverview() */
3403 : /************************************************************************/
3404 :
3405 : /**
3406 : * \brief Fetch best sampling overview.
3407 : *
3408 : * Returns the most reduced overview of the given band that still satisfies
3409 : * the desired number of samples. This function can be used with zero
3410 : * as the number of desired samples to fetch the most reduced overview.
3411 : * The same band as was passed in will be returned if it has not overviews,
3412 : * or if none of the overviews have enough samples.
3413 : *
3414 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3415 : * and GDALGetRasterSampleOverviewEx().
3416 : *
3417 : * @param nDesiredSamples the returned band will have at least this many
3418 : * pixels.
3419 : *
3420 : * @return optimal overview or the band itself.
3421 : */
3422 :
3423 : GDALRasterBand *
3424 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3425 :
3426 : {
3427 2006 : GDALRasterBand *poBestBand = this;
3428 :
3429 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3430 :
3431 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3432 : {
3433 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3434 :
3435 2017 : if (poOBand == nullptr)
3436 0 : continue;
3437 :
3438 : const double dfOSamples =
3439 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3440 :
3441 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3442 : {
3443 2014 : dfBestSamples = dfOSamples;
3444 2014 : poBestBand = poOBand;
3445 : }
3446 : }
3447 :
3448 2006 : return poBestBand;
3449 : }
3450 :
3451 : /************************************************************************/
3452 : /* GDALGetRasterSampleOverview() */
3453 : /************************************************************************/
3454 :
3455 : /**
3456 : * \brief Fetch best sampling overview.
3457 : *
3458 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3459 : * billion samples.
3460 : *
3461 : * @see GDALRasterBand::GetRasterSampleOverview()
3462 : * @see GDALGetRasterSampleOverviewEx()
3463 : */
3464 :
3465 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3466 : int nDesiredSamples)
3467 :
3468 : {
3469 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3470 :
3471 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3472 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3473 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3474 : }
3475 :
3476 : /************************************************************************/
3477 : /* GDALGetRasterSampleOverviewEx() */
3478 : /************************************************************************/
3479 :
3480 : /**
3481 : * \brief Fetch best sampling overview.
3482 : *
3483 : * @see GDALRasterBand::GetRasterSampleOverview()
3484 : */
3485 :
3486 : GDALRasterBandH CPL_STDCALL
3487 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3488 :
3489 : {
3490 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3491 :
3492 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3493 2000 : return GDALRasterBand::ToHandle(
3494 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3495 : }
3496 :
3497 : /************************************************************************/
3498 : /* BuildOverviews() */
3499 : /************************************************************************/
3500 :
3501 : /**
3502 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3503 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3504 : *
3505 : * If the operation is unsupported for the indicated dataset, then
3506 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3507 : * CPLE_NotSupported.
3508 : *
3509 : * WARNING: Most formats don't support per-band overview computation, but
3510 : * require that overviews are computed for all bands of a dataset, using
3511 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3512 : * is the HFA driver which supports this method.
3513 : *
3514 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3515 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3516 : * applied.
3517 : * @param nOverviews number of overviews to build.
3518 : * @param panOverviewList the list of overview decimation factors to build.
3519 : * @param pfnProgress a function to call to report progress, or NULL.
3520 : * @param pProgressData application data to pass to the progress function.
3521 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3522 : * key=value pairs, or NULL
3523 : *
3524 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3525 : */
3526 :
3527 : /**/
3528 : /**/
3529 :
3530 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3531 : int /*nOverviews*/,
3532 : const int * /*panOverviewList*/,
3533 : GDALProgressFunc /*pfnProgress*/,
3534 : void * /*pProgressData*/,
3535 : CSLConstList /* papszOptions */)
3536 :
3537 : {
3538 0 : ReportError(CE_Failure, CPLE_NotSupported,
3539 : "BuildOverviews() not supported for this dataset.");
3540 :
3541 0 : return (CE_Failure);
3542 : }
3543 :
3544 : /************************************************************************/
3545 : /* GetOffset() */
3546 : /************************************************************************/
3547 :
3548 : /**
3549 : * \brief Fetch the raster value offset.
3550 : *
3551 : * This value (in combination with the GetScale() value) can be used to
3552 : * transform raw pixel values into the units returned by GetUnitType().
3553 : * For example this might be used to store elevations in GUInt16 bands
3554 : * with a precision of 0.1, and starting from -100.
3555 : *
3556 : * Units value = (raw value * scale) + offset
3557 : *
3558 : * Note that applying scale and offset is of the responsibility of the user,
3559 : * and is not done by methods such as RasterIO() or ReadBlock().
3560 : *
3561 : * For file formats that don't know this intrinsically a value of zero
3562 : * is returned.
3563 : *
3564 : * This method is the same as the C function GDALGetRasterOffset().
3565 : *
3566 : * @param pbSuccess pointer to a boolean to use to indicate if the
3567 : * returned value is meaningful or not. May be NULL (default).
3568 : *
3569 : * @return the raster offset.
3570 : */
3571 :
3572 445 : double GDALRasterBand::GetOffset(int *pbSuccess)
3573 :
3574 : {
3575 445 : if (pbSuccess != nullptr)
3576 336 : *pbSuccess = FALSE;
3577 :
3578 445 : return 0.0;
3579 : }
3580 :
3581 : /************************************************************************/
3582 : /* GDALGetRasterOffset() */
3583 : /************************************************************************/
3584 :
3585 : /**
3586 : * \brief Fetch the raster value offset.
3587 : *
3588 : * @see GDALRasterBand::GetOffset()
3589 : */
3590 :
3591 392 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3592 :
3593 : {
3594 392 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3595 :
3596 392 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3597 392 : return poBand->GetOffset(pbSuccess);
3598 : }
3599 :
3600 : /************************************************************************/
3601 : /* SetOffset() */
3602 : /************************************************************************/
3603 :
3604 : /**
3605 : * \fn GDALRasterBand::SetOffset(double)
3606 : * \brief Set scaling offset.
3607 : *
3608 : * Very few formats implement this method. When not implemented it will
3609 : * issue a CPLE_NotSupported error and return CE_Failure.
3610 : *
3611 : * This method is the same as the C function GDALSetRasterOffset().
3612 : *
3613 : * @param dfNewOffset the new offset.
3614 : *
3615 : * @return CE_None or success or CE_Failure on failure.
3616 : */
3617 :
3618 : /**/
3619 : /**/
3620 :
3621 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3622 : {
3623 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3624 0 : ReportError(CE_Failure, CPLE_NotSupported,
3625 : "SetOffset() not supported on this raster band.");
3626 :
3627 0 : return CE_Failure;
3628 : }
3629 :
3630 : /************************************************************************/
3631 : /* GDALSetRasterOffset() */
3632 : /************************************************************************/
3633 :
3634 : /**
3635 : * \brief Set scaling offset.
3636 : *
3637 : * @see GDALRasterBand::SetOffset()
3638 : */
3639 :
3640 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3641 : double dfNewOffset)
3642 :
3643 : {
3644 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3645 :
3646 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3647 86 : return poBand->SetOffset(dfNewOffset);
3648 : }
3649 :
3650 : /************************************************************************/
3651 : /* GetScale() */
3652 : /************************************************************************/
3653 :
3654 : /**
3655 : * \brief Fetch the raster value scale.
3656 : *
3657 : * This value (in combination with the GetOffset() value) can be used to
3658 : * transform raw pixel values into the units returned by GetUnitType().
3659 : * For example this might be used to store elevations in GUInt16 bands
3660 : * with a precision of 0.1, and starting from -100.
3661 : *
3662 : * Units value = (raw value * scale) + offset
3663 : *
3664 : * Note that applying scale and offset is of the responsibility of the user,
3665 : * and is not done by methods such as RasterIO() or ReadBlock().
3666 : *
3667 : * For file formats that don't know this intrinsically a value of one
3668 : * is returned.
3669 : *
3670 : * This method is the same as the C function GDALGetRasterScale().
3671 : *
3672 : * @param pbSuccess pointer to a boolean to use to indicate if the
3673 : * returned value is meaningful or not. May be NULL (default).
3674 : *
3675 : * @return the raster scale.
3676 : */
3677 :
3678 445 : double GDALRasterBand::GetScale(int *pbSuccess)
3679 :
3680 : {
3681 445 : if (pbSuccess != nullptr)
3682 336 : *pbSuccess = FALSE;
3683 :
3684 445 : return 1.0;
3685 : }
3686 :
3687 : /************************************************************************/
3688 : /* GDALGetRasterScale() */
3689 : /************************************************************************/
3690 :
3691 : /**
3692 : * \brief Fetch the raster value scale.
3693 : *
3694 : * @see GDALRasterBand::GetScale()
3695 : */
3696 :
3697 390 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3698 :
3699 : {
3700 390 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3701 :
3702 390 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3703 390 : return poBand->GetScale(pbSuccess);
3704 : }
3705 :
3706 : /************************************************************************/
3707 : /* SetScale() */
3708 : /************************************************************************/
3709 :
3710 : /**
3711 : * \fn GDALRasterBand::SetScale(double)
3712 : * \brief Set scaling ratio.
3713 : *
3714 : * Very few formats implement this method. When not implemented it will
3715 : * issue a CPLE_NotSupported error and return CE_Failure.
3716 : *
3717 : * This method is the same as the C function GDALSetRasterScale().
3718 : *
3719 : * @param dfNewScale the new scale.
3720 : *
3721 : * @return CE_None or success or CE_Failure on failure.
3722 : */
3723 :
3724 : /**/
3725 : /**/
3726 :
3727 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3728 :
3729 : {
3730 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3731 0 : ReportError(CE_Failure, CPLE_NotSupported,
3732 : "SetScale() not supported on this raster band.");
3733 :
3734 0 : return CE_Failure;
3735 : }
3736 :
3737 : /************************************************************************/
3738 : /* GDALSetRasterScale() */
3739 : /************************************************************************/
3740 :
3741 : /**
3742 : * \brief Set scaling ratio.
3743 : *
3744 : * @see GDALRasterBand::SetScale()
3745 : */
3746 :
3747 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3748 :
3749 : {
3750 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3751 :
3752 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3753 87 : return poBand->SetScale(dfNewOffset);
3754 : }
3755 :
3756 : /************************************************************************/
3757 : /* GetUnitType() */
3758 : /************************************************************************/
3759 :
3760 : /**
3761 : * \brief Return raster unit type.
3762 : *
3763 : * Return a name for the units of this raster's values. For instance, it
3764 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3765 : * units are available, a value of "" will be returned. The returned string
3766 : * should not be modified, nor freed by the calling application.
3767 : *
3768 : * This method is the same as the C function GDALGetRasterUnitType().
3769 : *
3770 : * @return unit name string.
3771 : */
3772 :
3773 165 : const char *GDALRasterBand::GetUnitType()
3774 :
3775 : {
3776 165 : return "";
3777 : }
3778 :
3779 : /************************************************************************/
3780 : /* GDALGetRasterUnitType() */
3781 : /************************************************************************/
3782 :
3783 : /**
3784 : * \brief Return raster unit type.
3785 : *
3786 : * @see GDALRasterBand::GetUnitType()
3787 : */
3788 :
3789 1474 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3790 :
3791 : {
3792 1474 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3793 :
3794 1474 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3795 1474 : return poBand->GetUnitType();
3796 : }
3797 :
3798 : /************************************************************************/
3799 : /* SetUnitType() */
3800 : /************************************************************************/
3801 :
3802 : /**
3803 : * \fn GDALRasterBand::SetUnitType(const char*)
3804 : * \brief Set unit type.
3805 : *
3806 : * Set the unit type for a raster band. Values should be one of
3807 : * "" (the default indicating it is unknown), "m" indicating meters,
3808 : * or "ft" indicating feet, though other nonstandard values are allowed.
3809 : *
3810 : * This method is the same as the C function GDALSetRasterUnitType().
3811 : *
3812 : * @param pszNewValue the new unit type value.
3813 : *
3814 : * @return CE_None on success or CE_Failure if not successful, or
3815 : * unsupported.
3816 : */
3817 :
3818 : /**/
3819 : /**/
3820 :
3821 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3822 :
3823 : {
3824 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3825 0 : ReportError(CE_Failure, CPLE_NotSupported,
3826 : "SetUnitType() not supported on this raster band.");
3827 0 : return CE_Failure;
3828 : }
3829 :
3830 : /************************************************************************/
3831 : /* GDALSetRasterUnitType() */
3832 : /************************************************************************/
3833 :
3834 : /**
3835 : * \brief Set unit type.
3836 : *
3837 : * @see GDALRasterBand::SetUnitType()
3838 : *
3839 : */
3840 :
3841 95 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842 : const char *pszNewValue)
3843 :
3844 : {
3845 95 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846 :
3847 95 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848 95 : return poBand->SetUnitType(pszNewValue);
3849 : }
3850 :
3851 : /************************************************************************/
3852 : /* GetXSize() */
3853 : /************************************************************************/
3854 :
3855 : /**
3856 : * \brief Fetch XSize of raster.
3857 : *
3858 : * This method is the same as the C function GDALGetRasterBandXSize().
3859 : *
3860 : * @return the width in pixels of this band.
3861 : */
3862 :
3863 8458980 : int GDALRasterBand::GetXSize() const
3864 :
3865 : {
3866 8458980 : return nRasterXSize;
3867 : }
3868 :
3869 : /************************************************************************/
3870 : /* GDALGetRasterBandXSize() */
3871 : /************************************************************************/
3872 :
3873 : /**
3874 : * \brief Fetch XSize of raster.
3875 : *
3876 : * @see GDALRasterBand::GetXSize()
3877 : */
3878 :
3879 57844 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880 :
3881 : {
3882 57844 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883 :
3884 57844 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885 57844 : return poBand->GetXSize();
3886 : }
3887 :
3888 : /************************************************************************/
3889 : /* GetYSize() */
3890 : /************************************************************************/
3891 :
3892 : /**
3893 : * \brief Fetch YSize of raster.
3894 : *
3895 : * This method is the same as the C function GDALGetRasterBandYSize().
3896 : *
3897 : * @return the height in pixels of this band.
3898 : */
3899 :
3900 4695280 : int GDALRasterBand::GetYSize() const
3901 :
3902 : {
3903 4695280 : return nRasterYSize;
3904 : }
3905 :
3906 : /************************************************************************/
3907 : /* GDALGetRasterBandYSize() */
3908 : /************************************************************************/
3909 :
3910 : /**
3911 : * \brief Fetch YSize of raster.
3912 : *
3913 : * @see GDALRasterBand::GetYSize()
3914 : */
3915 :
3916 56707 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917 :
3918 : {
3919 56707 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920 :
3921 56707 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922 56707 : return poBand->GetYSize();
3923 : }
3924 :
3925 : /************************************************************************/
3926 : /* GetBand() */
3927 : /************************************************************************/
3928 :
3929 : /**
3930 : * \brief Fetch the band number.
3931 : *
3932 : * This method returns the band that this GDALRasterBand objects represents
3933 : * within its dataset. This method may return a value of 0 to indicate
3934 : * GDALRasterBand objects without an apparently relationship to a dataset,
3935 : * such as GDALRasterBands serving as overviews.
3936 : *
3937 : * This method is the same as the C function GDALGetBandNumber().
3938 : *
3939 : * @return band number (1+) or 0 if the band number isn't known.
3940 : */
3941 :
3942 150733 : int GDALRasterBand::GetBand() const
3943 :
3944 : {
3945 150733 : return nBand;
3946 : }
3947 :
3948 : /************************************************************************/
3949 : /* GDALGetBandNumber() */
3950 : /************************************************************************/
3951 :
3952 : /**
3953 : * \brief Fetch the band number.
3954 : *
3955 : * @see GDALRasterBand::GetBand()
3956 : */
3957 :
3958 208 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3959 :
3960 : {
3961 208 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3962 :
3963 208 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3964 208 : return poBand->GetBand();
3965 : }
3966 :
3967 : /************************************************************************/
3968 : /* GetDataset() */
3969 : /************************************************************************/
3970 :
3971 : /**
3972 : * \brief Fetch the owning dataset handle.
3973 : *
3974 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3975 : * such as overviews or other "freestanding" bands.
3976 : *
3977 : * This method is the same as the C function GDALGetBandDataset().
3978 : *
3979 : * @return the pointer to the GDALDataset to which this band belongs, or
3980 : * NULL if this cannot be determined.
3981 : */
3982 :
3983 5288880 : GDALDataset *GDALRasterBand::GetDataset() const
3984 :
3985 : {
3986 5288880 : return poDS;
3987 : }
3988 :
3989 : /************************************************************************/
3990 : /* GDALGetBandDataset() */
3991 : /************************************************************************/
3992 :
3993 : /**
3994 : * \brief Fetch the owning dataset handle.
3995 : *
3996 : * @see GDALRasterBand::GetDataset()
3997 : */
3998 :
3999 355 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000 :
4001 : {
4002 355 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003 :
4004 355 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005 355 : return GDALDataset::ToHandle(poBand->GetDataset());
4006 : }
4007 :
4008 : /************************************************************************/
4009 : /* ComputeFloat16NoDataValue() */
4010 : /************************************************************************/
4011 :
4012 2282 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013 : double dfNoDataValue,
4014 : int &bGotNoDataValue,
4015 : GFloat16 &fNoDataValue,
4016 : bool &bGotFloat16NoDataValue)
4017 : {
4018 2282 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4019 : {
4020 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4021 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4022 : {
4023 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4024 0 : bGotFloat16NoDataValue = true;
4025 0 : bGotNoDataValue = false;
4026 : }
4027 : }
4028 2282 : }
4029 :
4030 : /************************************************************************/
4031 : /* ComputeFloatNoDataValue() */
4032 : /************************************************************************/
4033 :
4034 2282 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035 : double dfNoDataValue,
4036 : int &bGotNoDataValue,
4037 : float &fNoDataValue,
4038 : bool &bGotFloatNoDataValue)
4039 : {
4040 2282 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4041 : {
4042 90 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4043 90 : if (GDALIsValueInRange<float>(dfNoDataValue))
4044 : {
4045 90 : fNoDataValue = static_cast<float>(dfNoDataValue);
4046 90 : bGotFloatNoDataValue = true;
4047 90 : bGotNoDataValue = false;
4048 : }
4049 : }
4050 2282 : }
4051 :
4052 : /************************************************************************/
4053 : /* struct GDALNoDataValues */
4054 : /************************************************************************/
4055 :
4056 : /**
4057 : * \brief No-data-values for all types
4058 : *
4059 : * The functions below pass various no-data-values around. To avoid
4060 : * long argument lists, this struct collects the no-data-values for
4061 : * all types into a single, convenient place.
4062 : **/
4063 :
4064 : struct GDALNoDataValues
4065 : {
4066 : int bGotNoDataValue;
4067 : double dfNoDataValue;
4068 :
4069 : bool bGotInt64NoDataValue;
4070 : int64_t nInt64NoDataValue;
4071 :
4072 : bool bGotUInt64NoDataValue;
4073 : uint64_t nUInt64NoDataValue;
4074 :
4075 : bool bGotFloatNoDataValue;
4076 : float fNoDataValue;
4077 :
4078 : bool bGotFloat16NoDataValue;
4079 : GFloat16 hfNoDataValue;
4080 :
4081 2326 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4082 2326 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4083 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4084 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4085 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4086 2326 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4087 : {
4088 2326 : if (eDataType == GDT_Int64)
4089 : {
4090 28 : int nGot = false;
4091 28 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4092 28 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4093 28 : if (bGotInt64NoDataValue)
4094 : {
4095 3 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4096 3 : bGotNoDataValue =
4097 3 : nInt64NoDataValue <=
4098 6 : std::numeric_limits<int64_t>::max() - 1024 &&
4099 3 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4100 : }
4101 : else
4102 25 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4103 : }
4104 2298 : else if (eDataType == GDT_UInt64)
4105 : {
4106 16 : int nGot = false;
4107 16 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4108 16 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4109 16 : if (bGotUInt64NoDataValue)
4110 : {
4111 3 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4112 3 : bGotNoDataValue =
4113 3 : nUInt64NoDataValue <=
4114 6 : std::numeric_limits<uint64_t>::max() - 2048 &&
4115 3 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4116 : }
4117 : else
4118 13 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4119 : }
4120 : else
4121 : {
4122 2282 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4123 2282 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4124 :
4125 2282 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4126 2282 : fNoDataValue, bGotFloatNoDataValue);
4127 :
4128 2282 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4129 2282 : hfNoDataValue, bGotFloat16NoDataValue);
4130 : }
4131 2326 : }
4132 : };
4133 :
4134 : /************************************************************************/
4135 : /* ARE_REAL_EQUAL() */
4136 : /************************************************************************/
4137 :
4138 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4139 : {
4140 : using std::abs;
4141 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4142 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4143 0 : abs(dfVal1 + dfVal2) * ulp;
4144 : }
4145 :
4146 : /************************************************************************/
4147 : /* GetHistogram() */
4148 : /************************************************************************/
4149 :
4150 : /**
4151 : * \brief Compute raster histogram.
4152 : *
4153 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4154 : *
4155 : * For example to compute a simple 256 entry histogram of eight bit data,
4156 : * the following would be suitable. The unusual bounds are to ensure that
4157 : * bucket boundaries don't fall right on integer values causing possible errors
4158 : * due to rounding after scaling.
4159 : \code{.cpp}
4160 : GUIntBig anHistogram[256];
4161 :
4162 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4163 : GDALDummyProgress, nullptr );
4164 : \endcode
4165 : *
4166 : * Note that setting bApproxOK will generally result in a subsampling of the
4167 : * file, and will utilize overviews if available. It should generally
4168 : * produce a representative histogram for the data that is suitable for use
4169 : * in generating histogram based luts for instance. Generally bApproxOK is
4170 : * much faster than an exactly computed histogram.
4171 : *
4172 : * This method is the same as the C functions GDALGetRasterHistogram() and
4173 : * GDALGetRasterHistogramEx().
4174 : *
4175 : * @param dfMin the lower bound of the histogram.
4176 : * @param dfMax the upper bound of the histogram.
4177 : * @param nBuckets the number of buckets in panHistogram.
4178 : * @param panHistogram array into which the histogram totals are placed.
4179 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4180 : * mapped into panHistogram[0], and values above will be mapped into
4181 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4182 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4183 : * @param pfnProgress function to report progress to completion.
4184 : * @param pProgressData application data to pass to pfnProgress.
4185 : *
4186 : * @return CE_None on success, or CE_Failure if something goes wrong.
4187 : */
4188 :
4189 42 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4190 : GUIntBig *panHistogram,
4191 : int bIncludeOutOfRange, int bApproxOK,
4192 : GDALProgressFunc pfnProgress,
4193 : void *pProgressData)
4194 :
4195 : {
4196 42 : CPLAssert(nullptr != panHistogram);
4197 :
4198 42 : if (pfnProgress == nullptr)
4199 29 : pfnProgress = GDALDummyProgress;
4200 :
4201 : /* -------------------------------------------------------------------- */
4202 : /* If we have overviews, use them for the histogram. */
4203 : /* -------------------------------------------------------------------- */
4204 42 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4205 : {
4206 : // FIXME: should we use the most reduced overview here or use some
4207 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4208 : // does?
4209 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4210 :
4211 0 : if (poBestOverview != this)
4212 : {
4213 0 : return poBestOverview->GetHistogram(
4214 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4215 0 : bApproxOK, pfnProgress, pProgressData);
4216 : }
4217 : }
4218 :
4219 : /* -------------------------------------------------------------------- */
4220 : /* Read actual data and build histogram. */
4221 : /* -------------------------------------------------------------------- */
4222 42 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4223 : {
4224 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4225 0 : return CE_Failure;
4226 : }
4227 :
4228 : // Written this way to deal with NaN
4229 42 : if (!(dfMax > dfMin))
4230 : {
4231 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4232 : "dfMax should be strictly greater than dfMin");
4233 5 : return CE_Failure;
4234 : }
4235 :
4236 : GDALRasterIOExtraArg sExtraArg;
4237 37 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4238 :
4239 37 : const double dfScale = nBuckets / (dfMax - dfMin);
4240 37 : if (dfScale == 0 || !std::isfinite(dfScale))
4241 : {
4242 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4243 : "dfMin and dfMax should be finite values such that "
4244 : "nBuckets / (dfMax - dfMin) is non-zero");
4245 5 : return CE_Failure;
4246 : }
4247 32 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4248 :
4249 32 : GDALNoDataValues sNoDataValues(this, eDataType);
4250 32 : GDALRasterBand *poMaskBand = nullptr;
4251 32 : if (!sNoDataValues.bGotNoDataValue)
4252 : {
4253 31 : const int l_nMaskFlags = GetMaskFlags();
4254 33 : if (l_nMaskFlags != GMF_ALL_VALID &&
4255 2 : GetColorInterpretation() != GCI_AlphaBand)
4256 : {
4257 2 : poMaskBand = GetMaskBand();
4258 : }
4259 : }
4260 :
4261 32 : bool bSignedByte = false;
4262 32 : if (eDataType == GDT_Byte)
4263 : {
4264 23 : EnablePixelTypeSignedByteWarning(false);
4265 : const char *pszPixelType =
4266 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4267 23 : EnablePixelTypeSignedByteWarning(true);
4268 23 : bSignedByte =
4269 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4270 : }
4271 :
4272 32 : if (bApproxOK && HasArbitraryOverviews())
4273 : {
4274 : /* --------------------------------------------------------------------
4275 : */
4276 : /* Figure out how much the image should be reduced to get an */
4277 : /* approximate value. */
4278 : /* --------------------------------------------------------------------
4279 : */
4280 : const double dfReduction =
4281 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4282 : GDALSTAT_APPROX_NUMSAMPLES);
4283 :
4284 0 : int nXReduced = nRasterXSize;
4285 0 : int nYReduced = nRasterYSize;
4286 0 : if (dfReduction > 1.0)
4287 : {
4288 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4289 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4290 :
4291 : // Catch the case of huge resizing ratios here
4292 0 : if (nXReduced == 0)
4293 0 : nXReduced = 1;
4294 0 : if (nYReduced == 0)
4295 0 : nYReduced = 1;
4296 : }
4297 :
4298 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4299 : nXReduced, nYReduced);
4300 0 : if (!pData)
4301 0 : return CE_Failure;
4302 :
4303 : const CPLErr eErr =
4304 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4305 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4306 0 : if (eErr != CE_None)
4307 : {
4308 0 : CPLFree(pData);
4309 0 : return eErr;
4310 : }
4311 :
4312 0 : GByte *pabyMaskData = nullptr;
4313 0 : if (poMaskBand)
4314 : {
4315 : pabyMaskData =
4316 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4317 0 : if (!pabyMaskData)
4318 : {
4319 0 : CPLFree(pData);
4320 0 : return CE_Failure;
4321 : }
4322 :
4323 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4324 : pabyMaskData, nXReduced, nYReduced,
4325 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4326 : {
4327 0 : CPLFree(pData);
4328 0 : CPLFree(pabyMaskData);
4329 0 : return CE_Failure;
4330 : }
4331 : }
4332 :
4333 : // This isn't the fastest way to do this, but is easier for now.
4334 0 : for (int iY = 0; iY < nYReduced; iY++)
4335 : {
4336 0 : for (int iX = 0; iX < nXReduced; iX++)
4337 : {
4338 0 : const int iOffset = iX + iY * nXReduced;
4339 0 : double dfValue = 0.0;
4340 :
4341 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4342 0 : continue;
4343 :
4344 0 : switch (eDataType)
4345 : {
4346 0 : case GDT_Byte:
4347 : {
4348 0 : if (bSignedByte)
4349 0 : dfValue =
4350 0 : static_cast<signed char *>(pData)[iOffset];
4351 : else
4352 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4353 0 : break;
4354 : }
4355 0 : case GDT_Int8:
4356 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357 0 : break;
4358 0 : case GDT_UInt16:
4359 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360 0 : break;
4361 0 : case GDT_Int16:
4362 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363 0 : break;
4364 0 : case GDT_UInt32:
4365 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366 0 : break;
4367 0 : case GDT_Int32:
4368 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369 0 : break;
4370 0 : case GDT_UInt64:
4371 0 : dfValue = static_cast<double>(
4372 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4373 0 : break;
4374 0 : case GDT_Int64:
4375 0 : dfValue = static_cast<double>(
4376 0 : static_cast<GInt64 *>(pData)[iOffset]);
4377 0 : break;
4378 0 : case GDT_Float16:
4379 : {
4380 : using namespace std;
4381 0 : const GFloat16 hfValue =
4382 0 : static_cast<GFloat16 *>(pData)[iOffset];
4383 0 : if (isnan(hfValue) ||
4384 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4385 0 : ARE_REAL_EQUAL(hfValue,
4386 : sNoDataValues.hfNoDataValue)))
4387 0 : continue;
4388 0 : dfValue = hfValue;
4389 0 : break;
4390 : }
4391 0 : case GDT_Float32:
4392 : {
4393 0 : const float fValue =
4394 0 : static_cast<float *>(pData)[iOffset];
4395 0 : if (std::isnan(fValue) ||
4396 0 : (sNoDataValues.bGotFloatNoDataValue &&
4397 0 : ARE_REAL_EQUAL(fValue,
4398 : sNoDataValues.fNoDataValue)))
4399 0 : continue;
4400 0 : dfValue = double(fValue);
4401 0 : break;
4402 : }
4403 0 : case GDT_Float64:
4404 0 : dfValue = static_cast<double *>(pData)[iOffset];
4405 0 : if (std::isnan(dfValue))
4406 0 : continue;
4407 0 : break;
4408 0 : case GDT_CInt16:
4409 : {
4410 0 : const double dfReal =
4411 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4412 0 : const double dfImag =
4413 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4414 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4415 0 : continue;
4416 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4417 : }
4418 0 : break;
4419 0 : case GDT_CInt32:
4420 : {
4421 0 : const double dfReal =
4422 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4423 0 : const double dfImag =
4424 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4425 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4426 0 : continue;
4427 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4428 : }
4429 0 : break;
4430 0 : case GDT_CFloat16:
4431 : {
4432 : const double dfReal =
4433 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4434 : const double dfImag =
4435 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4436 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4437 0 : continue;
4438 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4439 0 : break;
4440 : }
4441 0 : case GDT_CFloat32:
4442 : {
4443 0 : const double dfReal =
4444 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4445 0 : const double dfImag = double(
4446 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4447 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4448 0 : continue;
4449 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4450 0 : break;
4451 : }
4452 0 : case GDT_CFloat64:
4453 : {
4454 0 : const double dfReal =
4455 0 : static_cast<double *>(pData)[iOffset * 2];
4456 0 : const double dfImag =
4457 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4458 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4459 0 : continue;
4460 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4461 0 : break;
4462 : }
4463 0 : case GDT_Unknown:
4464 : case GDT_TypeCount:
4465 0 : CPLAssert(false);
4466 : }
4467 :
4468 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4469 0 : sNoDataValues.bGotNoDataValue &&
4470 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4471 0 : continue;
4472 :
4473 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4474 : // finite, the result of the multiplication cannot be NaN
4475 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4476 :
4477 0 : if (dfIndex < 0)
4478 : {
4479 0 : if (bIncludeOutOfRange)
4480 0 : panHistogram[0]++;
4481 : }
4482 0 : else if (dfIndex >= nBuckets)
4483 : {
4484 0 : if (bIncludeOutOfRange)
4485 0 : ++panHistogram[nBuckets - 1];
4486 : }
4487 : else
4488 : {
4489 0 : ++panHistogram[static_cast<int>(dfIndex)];
4490 : }
4491 : }
4492 : }
4493 :
4494 0 : CPLFree(pData);
4495 0 : CPLFree(pabyMaskData);
4496 : }
4497 : else // No arbitrary overviews.
4498 : {
4499 32 : if (!InitBlockInfo())
4500 0 : return CE_Failure;
4501 :
4502 : /* --------------------------------------------------------------------
4503 : */
4504 : /* Figure out the ratio of blocks we will read to get an */
4505 : /* approximate value. */
4506 : /* --------------------------------------------------------------------
4507 : */
4508 :
4509 32 : int nSampleRate = 1;
4510 32 : if (bApproxOK)
4511 : {
4512 8 : nSampleRate = static_cast<int>(std::max(
4513 16 : 1.0,
4514 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4515 : // We want to avoid probing only the first column of blocks for
4516 : // a square shaped raster, because it is not unlikely that it may
4517 : // be padding only (#6378).
4518 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4519 1 : nSampleRate += 1;
4520 : }
4521 :
4522 32 : GByte *pabyMaskData = nullptr;
4523 32 : if (poMaskBand)
4524 : {
4525 : pabyMaskData = static_cast<GByte *>(
4526 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4527 2 : if (!pabyMaskData)
4528 : {
4529 0 : return CE_Failure;
4530 : }
4531 : }
4532 :
4533 : /* --------------------------------------------------------------------
4534 : */
4535 : /* Read the blocks, and add to histogram. */
4536 : /* --------------------------------------------------------------------
4537 : */
4538 32 : for (GIntBig iSampleBlock = 0;
4539 154 : iSampleBlock <
4540 154 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4541 122 : iSampleBlock += nSampleRate)
4542 : {
4543 122 : if (!pfnProgress(
4544 122 : static_cast<double>(iSampleBlock) /
4545 122 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4546 : "Compute Histogram", pProgressData))
4547 : {
4548 0 : CPLFree(pabyMaskData);
4549 0 : return CE_Failure;
4550 : }
4551 :
4552 122 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4553 122 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4554 :
4555 122 : int nXCheck = 0, nYCheck = 0;
4556 122 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4557 :
4558 124 : if (poMaskBand &&
4559 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4560 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4561 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4562 2 : 0, nBlockXSize, nullptr) != CE_None)
4563 : {
4564 0 : CPLFree(pabyMaskData);
4565 0 : return CE_Failure;
4566 : }
4567 :
4568 122 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4569 122 : if (poBlock == nullptr)
4570 : {
4571 0 : CPLFree(pabyMaskData);
4572 0 : return CE_Failure;
4573 : }
4574 :
4575 122 : void *pData = poBlock->GetDataRef();
4576 :
4577 : // this is a special case for a common situation.
4578 122 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4579 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4580 83 : nXCheck == nBlockXSize && nBuckets == 256)
4581 : {
4582 83 : const GPtrDiff_t nPixels =
4583 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4584 83 : GByte *pabyData = static_cast<GByte *>(pData);
4585 :
4586 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4587 : {
4588 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4589 0 : continue;
4590 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4591 512 : (pabyData[i] ==
4592 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4593 : {
4594 71798 : panHistogram[pabyData[i]]++;
4595 : }
4596 : }
4597 :
4598 83 : poBlock->DropLock();
4599 83 : continue; // To next sample block.
4600 : }
4601 :
4602 : // This isn't the fastest way to do this, but is easier for now.
4603 257 : for (int iY = 0; iY < nYCheck; iY++)
4604 : {
4605 36389 : for (int iX = 0; iX < nXCheck; iX++)
4606 : {
4607 36171 : const GPtrDiff_t iOffset =
4608 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4609 :
4610 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4611 2 : continue;
4612 :
4613 36169 : double dfValue = 0.0;
4614 :
4615 36169 : switch (eDataType)
4616 : {
4617 19716 : case GDT_Byte:
4618 : {
4619 19716 : if (bSignedByte)
4620 0 : dfValue =
4621 0 : static_cast<signed char *>(pData)[iOffset];
4622 : else
4623 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4624 19716 : break;
4625 : }
4626 1 : case GDT_Int8:
4627 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4628 1 : break;
4629 16384 : case GDT_UInt16:
4630 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4631 16384 : break;
4632 3 : case GDT_Int16:
4633 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4634 3 : break;
4635 0 : case GDT_UInt32:
4636 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4637 0 : break;
4638 60 : case GDT_Int32:
4639 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4640 60 : break;
4641 0 : case GDT_UInt64:
4642 0 : dfValue = static_cast<double>(
4643 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4644 0 : break;
4645 0 : case GDT_Int64:
4646 0 : dfValue = static_cast<double>(
4647 0 : static_cast<GInt64 *>(pData)[iOffset]);
4648 0 : break;
4649 0 : case GDT_Float16:
4650 : {
4651 : using namespace std;
4652 0 : const GFloat16 hfValue =
4653 0 : static_cast<GFloat16 *>(pData)[iOffset];
4654 0 : if (isnan(hfValue) ||
4655 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4656 0 : ARE_REAL_EQUAL(hfValue,
4657 : sNoDataValues.hfNoDataValue)))
4658 0 : continue;
4659 0 : dfValue = hfValue;
4660 0 : break;
4661 : }
4662 3 : case GDT_Float32:
4663 : {
4664 3 : const float fValue =
4665 3 : static_cast<float *>(pData)[iOffset];
4666 6 : if (std::isnan(fValue) ||
4667 6 : (sNoDataValues.bGotFloatNoDataValue &&
4668 3 : ARE_REAL_EQUAL(fValue,
4669 : sNoDataValues.fNoDataValue)))
4670 0 : continue;
4671 3 : dfValue = double(fValue);
4672 3 : break;
4673 : }
4674 2 : case GDT_Float64:
4675 2 : dfValue = static_cast<double *>(pData)[iOffset];
4676 2 : if (std::isnan(dfValue))
4677 0 : continue;
4678 2 : break;
4679 0 : case GDT_CInt16:
4680 : {
4681 0 : double dfReal =
4682 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4683 0 : double dfImag =
4684 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4685 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686 0 : break;
4687 : }
4688 0 : case GDT_CInt32:
4689 : {
4690 0 : double dfReal =
4691 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4692 0 : double dfImag =
4693 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4694 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4695 0 : break;
4696 : }
4697 0 : case GDT_CFloat16:
4698 : {
4699 : double dfReal =
4700 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4701 : double dfImag =
4702 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4703 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4704 0 : continue;
4705 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4706 0 : break;
4707 : }
4708 0 : case GDT_CFloat32:
4709 : {
4710 0 : double dfReal = double(
4711 0 : static_cast<float *>(pData)[iOffset * 2]);
4712 0 : double dfImag = double(
4713 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4714 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4715 0 : continue;
4716 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4717 0 : break;
4718 : }
4719 0 : case GDT_CFloat64:
4720 : {
4721 0 : double dfReal =
4722 0 : static_cast<double *>(pData)[iOffset * 2];
4723 0 : double dfImag =
4724 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4725 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4726 0 : continue;
4727 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4728 0 : break;
4729 : }
4730 0 : case GDT_Unknown:
4731 : case GDT_TypeCount:
4732 0 : CPLAssert(false);
4733 : CPLFree(pabyMaskData);
4734 : return CE_Failure;
4735 : }
4736 :
4737 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4738 72338 : sNoDataValues.bGotNoDataValue &&
4739 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4740 0 : continue;
4741 :
4742 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4743 : // and finite, the result of the multiplication cannot be
4744 : // NaN
4745 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4746 :
4747 36169 : if (dfIndex < 0)
4748 : {
4749 1 : if (bIncludeOutOfRange)
4750 1 : panHistogram[0]++;
4751 : }
4752 36168 : else if (dfIndex >= nBuckets)
4753 : {
4754 7 : if (bIncludeOutOfRange)
4755 4 : ++panHistogram[nBuckets - 1];
4756 : }
4757 : else
4758 : {
4759 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4760 : }
4761 : }
4762 : }
4763 :
4764 39 : poBlock->DropLock();
4765 : }
4766 :
4767 32 : CPLFree(pabyMaskData);
4768 : }
4769 :
4770 32 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4771 :
4772 32 : return CE_None;
4773 : }
4774 :
4775 : /************************************************************************/
4776 : /* GDALGetRasterHistogram() */
4777 : /************************************************************************/
4778 :
4779 : /**
4780 : * \brief Compute raster histogram.
4781 : *
4782 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4783 : * exceeding 2 billion.
4784 : *
4785 : * @see GDALRasterBand::GetHistogram()
4786 : * @see GDALGetRasterHistogramEx()
4787 : */
4788 :
4789 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4790 : double dfMax, int nBuckets,
4791 : int *panHistogram,
4792 : int bIncludeOutOfRange, int bApproxOK,
4793 : GDALProgressFunc pfnProgress,
4794 : void *pProgressData)
4795 :
4796 : {
4797 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4798 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4799 :
4800 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4801 :
4802 : GUIntBig *panHistogramTemp =
4803 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4804 0 : if (panHistogramTemp == nullptr)
4805 : {
4806 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4807 : "Out of memory in GDALGetRasterHistogram().");
4808 0 : return CE_Failure;
4809 : }
4810 :
4811 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4812 : bIncludeOutOfRange, bApproxOK,
4813 0 : pfnProgress, pProgressData);
4814 :
4815 0 : if (eErr == CE_None)
4816 : {
4817 0 : for (int i = 0; i < nBuckets; i++)
4818 : {
4819 0 : if (panHistogramTemp[i] > INT_MAX)
4820 : {
4821 0 : CPLError(CE_Warning, CPLE_AppDefined,
4822 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4823 : " exceeds maximum 32 bit value",
4824 0 : i, panHistogramTemp[i]);
4825 0 : panHistogram[i] = INT_MAX;
4826 : }
4827 : else
4828 : {
4829 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4830 : }
4831 : }
4832 : }
4833 :
4834 0 : CPLFree(panHistogramTemp);
4835 :
4836 0 : return eErr;
4837 : }
4838 :
4839 : /************************************************************************/
4840 : /* GDALGetRasterHistogramEx() */
4841 : /************************************************************************/
4842 :
4843 : /**
4844 : * \brief Compute raster histogram.
4845 : *
4846 : * @see GDALRasterBand::GetHistogram()
4847 : *
4848 : */
4849 :
4850 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4851 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4852 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4853 : GDALProgressFunc pfnProgress, void *pProgressData)
4854 :
4855 : {
4856 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4857 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4858 :
4859 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4860 :
4861 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4862 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4863 26 : pProgressData);
4864 : }
4865 :
4866 : /************************************************************************/
4867 : /* GetDefaultHistogram() */
4868 : /************************************************************************/
4869 :
4870 : /**
4871 : * \brief Fetch default raster histogram.
4872 : *
4873 : * The default method in GDALRasterBand will compute a default histogram. This
4874 : * method is overridden by derived classes (such as GDALPamRasterBand,
4875 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4876 : * stored histogram.
4877 : *
4878 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4879 : * GDALGetDefaultHistogramEx().
4880 : *
4881 : * @param pdfMin pointer to double value that will contain the lower bound of
4882 : * the histogram.
4883 : * @param pdfMax pointer to double value that will contain the upper bound of
4884 : * the histogram.
4885 : * @param pnBuckets pointer to int value that will contain the number of buckets
4886 : * in *ppanHistogram.
4887 : * @param ppanHistogram pointer to array into which the histogram totals are
4888 : * placed. To be freed with VSIFree
4889 : * @param bForce TRUE to force the computation. If FALSE and no default
4890 : * histogram is available, the method will return CE_Warning
4891 : * @param pfnProgress function to report progress to completion.
4892 : * @param pProgressData application data to pass to pfnProgress.
4893 : *
4894 : * @return CE_None on success, CE_Failure if something goes wrong, or
4895 : * CE_Warning if no default histogram is available.
4896 : */
4897 :
4898 24 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4899 : int *pnBuckets,
4900 : GUIntBig **ppanHistogram, int bForce,
4901 : GDALProgressFunc pfnProgress,
4902 : void *pProgressData)
4903 :
4904 : {
4905 24 : CPLAssert(nullptr != pnBuckets);
4906 24 : CPLAssert(nullptr != ppanHistogram);
4907 24 : CPLAssert(nullptr != pdfMin);
4908 24 : CPLAssert(nullptr != pdfMax);
4909 :
4910 24 : *pnBuckets = 0;
4911 24 : *ppanHistogram = nullptr;
4912 :
4913 24 : if (!bForce)
4914 5 : return CE_Warning;
4915 :
4916 19 : int nBuckets = 256;
4917 :
4918 19 : bool bSignedByte = false;
4919 19 : if (eDataType == GDT_Byte)
4920 : {
4921 17 : EnablePixelTypeSignedByteWarning(false);
4922 : const char *pszPixelType =
4923 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4924 17 : EnablePixelTypeSignedByteWarning(true);
4925 17 : bSignedByte =
4926 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4927 : }
4928 :
4929 19 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4930 : {
4931 17 : *pdfMin = -0.5;
4932 17 : *pdfMax = 255.5;
4933 : }
4934 2 : else if (GetRasterDataType() == GDT_Int8)
4935 : {
4936 1 : *pdfMin = -128 - 0.5;
4937 1 : *pdfMax = 127 + 0.5;
4938 : }
4939 : else
4940 : {
4941 :
4942 : const CPLErr eErr =
4943 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4944 1 : if (eErr != CE_None)
4945 0 : return eErr;
4946 1 : if (*pdfMin == *pdfMax)
4947 : {
4948 1 : nBuckets = 1;
4949 1 : *pdfMin -= 0.5;
4950 1 : *pdfMax += 0.5;
4951 : }
4952 : else
4953 : {
4954 0 : const double dfHalfBucket =
4955 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4956 0 : *pdfMin -= dfHalfBucket;
4957 0 : *pdfMax += dfHalfBucket;
4958 : }
4959 : }
4960 :
4961 19 : *ppanHistogram =
4962 19 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4963 19 : if (*ppanHistogram == nullptr)
4964 : {
4965 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4966 : "Out of memory in InitBlockInfo().");
4967 0 : return CE_Failure;
4968 : }
4969 :
4970 19 : *pnBuckets = nBuckets;
4971 38 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4972 19 : TRUE, FALSE, pfnProgress, pProgressData);
4973 19 : if (eErr != CE_None)
4974 : {
4975 0 : *pnBuckets = 0;
4976 : }
4977 19 : return eErr;
4978 : }
4979 :
4980 : /************************************************************************/
4981 : /* GDALGetDefaultHistogram() */
4982 : /************************************************************************/
4983 :
4984 : /**
4985 : * \brief Fetch default raster histogram.
4986 : *
4987 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4988 : * exceeding 2 billion.
4989 : *
4990 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4991 : * @see GDALGetRasterHistogramEx()
4992 : */
4993 :
4994 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4995 : double *pdfMin, double *pdfMax,
4996 : int *pnBuckets, int **ppanHistogram,
4997 : int bForce,
4998 : GDALProgressFunc pfnProgress,
4999 : void *pProgressData)
5000 :
5001 : {
5002 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5003 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5004 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5005 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5006 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5007 :
5008 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5009 0 : GUIntBig *panHistogramTemp = nullptr;
5010 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5011 : &panHistogramTemp, bForce,
5012 0 : pfnProgress, pProgressData);
5013 0 : if (eErr == CE_None)
5014 : {
5015 0 : const int nBuckets = *pnBuckets;
5016 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5017 0 : if (*ppanHistogram == nullptr)
5018 : {
5019 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5020 : "Out of memory in GDALGetDefaultHistogram().");
5021 0 : VSIFree(panHistogramTemp);
5022 0 : return CE_Failure;
5023 : }
5024 :
5025 0 : for (int i = 0; i < nBuckets; ++i)
5026 : {
5027 0 : if (panHistogramTemp[i] > INT_MAX)
5028 : {
5029 0 : CPLError(CE_Warning, CPLE_AppDefined,
5030 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5031 : " exceeds maximum 32 bit value",
5032 0 : i, panHistogramTemp[i]);
5033 0 : (*ppanHistogram)[i] = INT_MAX;
5034 : }
5035 : else
5036 : {
5037 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5038 : }
5039 : }
5040 :
5041 0 : CPLFree(panHistogramTemp);
5042 : }
5043 : else
5044 : {
5045 0 : *ppanHistogram = nullptr;
5046 : }
5047 :
5048 0 : return eErr;
5049 : }
5050 :
5051 : /************************************************************************/
5052 : /* GDALGetDefaultHistogramEx() */
5053 : /************************************************************************/
5054 :
5055 : /**
5056 : * \brief Fetch default raster histogram.
5057 : *
5058 : * @see GDALRasterBand::GetDefaultHistogram()
5059 : *
5060 : */
5061 :
5062 : CPLErr CPL_STDCALL
5063 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5064 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5065 : GDALProgressFunc pfnProgress, void *pProgressData)
5066 :
5067 : {
5068 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5069 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5070 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5071 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5072 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5073 :
5074 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5075 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5076 30 : bForce, pfnProgress, pProgressData);
5077 : }
5078 :
5079 : /************************************************************************/
5080 : /* AdviseRead() */
5081 : /************************************************************************/
5082 :
5083 : /**
5084 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5085 : * \brief Advise driver of upcoming read requests.
5086 : *
5087 : * Some GDAL drivers operate more efficiently if they know in advance what
5088 : * set of upcoming read requests will be made. The AdviseRead() method allows
5089 : * an application to notify the driver of the region of interest,
5090 : * and at what resolution the region will be read.
5091 : *
5092 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5093 : * accelerate access via some drivers.
5094 : *
5095 : * Depending on call paths, drivers might receive several calls to
5096 : * AdviseRead() with the same parameters.
5097 : *
5098 : * @param nXOff The pixel offset to the top left corner of the region
5099 : * of the band to be accessed. This would be zero to start from the left side.
5100 : *
5101 : * @param nYOff The line offset to the top left corner of the region
5102 : * of the band to be accessed. This would be zero to start from the top.
5103 : *
5104 : * @param nXSize The width of the region of the band to be accessed in pixels.
5105 : *
5106 : * @param nYSize The height of the region of the band to be accessed in lines.
5107 : *
5108 : * @param nBufXSize the width of the buffer image into which the desired region
5109 : * is to be read, or from which it is to be written.
5110 : *
5111 : * @param nBufYSize the height of the buffer image into which the desired
5112 : * region is to be read, or from which it is to be written.
5113 : *
5114 : * @param eBufType the type of the pixel values in the pData data buffer. The
5115 : * pixel values will automatically be translated to/from the GDALRasterBand
5116 : * data type as needed.
5117 : *
5118 : * @param papszOptions a list of name=value strings with special control
5119 : * options. Normally this is NULL.
5120 : *
5121 : * @return CE_Failure if the request is invalid and CE_None if it works or
5122 : * is ignored.
5123 : */
5124 :
5125 : /**/
5126 : /**/
5127 :
5128 113742 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5129 : int /*nYSize*/, int /*nBufXSize*/,
5130 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5131 : char ** /*papszOptions*/)
5132 : {
5133 113742 : return CE_None;
5134 : }
5135 :
5136 : /************************************************************************/
5137 : /* GDALRasterAdviseRead() */
5138 : /************************************************************************/
5139 :
5140 : /**
5141 : * \brief Advise driver of upcoming read requests.
5142 : *
5143 : * @see GDALRasterBand::AdviseRead()
5144 : */
5145 :
5146 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5147 : int nYOff, int nXSize, int nYSize,
5148 : int nBufXSize, int nBufYSize,
5149 : GDALDataType eDT,
5150 : CSLConstList papszOptions)
5151 :
5152 : {
5153 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5154 :
5155 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5156 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5157 : nBufYSize, eDT,
5158 2 : const_cast<char **>(papszOptions));
5159 : }
5160 :
5161 : /************************************************************************/
5162 : /* GetStatistics() */
5163 : /************************************************************************/
5164 :
5165 : /**
5166 : * \brief Fetch image statistics.
5167 : *
5168 : * Returns the minimum, maximum, mean and standard deviation of all
5169 : * pixel values in this band. If approximate statistics are sufficient,
5170 : * the bApproxOK flag can be set to true in which case overviews, or a
5171 : * subset of image tiles may be used in computing the statistics.
5172 : *
5173 : * If bForce is FALSE results will only be returned if it can be done
5174 : * quickly (i.e. without scanning the image, typically by using pre-existing
5175 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5176 : * returned efficiently, the method will return CE_Warning but no warning will
5177 : * be issued. This is a non-standard use of the CE_Warning return value
5178 : * to indicate "nothing done".
5179 : *
5180 : * If bForce is TRUE, and results are quickly available without scanning the
5181 : * image, they will be used. If bForce is TRUE and results are not quickly
5182 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5183 : * which will scan the image.
5184 : *
5185 : * To always force recomputation of statistics, use ComputeStatistics() instead
5186 : * of this method.
5187 : *
5188 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5189 : * will generally cache statistics in the .pam file allowing fast fetch
5190 : * after the first request.
5191 : *
5192 : * This method is the same as the C function GDALGetRasterStatistics().
5193 : *
5194 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5195 : * or a subset of all tiles.
5196 : *
5197 : * @param bForce If FALSE statistics will only be returned if it can
5198 : * be done without rescanning the image. If TRUE, statistics computation will
5199 : * be forced if pre-existing values are not quickly available.
5200 : *
5201 : * @param pdfMin Location into which to load image minimum (may be NULL).
5202 : *
5203 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5204 : *
5205 : * @param pdfMean Location into which to load image mean (may be NULL).
5206 : *
5207 : * @param pdfStdDev Location into which to load image standard deviation
5208 : * (may be NULL).
5209 : *
5210 : * @return CE_None on success, CE_Warning if no values returned,
5211 : * CE_Failure if an error occurs.
5212 : */
5213 :
5214 663 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5215 : double *pdfMax, double *pdfMean,
5216 : double *pdfStdDev)
5217 :
5218 : {
5219 : /* -------------------------------------------------------------------- */
5220 : /* Do we already have metadata items for the requested values? */
5221 : /* -------------------------------------------------------------------- */
5222 1326 : if ((pdfMin == nullptr ||
5223 663 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5224 205 : (pdfMax == nullptr ||
5225 205 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5226 1531 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5227 205 : (pdfStdDev == nullptr ||
5228 205 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5229 : {
5230 205 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5231 : {
5232 198 : if (pdfMin != nullptr)
5233 198 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5234 198 : if (pdfMax != nullptr)
5235 198 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5236 198 : if (pdfMean != nullptr)
5237 198 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5238 198 : if (pdfStdDev != nullptr)
5239 198 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5240 :
5241 198 : return CE_None;
5242 : }
5243 : }
5244 :
5245 : /* -------------------------------------------------------------------- */
5246 : /* Does the driver already know the min/max? */
5247 : /* -------------------------------------------------------------------- */
5248 465 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5249 : {
5250 1 : int bSuccessMin = FALSE;
5251 1 : int bSuccessMax = FALSE;
5252 :
5253 1 : const double dfMin = GetMinimum(&bSuccessMin);
5254 1 : const double dfMax = GetMaximum(&bSuccessMax);
5255 :
5256 1 : if (bSuccessMin && bSuccessMax)
5257 : {
5258 0 : if (pdfMin != nullptr)
5259 0 : *pdfMin = dfMin;
5260 0 : if (pdfMax != nullptr)
5261 0 : *pdfMax = dfMax;
5262 0 : return CE_None;
5263 : }
5264 : }
5265 :
5266 : /* -------------------------------------------------------------------- */
5267 : /* Either return without results, or force computation. */
5268 : /* -------------------------------------------------------------------- */
5269 465 : if (!bForce)
5270 183 : return CE_Warning;
5271 : else
5272 282 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5273 282 : GDALDummyProgress, nullptr);
5274 : }
5275 :
5276 : /************************************************************************/
5277 : /* GDALGetRasterStatistics() */
5278 : /************************************************************************/
5279 :
5280 : /**
5281 : * \brief Fetch image statistics.
5282 : *
5283 : * @see GDALRasterBand::GetStatistics()
5284 : */
5285 :
5286 311 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5287 : int bForce, double *pdfMin,
5288 : double *pdfMax, double *pdfMean,
5289 : double *pdfStdDev)
5290 :
5291 : {
5292 311 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5293 :
5294 311 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5295 311 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5296 311 : pdfStdDev);
5297 : }
5298 :
5299 : /************************************************************************/
5300 : /* GDALUInt128 */
5301 : /************************************************************************/
5302 :
5303 : #ifdef HAVE_UINT128_T
5304 : class GDALUInt128
5305 : {
5306 : __uint128_t val;
5307 :
5308 1155 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5309 : {
5310 1155 : }
5311 :
5312 : public:
5313 770 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5314 : {
5315 : // Evaluates to just a single mul on x86_64
5316 770 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5317 : }
5318 :
5319 385 : GDALUInt128 operator-(const GDALUInt128 &other) const
5320 : {
5321 385 : return GDALUInt128(val - other.val);
5322 : }
5323 :
5324 376 : operator double() const
5325 : {
5326 376 : return static_cast<double>(val);
5327 : }
5328 : };
5329 : #else
5330 :
5331 : #if defined(_MSC_VER) && defined(_M_X64)
5332 : #include <intrin.h>
5333 : #endif
5334 :
5335 : class GDALUInt128
5336 : {
5337 : GUIntBig low, high;
5338 :
5339 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5340 : {
5341 : }
5342 :
5343 : public:
5344 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5345 : {
5346 : #if defined(_MSC_VER) && defined(_M_X64)
5347 : GUIntBig highRes;
5348 : GUIntBig lowRes = _umul128(first, second, &highRes);
5349 : return GDALUInt128(lowRes, highRes);
5350 : #else
5351 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5352 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5353 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5354 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5355 : GUIntBig highRes = 0;
5356 : const GUIntBig firstLowSecondHigh =
5357 : static_cast<GUIntBig>(firstLow) * secondHigh;
5358 : const GUIntBig firstHighSecondLow =
5359 : static_cast<GUIntBig>(firstHigh) * secondLow;
5360 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5361 : if (middleTerm < firstLowSecondHigh) // check for overflow
5362 : highRes += static_cast<GUIntBig>(1) << 32;
5363 : const GUIntBig firstLowSecondLow =
5364 : static_cast<GUIntBig>(firstLow) * secondLow;
5365 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5366 : if (lowRes < firstLowSecondLow) // check for overflow
5367 : highRes++;
5368 : highRes +=
5369 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5370 : return GDALUInt128(lowRes, highRes);
5371 : #endif
5372 : }
5373 :
5374 : GDALUInt128 operator-(const GDALUInt128 &other) const
5375 : {
5376 : GUIntBig highRes = high - other.high;
5377 : GUIntBig lowRes = low - other.low;
5378 : if (lowRes > low) // check for underflow
5379 : --highRes;
5380 : return GDALUInt128(lowRes, highRes);
5381 : }
5382 :
5383 : operator double() const
5384 : {
5385 : const double twoPow64 = 18446744073709551616.0;
5386 : return high * twoPow64 + low;
5387 : }
5388 : };
5389 : #endif
5390 :
5391 : /************************************************************************/
5392 : /* ComputeStatisticsInternal() */
5393 : /************************************************************************/
5394 :
5395 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5396 : // not needed.
5397 : #define static_cast_for_coverity_scan static_cast
5398 :
5399 : // The rationale for below optimizations is detailed in statistics.txt
5400 :
5401 : // Use with T = GByte or GUInt16 only !
5402 : template <class T, bool COMPUTE_OTHER_STATS>
5403 : struct ComputeStatisticsInternalGeneric
5404 : {
5405 249 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5406 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5407 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5408 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5409 : {
5410 : static_assert(std::is_same<T, GByte>::value ||
5411 : std::is_same<T, GUInt16>::value,
5412 : "bad type for T");
5413 249 : if (bHasNoData)
5414 : {
5415 : // General case
5416 606 : for (int iY = 0; iY < nYCheck; iY++)
5417 : {
5418 161751 : for (int iX = 0; iX < nXCheck; iX++)
5419 : {
5420 161268 : const GPtrDiff_t iOffset =
5421 161268 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5422 161268 : const GUInt32 nValue = pData[iOffset];
5423 161268 : if (nValue == nNoDataValue)
5424 318 : continue;
5425 160950 : if (nValue < nMin)
5426 34 : nMin = nValue;
5427 160950 : if (nValue > nMax)
5428 71 : nMax = nValue;
5429 : if constexpr (COMPUTE_OTHER_STATS)
5430 : {
5431 159314 : nValidCount++;
5432 159314 : nSum += nValue;
5433 159314 : nSumSquare +=
5434 159314 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5435 159314 : nValue;
5436 : }
5437 : }
5438 : }
5439 : if constexpr (COMPUTE_OTHER_STATS)
5440 : {
5441 40 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5442 : }
5443 : }
5444 144 : else if (nMin == std::numeric_limits<T>::lowest() &&
5445 18 : nMax == std::numeric_limits<T>::max())
5446 : {
5447 : if constexpr (COMPUTE_OTHER_STATS)
5448 : {
5449 : // Optimization when there is no nodata and we know we have already
5450 : // reached the min and max
5451 416 : for (int iY = 0; iY < nYCheck; iY++)
5452 : {
5453 : int iX;
5454 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5455 : {
5456 1600 : const GPtrDiff_t iOffset =
5457 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458 1600 : const GUIntBig nValue = pData[iOffset];
5459 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5460 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5461 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5462 1600 : nSum += nValue;
5463 1600 : nSumSquare += nValue * nValue;
5464 1600 : nSum += nValue2;
5465 1600 : nSumSquare += nValue2 * nValue2;
5466 1600 : nSum += nValue3;
5467 1600 : nSumSquare += nValue3 * nValue3;
5468 1600 : nSum += nValue4;
5469 1600 : nSumSquare += nValue4 * nValue4;
5470 : }
5471 414 : for (; iX < nXCheck; ++iX)
5472 : {
5473 10 : const GPtrDiff_t iOffset =
5474 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5475 10 : const GUIntBig nValue = pData[iOffset];
5476 10 : nSum += nValue;
5477 10 : nSumSquare += nValue * nValue;
5478 : }
5479 : }
5480 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5481 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5482 : }
5483 : }
5484 : else
5485 : {
5486 6019 : for (int iY = 0; iY < nYCheck; iY++)
5487 : {
5488 : int iX;
5489 1270510 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5490 : {
5491 1264611 : const GPtrDiff_t iOffset =
5492 1264611 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493 1264611 : const GUInt32 nValue = pData[iOffset];
5494 1264611 : const GUInt32 nValue2 = pData[iOffset + 1];
5495 1264611 : if (nValue < nValue2)
5496 : {
5497 2324 : if (nValue < nMin)
5498 50 : nMin = nValue;
5499 2324 : if (nValue2 > nMax)
5500 118 : nMax = nValue2;
5501 : }
5502 : else
5503 : {
5504 1262285 : if (nValue2 < nMin)
5505 67 : nMin = nValue2;
5506 1262285 : if (nValue > nMax)
5507 216 : nMax = nValue;
5508 : }
5509 : if constexpr (COMPUTE_OTHER_STATS)
5510 : {
5511 1257560 : nSum += nValue;
5512 1257560 : nSumSquare +=
5513 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5514 1257560 : nValue;
5515 1257560 : nSum += nValue2;
5516 1257560 : nSumSquare +=
5517 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5518 1257560 : nValue2;
5519 : }
5520 : }
5521 5905 : if (iX < nXCheck)
5522 : {
5523 27 : const GPtrDiff_t iOffset =
5524 27 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5525 27 : const GUInt32 nValue = pData[iOffset];
5526 27 : if (nValue < nMin)
5527 19 : nMin = nValue;
5528 27 : if (nValue > nMax)
5529 20 : nMax = nValue;
5530 : if (COMPUTE_OTHER_STATS)
5531 : {
5532 19 : nSum += nValue;
5533 19 : nSumSquare +=
5534 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5535 19 : nValue;
5536 : }
5537 : }
5538 : }
5539 : if constexpr (COMPUTE_OTHER_STATS)
5540 : {
5541 60 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5542 60 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5543 : }
5544 : }
5545 249 : }
5546 : };
5547 :
5548 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5549 : // using 64bit accumulators in internal loops. This also slightly helps in
5550 : // 64bit mode.
5551 : template <bool COMPUTE_OTHER_STATS>
5552 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5553 : {
5554 13724 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5555 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5556 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5557 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5558 : {
5559 13724 : int nOuterLoops = nXCheck / 65536;
5560 13724 : if (nXCheck % 65536)
5561 13724 : nOuterLoops++;
5562 :
5563 13724 : if (bHasNoData)
5564 : {
5565 : // General case
5566 23767 : for (int iY = 0; iY < nYCheck; iY++)
5567 : {
5568 13186 : int iX = 0;
5569 26372 : for (int k = 0; k < nOuterLoops; k++)
5570 : {
5571 13186 : int iMax = iX + 65536;
5572 13186 : if (iMax > nXCheck)
5573 13186 : iMax = nXCheck;
5574 13186 : GUInt32 nSum32bit = 0;
5575 13186 : GUInt32 nSumSquare32bit = 0;
5576 13186 : GUInt32 nValidCount32bit = 0;
5577 13186 : GUInt32 nSampleCount32bit = 0;
5578 20722795 : for (; iX < iMax; iX++)
5579 : {
5580 20709658 : const GPtrDiff_t iOffset =
5581 20709658 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5582 20709658 : const GUInt32 nValue = pData[iOffset];
5583 :
5584 20709658 : nSampleCount32bit++;
5585 20709658 : if (nValue == nNoDataValue)
5586 20353515 : continue;
5587 356088 : if (nValue < nMin)
5588 371 : nMin = nValue;
5589 356088 : if (nValue > nMax)
5590 834 : nMax = nValue;
5591 : if constexpr (COMPUTE_OTHER_STATS)
5592 : {
5593 32343 : nValidCount32bit++;
5594 32343 : nSum32bit += nValue;
5595 32343 : nSumSquare32bit += nValue * nValue;
5596 : }
5597 : }
5598 : if constexpr (COMPUTE_OTHER_STATS)
5599 : {
5600 937 : nSampleCount += nSampleCount32bit;
5601 937 : nValidCount += nValidCount32bit;
5602 937 : nSum += nSum32bit;
5603 937 : nSumSquare += nSumSquare32bit;
5604 : }
5605 : }
5606 : }
5607 : }
5608 3143 : else if (nMin == 0 && nMax == 255)
5609 : {
5610 : if constexpr (COMPUTE_OTHER_STATS)
5611 : {
5612 : // Optimization when there is no nodata and we know we have already
5613 : // reached the min and max
5614 2850 : for (int iY = 0; iY < nYCheck; iY++)
5615 : {
5616 2818 : int iX = 0;
5617 5636 : for (int k = 0; k < nOuterLoops; k++)
5618 : {
5619 2818 : int iMax = iX + 65536;
5620 2818 : if (iMax > nXCheck)
5621 2818 : iMax = nXCheck;
5622 2818 : GUInt32 nSum32bit = 0;
5623 2818 : GUInt32 nSumSquare32bit = 0;
5624 177298 : for (; iX + 3 < iMax; iX += 4)
5625 : {
5626 174480 : const GPtrDiff_t iOffset =
5627 174480 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5628 174480 : const GUInt32 nValue = pData[iOffset];
5629 174480 : const GUInt32 nValue2 = pData[iOffset + 1];
5630 174480 : const GUInt32 nValue3 = pData[iOffset + 2];
5631 174480 : const GUInt32 nValue4 = pData[iOffset + 3];
5632 174480 : nSum32bit += nValue;
5633 174480 : nSumSquare32bit += nValue * nValue;
5634 174480 : nSum32bit += nValue2;
5635 174480 : nSumSquare32bit += nValue2 * nValue2;
5636 174480 : nSum32bit += nValue3;
5637 174480 : nSumSquare32bit += nValue3 * nValue3;
5638 174480 : nSum32bit += nValue4;
5639 174480 : nSumSquare32bit += nValue4 * nValue4;
5640 : }
5641 2818 : nSum += nSum32bit;
5642 2818 : nSumSquare += nSumSquare32bit;
5643 : }
5644 2824 : for (; iX < nXCheck; ++iX)
5645 : {
5646 6 : const GPtrDiff_t iOffset =
5647 6 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5648 6 : const GUIntBig nValue = pData[iOffset];
5649 6 : nSum += nValue;
5650 6 : nSumSquare += nValue * nValue;
5651 : }
5652 : }
5653 32 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5654 32 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5655 32 : }
5656 : }
5657 : else
5658 : {
5659 8424 : for (int iY = 0; iY < nYCheck; iY++)
5660 : {
5661 5313 : int iX = 0;
5662 10626 : for (int k = 0; k < nOuterLoops; k++)
5663 : {
5664 5313 : int iMax = iX + 65536;
5665 5313 : if (iMax > nXCheck)
5666 5313 : iMax = nXCheck;
5667 5313 : GUInt32 nSum32bit = 0;
5668 5313 : GUInt32 nSumSquare32bit = 0;
5669 284873 : for (; iX + 1 < iMax; iX += 2)
5670 : {
5671 279560 : const GPtrDiff_t iOffset =
5672 279560 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673 279560 : const GUInt32 nValue = pData[iOffset];
5674 279560 : const GUInt32 nValue2 = pData[iOffset + 1];
5675 279560 : if (nValue < nValue2)
5676 : {
5677 8056 : if (nValue < nMin)
5678 231 : nMin = nValue;
5679 8056 : if (nValue2 > nMax)
5680 220 : nMax = nValue2;
5681 : }
5682 : else
5683 : {
5684 271504 : if (nValue2 < nMin)
5685 360 : nMin = nValue2;
5686 271504 : if (nValue > nMax)
5687 829 : nMax = nValue;
5688 : }
5689 : if constexpr (COMPUTE_OTHER_STATS)
5690 : {
5691 257423 : nSum32bit += nValue;
5692 257423 : nSumSquare32bit += nValue * nValue;
5693 257423 : nSum32bit += nValue2;
5694 257423 : nSumSquare32bit += nValue2 * nValue2;
5695 : }
5696 : }
5697 : if constexpr (COMPUTE_OTHER_STATS)
5698 : {
5699 2127 : nSum += nSum32bit;
5700 2127 : nSumSquare += nSumSquare32bit;
5701 : }
5702 : }
5703 5313 : if (iX < nXCheck)
5704 : {
5705 1529 : const GPtrDiff_t iOffset =
5706 1529 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5707 1529 : const GUInt32 nValue = pData[iOffset];
5708 1529 : if (nValue < nMin)
5709 117 : nMin = nValue;
5710 1529 : if (nValue > nMax)
5711 101 : nMax = nValue;
5712 : if constexpr (COMPUTE_OTHER_STATS)
5713 : {
5714 318 : nSum += nValue;
5715 318 : nSumSquare +=
5716 318 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5717 318 : nValue;
5718 : }
5719 : }
5720 : }
5721 : if constexpr (COMPUTE_OTHER_STATS)
5722 : {
5723 915 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5724 915 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5725 : }
5726 : }
5727 13724 : }
5728 : };
5729 :
5730 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5731 : {
5732 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5733 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5734 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5735 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5736 : {
5737 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5738 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5739 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5740 : }
5741 : };
5742 :
5743 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5744 : (defined(__GNUC__) || defined(_MSC_VER))
5745 :
5746 : #include "gdal_avx2_emulation.hpp"
5747 :
5748 : #define ZERO256 GDALmm256_setzero_si256()
5749 :
5750 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5751 : static void
5752 21345 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5753 : // assumed to be aligned on 256 bits
5754 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5755 : GUIntBig &nSum, GUIntBig &nSumSquare,
5756 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5757 : {
5758 : // 32-byte alignment may not be enforced by linker, so do it at hand
5759 : GByte
5760 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5761 21345 : GByte *paby32ByteAligned =
5762 : aby32ByteUnaligned +
5763 21345 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5764 21345 : GByte *pabyMin = paby32ByteAligned;
5765 21345 : GByte *pabyMax = paby32ByteAligned + 32;
5766 21345 : GUInt32 *panSum =
5767 : COMPUTE_OTHER_STATS
5768 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5769 : : nullptr;
5770 21345 : GUInt32 *panSumSquare =
5771 : COMPUTE_OTHER_STATS
5772 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5773 : : nullptr;
5774 :
5775 21345 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5776 :
5777 21345 : GPtrDiff_t i = 0;
5778 : // Make sure that sumSquare can fit on uint32
5779 : // * 8 since we can hold 8 sums per vector register
5780 21345 : const int nMaxIterationsPerInnerLoop =
5781 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5782 21345 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5783 21345 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5784 21345 : nOuterLoops++;
5785 :
5786 : GDALm256i ymm_min =
5787 21345 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5788 21345 : GDALm256i ymm_max = ymm_min;
5789 21345 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5790 :
5791 42690 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5792 : {
5793 21345 : const auto iMax =
5794 21345 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5795 :
5796 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5797 21345 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5798 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5799 21345 : ZERO256; // holds 8 uint32 sums
5800 724706 : for (; i + 31 < iMax; i += 32)
5801 : {
5802 703361 : const GDALm256i ymm = GDALmm256_load_si256(
5803 703361 : reinterpret_cast<const GDALm256i *>(pData + i));
5804 : if (COMPUTE_MIN)
5805 : {
5806 243252 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5807 : }
5808 : if (COMPUTE_MAX)
5809 : {
5810 612062 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5811 : }
5812 :
5813 : if constexpr (COMPUTE_OTHER_STATS)
5814 : {
5815 : // Extract even-8bit values
5816 : const GDALm256i ymm_even =
5817 504089 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5818 : // Compute square of those 16 values as 32 bit result
5819 : // and add adjacent pairs
5820 : const GDALm256i ymm_even_square =
5821 504089 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5822 : // Add to the sumsquare accumulator
5823 : ymm_sumsquare =
5824 504089 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5825 :
5826 : // Extract odd-8bit values
5827 504089 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5828 : const GDALm256i ymm_odd_square =
5829 504089 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5830 : ymm_sumsquare =
5831 504089 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5832 :
5833 : // Now compute the sums
5834 504089 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5835 : GDALmm256_sad_epu8(ymm, ZERO256));
5836 : }
5837 : }
5838 :
5839 : if constexpr (COMPUTE_OTHER_STATS)
5840 : {
5841 10676 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5842 : ymm_sum);
5843 10676 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5844 : ymm_sumsquare);
5845 :
5846 10676 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5847 10676 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5848 10676 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5849 10676 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5850 : panSumSquare[7];
5851 : }
5852 : }
5853 :
5854 : if constexpr (COMPUTE_MIN)
5855 : {
5856 8448 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5857 : }
5858 : if constexpr (COMPUTE_MAX)
5859 : {
5860 17333 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5861 : }
5862 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5863 : {
5864 589248 : for (int j = 0; j < 32; j++)
5865 : {
5866 : if constexpr (COMPUTE_MIN)
5867 : {
5868 270336 : if (pabyMin[j] < nMin)
5869 1235 : nMin = pabyMin[j];
5870 : }
5871 : if constexpr (COMPUTE_MAX)
5872 : {
5873 554656 : if (pabyMax[j] > nMax)
5874 1794 : nMax = pabyMax[j];
5875 : }
5876 : }
5877 : }
5878 :
5879 234343 : for (; i < nBlockPixels; i++)
5880 : {
5881 212998 : const GUInt32 nValue = pData[i];
5882 : if constexpr (COMPUTE_MIN)
5883 : {
5884 88322 : if (nValue < nMin)
5885 2 : nMin = nValue;
5886 : }
5887 : if constexpr (COMPUTE_MAX)
5888 : {
5889 210223 : if (nValue > nMax)
5890 1150 : nMax = nValue;
5891 : }
5892 : if constexpr (COMPUTE_OTHER_STATS)
5893 : {
5894 77199 : nSum += nValue;
5895 77199 : nSumSquare +=
5896 77199 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5897 : }
5898 : }
5899 :
5900 : if constexpr (COMPUTE_OTHER_STATS)
5901 : {
5902 10676 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5903 10676 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5904 : }
5905 21345 : }
5906 :
5907 : // SSE2/AVX2 optimization for GByte case
5908 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5909 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5910 : // there are strictly equivalent to 2 parallel SSE2 streams.
5911 : template <bool COMPUTE_OTHER_STATS>
5912 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5913 : {
5914 30238 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5915 : // assumed to be aligned on 256 bits
5916 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5917 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5918 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5919 : GUIntBig &nValidCount)
5920 : {
5921 30238 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5922 30238 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5923 11610 : nMin <= nMax)
5924 : {
5925 : // 32-byte alignment may not be enforced by linker, so do it at hand
5926 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5927 1492 : GByte *paby32ByteAligned =
5928 : aby32ByteUnaligned +
5929 1492 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5930 1492 : GByte *pabyMin = paby32ByteAligned;
5931 1492 : GByte *pabyMax = paby32ByteAligned + 32;
5932 1492 : GUInt32 *panSum =
5933 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5934 1492 : GUInt32 *panSumSquare =
5935 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5936 :
5937 1492 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5938 :
5939 1492 : GPtrDiff_t i = 0;
5940 : // Make sure that sumSquare can fit on uint32
5941 : // * 8 since we can hold 8 sums per vector register
5942 1492 : const int nMaxIterationsPerInnerLoop =
5943 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5944 1492 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5945 1492 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5946 1492 : nOuterLoops++;
5947 :
5948 : const GDALm256i ymm_nodata =
5949 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5950 : // any non noData value in [min,max] would do.
5951 : const GDALm256i ymm_neutral =
5952 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5953 1492 : GDALm256i ymm_min = ymm_neutral;
5954 1492 : GDALm256i ymm_max = ymm_neutral;
5955 : [[maybe_unused]] const auto ymm_mask_8bits =
5956 1492 : GDALmm256_set1_epi16(0xFF);
5957 :
5958 1492 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5959 1492 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5960 1492 : const bool bComputeMinMax =
5961 1492 : nMin > nMinThreshold || nMax < nMaxThreshold;
5962 :
5963 2984 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5964 : {
5965 1492 : const auto iMax =
5966 1492 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5967 :
5968 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5969 1492 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5970 : // holds 8 uint32 sums
5971 1492 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5972 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5973 1492 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5974 1492 : const auto iInit = i;
5975 18982 : for (; i + 31 < iMax; i += 32)
5976 : {
5977 17490 : const GDALm256i ymm = GDALmm256_load_si256(
5978 17490 : reinterpret_cast<const GDALm256i *>(pData + i));
5979 :
5980 : // Check which values are nodata
5981 : const GDALm256i ymm_eq_nodata =
5982 17490 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5983 : if constexpr (COMPUTE_OTHER_STATS)
5984 : {
5985 : // Count how many values are nodata (due to cmpeq
5986 : // putting 255 when condition is met, this will actually
5987 : // be 255 times the number of nodata value, spread in 4
5988 : // 64 bits words). We can use add_epi32 as the counter
5989 : // will not overflow uint32
5990 9148 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5991 : ymm_count_nodata_mul_255,
5992 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5993 : }
5994 : // Replace all nodata values by zero for the purpose of sum
5995 : // and sumquare.
5996 : const GDALm256i ymm_nodata_by_zero =
5997 17490 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5998 17490 : if (bComputeMinMax)
5999 : {
6000 : // Replace all nodata values by a neutral value for the
6001 : // purpose of min and max.
6002 : const GDALm256i ymm_nodata_by_neutral =
6003 8720 : GDALmm256_or_si256(
6004 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6005 : ymm_nodata_by_zero);
6006 :
6007 : ymm_min =
6008 8720 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6009 : ymm_max =
6010 8720 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6011 : }
6012 :
6013 : if constexpr (COMPUTE_OTHER_STATS)
6014 : {
6015 : // Extract even-8bit values
6016 9148 : const GDALm256i ymm_even = GDALmm256_and_si256(
6017 : ymm_nodata_by_zero, ymm_mask_8bits);
6018 : // Compute square of those 16 values as 32 bit result
6019 : // and add adjacent pairs
6020 : const GDALm256i ymm_even_square =
6021 9148 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6022 : // Add to the sumsquare accumulator
6023 : ymm_sumsquare =
6024 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6025 :
6026 : // Extract odd-8bit values
6027 : const GDALm256i ymm_odd =
6028 9148 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6029 : const GDALm256i ymm_odd_square =
6030 9148 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6031 : ymm_sumsquare =
6032 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6033 :
6034 : // Now compute the sums
6035 9148 : ymm_sum = GDALmm256_add_epi32(
6036 : ymm_sum,
6037 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6038 : }
6039 : }
6040 :
6041 : if constexpr (COMPUTE_OTHER_STATS)
6042 : {
6043 186 : GUInt32 *panCoutNoDataMul255 = panSum;
6044 186 : GDALmm256_store_si256(
6045 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6046 : ymm_count_nodata_mul_255);
6047 :
6048 186 : nSampleCount += (i - iInit);
6049 :
6050 186 : nValidCount +=
6051 186 : (i - iInit) -
6052 186 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6053 186 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6054 : 255;
6055 :
6056 186 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6057 : ymm_sum);
6058 186 : GDALmm256_store_si256(
6059 : reinterpret_cast<GDALm256i *>(panSumSquare),
6060 : ymm_sumsquare);
6061 186 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6062 186 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6063 186 : panSumSquare[1] + panSumSquare[2] +
6064 186 : panSumSquare[3] + panSumSquare[4] +
6065 186 : panSumSquare[5] + panSumSquare[6] +
6066 : panSumSquare[7];
6067 : }
6068 : }
6069 :
6070 1492 : if (bComputeMinMax)
6071 : {
6072 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6073 : ymm_min);
6074 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6075 : ymm_max);
6076 47190 : for (int j = 0; j < 32; j++)
6077 : {
6078 45760 : if (pabyMin[j] < nMin)
6079 40 : nMin = pabyMin[j];
6080 45760 : if (pabyMax[j] > nMax)
6081 161 : nMax = pabyMax[j];
6082 : }
6083 : }
6084 :
6085 : if constexpr (COMPUTE_OTHER_STATS)
6086 : {
6087 186 : nSampleCount += nBlockPixels - i;
6088 : }
6089 34048 : for (; i < nBlockPixels; i++)
6090 : {
6091 32556 : const GUInt32 nValue = pData[i];
6092 32556 : if (nValue == nNoDataValue)
6093 24923 : continue;
6094 7633 : if (nValue < nMin)
6095 2 : nMin = nValue;
6096 7633 : if (nValue > nMax)
6097 14 : nMax = nValue;
6098 : if constexpr (COMPUTE_OTHER_STATS)
6099 : {
6100 3700 : nValidCount++;
6101 3700 : nSum += nValue;
6102 3700 : nSumSquare +=
6103 3700 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6104 3700 : nValue;
6105 : }
6106 1492 : }
6107 : }
6108 28746 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6109 : {
6110 14989 : if (nMin > 0)
6111 : {
6112 2092 : if (nMax < 255)
6113 : {
6114 : ComputeStatisticsByteNoNodata<true, true,
6115 1569 : COMPUTE_OTHER_STATS>(
6116 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6117 : nSampleCount, nValidCount);
6118 : }
6119 : else
6120 : {
6121 : ComputeStatisticsByteNoNodata<true, false,
6122 523 : COMPUTE_OTHER_STATS>(
6123 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6124 : nSampleCount, nValidCount);
6125 : }
6126 : }
6127 : else
6128 : {
6129 12897 : if (nMax < 255)
6130 : {
6131 : ComputeStatisticsByteNoNodata<false, true,
6132 9408 : COMPUTE_OTHER_STATS>(
6133 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6134 : nSampleCount, nValidCount);
6135 : }
6136 : else
6137 : {
6138 : ComputeStatisticsByteNoNodata<false, false,
6139 3489 : COMPUTE_OTHER_STATS>(
6140 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6141 : nSampleCount, nValidCount);
6142 : }
6143 : }
6144 : }
6145 12484 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6146 33 : (nBlockXSize % 32) == 0)
6147 : {
6148 6389 : for (int iY = 0; iY < nYCheck; iY++)
6149 : {
6150 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6151 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6152 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6153 33 : }
6154 : }
6155 : else
6156 : {
6157 13724 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6158 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6159 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6160 : }
6161 30238 : }
6162 : };
6163 :
6164 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6165 570 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6166 : GUIntBig i)
6167 : {
6168 570 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6169 570 : }
6170 :
6171 : // AVX2/SSE2 optimization for GUInt16 case
6172 : template <bool COMPUTE_OTHER_STATS>
6173 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6174 : {
6175 2093 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6176 : // assumed to be aligned on 128 bits
6177 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6178 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6179 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6180 : GUIntBig &nValidCount)
6181 : {
6182 2093 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6183 2093 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6184 : {
6185 1844 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6186 :
6187 1844 : GPtrDiff_t i = 0;
6188 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6189 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6190 : // Furthermore the shift is also needed to use madd_epi16
6191 1844 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6192 1844 : GDALm256i ymm_min = GDALmm256_load_si256(
6193 1844 : reinterpret_cast<const GDALm256i *>(pData + i));
6194 1844 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6195 1844 : GDALm256i ymm_max = ymm_min;
6196 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6197 1844 : ZERO256; // holds 4 uint64 sums
6198 :
6199 : // Make sure that sum can fit on uint32
6200 : // * 8 since we can hold 8 sums per vector register
6201 1844 : const int nMaxIterationsPerInnerLoop =
6202 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6203 1844 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6204 1844 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6205 1844 : nOuterLoops++;
6206 :
6207 1844 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6208 : [[maybe_unused]] const auto ymm_mask_16bits =
6209 1844 : GDALmm256_set1_epi32(0xFFFF);
6210 : [[maybe_unused]] const auto ymm_mask_32bits =
6211 1844 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6212 :
6213 1844 : GUIntBig nSumThis = 0;
6214 3712 : for (int k = 0; k < nOuterLoops; k++)
6215 : {
6216 1868 : const auto iMax =
6217 1868 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6218 :
6219 : [[maybe_unused]] GDALm256i ymm_sum =
6220 1868 : ZERO256; // holds 8 uint32 sums
6221 1057198 : for (; i + 15 < iMax; i += 16)
6222 : {
6223 1055330 : const GDALm256i ymm = GDALmm256_load_si256(
6224 1055330 : reinterpret_cast<const GDALm256i *>(pData + i));
6225 : const GDALm256i ymm_shifted =
6226 1055330 : GDALmm256_add_epi16(ymm, ymm_m32768);
6227 1055330 : if (bComputeMinMax)
6228 : {
6229 1037292 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6230 1037292 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6231 : }
6232 :
6233 : if constexpr (COMPUTE_OTHER_STATS)
6234 : {
6235 : // Note: the int32 range can overflow for (0-32768)^2 +
6236 : // (0-32768)^2 = 0x80000000, but as we know the result
6237 : // is positive, this is OK as we interpret is a uint32.
6238 : const GDALm256i ymm_square =
6239 188312 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6240 188312 : ymm_sumsquare = GDALmm256_add_epi64(
6241 : ymm_sumsquare,
6242 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6243 188312 : ymm_sumsquare = GDALmm256_add_epi64(
6244 : ymm_sumsquare,
6245 : GDALmm256_srli_epi64(ymm_square, 32));
6246 :
6247 : // Now compute the sums
6248 188312 : ymm_sum = GDALmm256_add_epi32(
6249 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6250 188312 : ymm_sum = GDALmm256_add_epi32(
6251 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6252 : }
6253 : }
6254 :
6255 : if constexpr (COMPUTE_OTHER_STATS)
6256 : {
6257 : GUInt32 anSum[8];
6258 570 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6259 : ymm_sum);
6260 570 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6261 570 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6262 570 : anSum[6] + anSum[7];
6263 : }
6264 : }
6265 :
6266 1844 : if (bComputeMinMax)
6267 : {
6268 : GUInt16 anMin[16];
6269 : GUInt16 anMax[16];
6270 :
6271 : // Unshift the result
6272 1762 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6273 1762 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6274 1762 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6275 : ymm_min);
6276 1762 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6277 : ymm_max);
6278 29954 : for (int j = 0; j < 16; j++)
6279 : {
6280 28192 : if (anMin[j] < nMin)
6281 389 : nMin = anMin[j];
6282 28192 : if (anMax[j] > nMax)
6283 567 : nMax = anMax[j];
6284 : }
6285 : }
6286 :
6287 : if constexpr (COMPUTE_OTHER_STATS)
6288 : {
6289 : GUIntBig anSumSquare[4];
6290 570 : GDALmm256_storeu_si256(
6291 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6292 570 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6293 : anSumSquare[3];
6294 :
6295 : // Unshift the sum of squares
6296 570 : UnshiftSumSquare(nSumSquare, nSumThis,
6297 : static_cast<GUIntBig>(i));
6298 :
6299 570 : nSum += nSumThis;
6300 :
6301 1014 : for (; i < nBlockPixels; i++)
6302 : {
6303 444 : const GUInt32 nValue = pData[i];
6304 444 : if (nValue < nMin)
6305 2 : nMin = nValue;
6306 444 : if (nValue > nMax)
6307 2 : nMax = nValue;
6308 444 : nSum += nValue;
6309 444 : nSumSquare +=
6310 444 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6311 444 : nValue;
6312 : }
6313 :
6314 570 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6315 570 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6316 1844 : }
6317 : }
6318 : else
6319 : {
6320 249 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6321 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6322 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6323 : }
6324 2093 : }
6325 : };
6326 :
6327 : #endif
6328 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6329 : // defined(_MSC_VER))
6330 :
6331 : /************************************************************************/
6332 : /* GetPixelValue() */
6333 : /************************************************************************/
6334 :
6335 19453000 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6336 : const void *pData, GPtrDiff_t iOffset,
6337 : const GDALNoDataValues &sNoDataValues,
6338 : bool &bValid)
6339 : {
6340 19453000 : bValid = true;
6341 19453000 : double dfValue = 0;
6342 19453000 : switch (eDataType)
6343 : {
6344 1400770 : case GDT_Byte:
6345 : {
6346 1400770 : if (bSignedByte)
6347 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6348 : else
6349 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6350 1400770 : break;
6351 : }
6352 10409 : case GDT_Int8:
6353 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6354 10409 : break;
6355 200608 : case GDT_UInt16:
6356 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6357 200608 : break;
6358 60193 : case GDT_Int16:
6359 60193 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6360 60193 : break;
6361 27600 : case GDT_UInt32:
6362 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6363 27600 : break;
6364 456810 : case GDT_Int32:
6365 456810 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6366 456810 : break;
6367 2604 : case GDT_UInt64:
6368 2604 : dfValue = static_cast<double>(
6369 2604 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6370 2604 : break;
6371 7404 : case GDT_Int64:
6372 7404 : dfValue = static_cast<double>(
6373 7404 : static_cast<const std::int64_t *>(pData)[iOffset]);
6374 7404 : break;
6375 0 : case GDT_Float16:
6376 : {
6377 : using namespace std;
6378 0 : const GFloat16 hfValue =
6379 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6380 0 : if (isnan(hfValue) ||
6381 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6382 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6383 : {
6384 0 : bValid = false;
6385 0 : return 0.0;
6386 : }
6387 0 : dfValue = hfValue;
6388 0 : return dfValue;
6389 : }
6390 13494500 : case GDT_Float32:
6391 : {
6392 13494500 : const float fValue = static_cast<const float *>(pData)[iOffset];
6393 26962000 : if (std::isnan(fValue) ||
6394 26736400 : (sNoDataValues.bGotFloatNoDataValue &&
6395 13268800 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6396 : {
6397 26877 : bValid = false;
6398 26877 : return 0.0;
6399 : }
6400 13467600 : dfValue = double(fValue);
6401 13467600 : return dfValue;
6402 : }
6403 3775010 : case GDT_Float64:
6404 3775010 : dfValue = static_cast<const double *>(pData)[iOffset];
6405 3775010 : if (std::isnan(dfValue))
6406 : {
6407 6 : bValid = false;
6408 6 : return 0.0;
6409 : }
6410 3775000 : break;
6411 2692 : case GDT_CInt16:
6412 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6413 2692 : break;
6414 2692 : case GDT_CInt32:
6415 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6416 2692 : break;
6417 0 : case GDT_CFloat16:
6418 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6419 0 : if (std::isnan(dfValue))
6420 : {
6421 0 : bValid = false;
6422 0 : return 0.0;
6423 : }
6424 0 : break;
6425 5812 : case GDT_CFloat32:
6426 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6427 5812 : if (std::isnan(dfValue))
6428 : {
6429 0 : bValid = false;
6430 0 : return 0.0;
6431 : }
6432 5812 : break;
6433 5892 : case GDT_CFloat64:
6434 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6435 5892 : if (std::isnan(dfValue))
6436 : {
6437 0 : bValid = false;
6438 0 : return 0.0;
6439 : }
6440 5892 : break;
6441 0 : case GDT_Unknown:
6442 : case GDT_TypeCount:
6443 0 : CPLAssert(false);
6444 : break;
6445 : }
6446 :
6447 9719860 : if (sNoDataValues.bGotNoDataValue &&
6448 3761370 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6449 : {
6450 3338720 : bValid = false;
6451 3338720 : return 0.0;
6452 : }
6453 2619770 : return dfValue;
6454 : }
6455 :
6456 : /************************************************************************/
6457 : /* SetValidPercent() */
6458 : /************************************************************************/
6459 :
6460 : //! @cond Doxygen_Suppress
6461 : /**
6462 : * \brief Set percentage of valid (not nodata) pixels.
6463 : *
6464 : * Stores the percentage of valid pixels in the metadata item
6465 : * STATISTICS_VALID_PERCENT
6466 : *
6467 : * @param nSampleCount Number of sampled pixels.
6468 : *
6469 : * @param nValidCount Number of valid pixels.
6470 : */
6471 :
6472 532 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6473 : GUIntBig nValidCount)
6474 : {
6475 532 : if (nValidCount == 0)
6476 : {
6477 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6478 : }
6479 520 : else if (nValidCount == nSampleCount)
6480 : {
6481 462 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6482 : }
6483 : else /* nValidCount < nSampleCount */
6484 : {
6485 58 : char szValue[128] = {0};
6486 :
6487 : /* percentage is only an indicator: limit precision */
6488 58 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6489 58 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6490 :
6491 58 : if (EQUAL(szValue, "100"))
6492 : {
6493 : /* don't set 100 percent valid
6494 : * because some of the sampled pixels were nodata */
6495 4 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6496 : }
6497 : else
6498 : {
6499 54 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6500 : }
6501 : }
6502 532 : }
6503 :
6504 : //! @endcond
6505 :
6506 : #if (defined(__x86_64__) || defined(_M_X64))
6507 :
6508 : #ifdef __AVX2__
6509 :
6510 : #define setzero_si _mm256_setzero_si256
6511 : #define setzero_ps _mm256_setzero_ps
6512 : #define set1_ps _mm256_set1_ps
6513 : #define set1_epi32 _mm256_set1_epi32
6514 : #define add_epi32 _mm256_add_epi32
6515 : #define loadu_ps _mm256_loadu_ps
6516 : #define or_ps _mm256_or_ps
6517 : #define min_ps _mm256_min_ps
6518 : #define max_ps _mm256_max_ps
6519 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6520 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6521 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6522 : #define movemask_ps _mm256_movemask_ps
6523 : #define add_ps _mm256_add_ps
6524 : #define sub_ps _mm256_sub_ps
6525 : #define mul_ps _mm256_mul_ps
6526 : #define div_ps _mm256_div_ps
6527 : #define storeu_ps _mm256_storeu_ps
6528 : #define cvtepi32_ps _mm256_cvtepi32_ps
6529 : #define cvtsi_si32(x) _mm256_extract_epi32((x), 0)
6530 : #define blendv_ps _mm256_blendv_ps
6531 : #ifdef __FMA__
6532 : #define fmadd_ps _mm256_fmadd_ps
6533 : #else
6534 : #define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
6535 : #endif
6536 :
6537 : #else
6538 :
6539 : #define setzero_si _mm_setzero_si128
6540 : #define setzero_ps _mm_setzero_ps
6541 : #define set1_ps _mm_set1_ps
6542 : #define set1_epi32 _mm_set1_epi32
6543 : #define add_epi32 _mm_add_epi32
6544 : #define loadu_ps _mm_loadu_ps
6545 : #define or_ps _mm_or_ps
6546 : #define min_ps _mm_min_ps
6547 : #define max_ps _mm_max_ps
6548 : #define cmpeq_ps _mm_cmpeq_ps
6549 : #define cmpneq_ps _mm_cmpneq_ps
6550 : #define cmpunord_ps _mm_cmpunord_ps
6551 : #define movemask_ps _mm_movemask_ps
6552 : #define add_ps _mm_add_ps
6553 : #define sub_ps _mm_sub_ps
6554 : #define mul_ps _mm_mul_ps
6555 : #define div_ps _mm_div_ps
6556 : #define storeu_ps _mm_storeu_ps
6557 : #define cvtepi32_ps _mm_cvtepi32_ps
6558 : #define cvtsi_si32 _mm_cvtsi128_si32
6559 : #ifdef __FMA__
6560 : #define fmadd_ps _mm_fmadd_ps
6561 : #else
6562 : #define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
6563 : #endif
6564 :
6565 2065850 : inline __m128 blendv_ps(__m128 a, __m128 b, __m128 mask)
6566 : {
6567 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6568 : return _mm_blendv_ps(a, b, mask);
6569 : #else
6570 6197540 : return _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b));
6571 : #endif
6572 : }
6573 : #endif
6574 :
6575 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6576 : #if defined(__GNUC__)
6577 : __attribute__((noinline))
6578 : #endif
6579 : static int
6580 4889 : ComputeStatisticsFloat32_SSE2(const float *pafData,
6581 : [[maybe_unused]] float fNoDataValue, int iX,
6582 : int nCount, float &fMin, float &fMax,
6583 : float &fBlockMean, float &fBlockM2,
6584 : int &nBlockValidCount)
6585 : {
6586 4889 : auto vValidCount = setzero_si();
6587 4889 : const auto vOne = set1_epi32(1);
6588 4889 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6589 :
6590 4889 : auto vMin_lo = set1_ps(fMin);
6591 9778 : auto vMax_lo = set1_ps(fMax);
6592 4889 : auto vMean_lo = setzero_ps();
6593 4889 : auto vM2_lo = setzero_ps();
6594 :
6595 4889 : auto vMin_hi = vMin_lo;
6596 4889 : auto vMax_hi = vMax_lo;
6597 4889 : auto vMean_hi = setzero_ps();
6598 4889 : auto vM2_hi = setzero_ps();
6599 :
6600 4889 : constexpr int VALS_PER_LOOP =
6601 : 2 * static_cast<int>(sizeof(vOne) / sizeof(float));
6602 590671 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6603 : {
6604 585783 : const auto vValues_lo = loadu_ps(pafData + iX);
6605 1171568 : const auto vValues_hi = loadu_ps(pafData + iX + VALS_PER_LOOP / 2);
6606 : // Check if there's at least one NaN in both vectors
6607 585783 : auto isNaNOrNoData = cmpunord_ps(vValues_lo, vValues_hi);
6608 : if constexpr (HAS_NODATA)
6609 : {
6610 : isNaNOrNoData =
6611 0 : or_ps(isNaNOrNoData, or_ps(cmpeq_ps(vValues_lo, vNoData),
6612 : cmpeq_ps(vValues_hi, vNoData)));
6613 : }
6614 585783 : if (movemask_ps(isNaNOrNoData))
6615 : {
6616 1 : break;
6617 : }
6618 :
6619 585782 : vValidCount = add_epi32(vValidCount, vOne);
6620 585782 : const auto vValidCountFloat32 = cvtepi32_ps(vValidCount);
6621 :
6622 585782 : vMin_lo = min_ps(vMin_lo, vValues_lo);
6623 585782 : vMax_lo = max_ps(vMax_lo, vValues_lo);
6624 585782 : const auto vDelta_lo = sub_ps(vValues_lo, vMean_lo);
6625 : const auto vNewMean_lo =
6626 1102213 : add_ps(vMean_lo, div_ps(vDelta_lo, vValidCountFloat32));
6627 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6628 : {
6629 516429 : const auto vMinNotSameAsMax_lo = cmpneq_ps(vMin_lo, vMax_lo);
6630 516429 : vMean_lo = blendv_ps(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6631 : const auto vNewM2_lo =
6632 1032860 : fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
6633 516429 : vM2_lo = blendv_ps(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6634 : }
6635 : else
6636 : {
6637 69353 : vMean_lo = vNewMean_lo;
6638 208059 : vM2_lo = fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
6639 : }
6640 :
6641 585782 : vMin_hi = min_ps(vMin_hi, vValues_hi);
6642 585782 : vMax_hi = max_ps(vMax_hi, vValues_hi);
6643 585782 : const auto vDelta_hi = sub_ps(vValues_hi, vMean_hi);
6644 : const auto vNewMean_hi =
6645 1102213 : add_ps(vMean_hi, div_ps(vDelta_hi, vValidCountFloat32));
6646 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6647 : {
6648 516429 : const auto vMinNotSameAsMax_hi = cmpneq_ps(vMin_hi, vMax_hi);
6649 516429 : vMean_hi = blendv_ps(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6650 : const auto vNewM2_hi =
6651 1032860 : fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
6652 516429 : vM2_hi = blendv_ps(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6653 : }
6654 : else
6655 : {
6656 69353 : vMean_hi = vNewMean_hi;
6657 208059 : vM2_hi = fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
6658 : }
6659 : }
6660 4889 : const int nValidVectorCount = cvtsi_si32(vValidCount);
6661 4889 : if (nValidVectorCount)
6662 : {
6663 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP], afMean[VALS_PER_LOOP],
6664 : afM2[VALS_PER_LOOP];
6665 : storeu_ps(afMin, vMin_lo);
6666 : storeu_ps(afMax, vMax_lo);
6667 : storeu_ps(afMean, vMean_lo);
6668 : storeu_ps(afM2, vM2_lo);
6669 4631 : storeu_ps(afMin + VALS_PER_LOOP / 2, vMin_hi);
6670 4631 : storeu_ps(afMax + VALS_PER_LOOP / 2, vMax_hi);
6671 4631 : storeu_ps(afMean + VALS_PER_LOOP / 2, vMean_hi);
6672 4631 : storeu_ps(afM2 + VALS_PER_LOOP / 2, vM2_hi);
6673 :
6674 41679 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6675 : {
6676 37048 : fMin = std::min(fMin, afMin[i]);
6677 37048 : fMax = std::max(fMax, afMax[i]);
6678 37048 : const auto nNewValidCount = nBlockValidCount + nValidVectorCount;
6679 37048 : if (afMean[i] != fBlockMean)
6680 : {
6681 17864 : const float fDelta = afMean[i] - fBlockMean;
6682 17864 : fBlockMean += fDelta * nValidVectorCount / nNewValidCount;
6683 17864 : fBlockM2 += afM2[i] + fDelta * fDelta * nBlockValidCount *
6684 17864 : nValidVectorCount / nNewValidCount;
6685 : }
6686 37048 : nBlockValidCount = nNewValidCount;
6687 : }
6688 : }
6689 :
6690 4889 : return iX;
6691 : }
6692 :
6693 : #ifdef __AVX2__
6694 :
6695 : #define setzero_pd _mm256_setzero_pd
6696 : #define set1_pd _mm256_set1_pd
6697 : #define loadu_pd _mm256_loadu_pd
6698 : #define or_pd _mm256_or_pd
6699 : #define min_pd _mm256_min_pd
6700 : #define max_pd _mm256_max_pd
6701 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6702 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6703 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6704 : #define movemask_pd _mm256_movemask_pd
6705 : #define add_pd _mm256_add_pd
6706 : #define sub_pd _mm256_sub_pd
6707 : #define mul_pd _mm256_mul_pd
6708 : #define div_pd _mm256_div_pd
6709 : #define storeu_pd _mm256_storeu_pd
6710 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6711 : #define blendv_pd _mm256_blendv_pd
6712 : #ifdef __FMA__
6713 : #define fmadd_pd _mm256_fmadd_pd
6714 : #else
6715 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6716 : #endif
6717 :
6718 : #else
6719 :
6720 : #define setzero_pd _mm_setzero_pd
6721 : #define set1_pd _mm_set1_pd
6722 : #define loadu_pd _mm_loadu_pd
6723 : #define or_pd _mm_or_pd
6724 : #define min_pd _mm_min_pd
6725 : #define max_pd _mm_max_pd
6726 : #define cmpeq_pd _mm_cmpeq_pd
6727 : #define cmpneq_pd _mm_cmpneq_pd
6728 : #define cmpunord_pd _mm_cmpunord_pd
6729 : #define movemask_pd _mm_movemask_pd
6730 : #define add_pd _mm_add_pd
6731 : #define sub_pd _mm_sub_pd
6732 : #define mul_pd _mm_mul_pd
6733 : #define div_pd _mm_div_pd
6734 : #define storeu_pd _mm_storeu_pd
6735 : #define cvtsd_f64 _mm_cvtsd_f64
6736 : #ifdef __FMA__
6737 : #define fmadd_pd _mm_fmadd_pd
6738 : #else
6739 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6740 : #endif
6741 :
6742 103928 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6743 : {
6744 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6745 : return _mm_blendv_pd(a, b, mask);
6746 : #else
6747 311784 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6748 : #endif
6749 : }
6750 : #endif
6751 :
6752 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6753 : #if defined(__GNUC__)
6754 : __attribute__((noinline))
6755 : #endif
6756 : static int
6757 1351 : ComputeStatisticsFloat64_SSE2(const double *padfData,
6758 : [[maybe_unused]] double dfNoDataValue, int iX,
6759 : int nCount, double &dfMin, double &dfMax,
6760 : double &dfBlockMean, double &dfBlockM2,
6761 : double &dfBlockValidCount)
6762 : {
6763 1351 : auto vValidCount = setzero_pd();
6764 1351 : const auto vOne = set1_pd(1);
6765 1351 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6766 :
6767 1351 : auto vMin_lo = set1_pd(dfMin);
6768 2702 : auto vMax_lo = set1_pd(dfMax);
6769 1351 : auto vMean_lo = setzero_pd();
6770 1351 : auto vM2_lo = setzero_pd();
6771 :
6772 1351 : auto vMin_hi = vMin_lo;
6773 1351 : auto vMax_hi = vMax_lo;
6774 1351 : auto vMean_hi = setzero_pd();
6775 1351 : auto vM2_hi = setzero_pd();
6776 :
6777 1351 : constexpr int VALS_PER_LOOP =
6778 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6779 43687 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6780 : {
6781 42379 : const auto vValues_lo = loadu_pd(padfData + iX);
6782 84758 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6783 : // Check if there's at least one NaN in both vectors
6784 42379 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6785 : if constexpr (HAS_NODATA)
6786 : {
6787 : isNaNOrNoData =
6788 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6789 : cmpeq_pd(vValues_hi, vNoData)));
6790 : }
6791 42379 : if (movemask_pd(isNaNOrNoData))
6792 : {
6793 43 : break;
6794 : }
6795 :
6796 42336 : vValidCount = add_pd(vValidCount, vOne);
6797 42336 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6798 :
6799 42336 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6800 42336 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6801 42336 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6802 68318 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6803 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6804 : {
6805 25982 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6806 25982 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6807 : const auto vNewM2_lo =
6808 51964 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6809 25982 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6810 : }
6811 : else
6812 : {
6813 16354 : vMean_lo = vNewMean_lo;
6814 49062 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6815 : }
6816 :
6817 42336 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6818 42336 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6819 42336 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6820 68318 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6821 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6822 : {
6823 25982 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6824 25982 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6825 : const auto vNewM2_hi =
6826 51964 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6827 25982 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6828 : }
6829 : else
6830 : {
6831 16354 : vMean_hi = vNewMean_hi;
6832 49062 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6833 : }
6834 : }
6835 1351 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6836 1351 : if (dfValidVectorCount > 0)
6837 : {
6838 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6839 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6840 : storeu_pd(adfMin, vMin_lo);
6841 : storeu_pd(adfMax, vMax_lo);
6842 : storeu_pd(adfMean, vMean_lo);
6843 : storeu_pd(adfM2, vM2_lo);
6844 801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6845 801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6846 801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6847 801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6848 :
6849 4005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6850 : {
6851 3204 : dfMin = std::min(dfMin, adfMin[i]);
6852 3204 : dfMax = std::max(dfMax, adfMax[i]);
6853 3204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6854 3204 : if (adfMean[i] != dfBlockMean)
6855 : {
6856 1874 : const double dfDelta = adfMean[i] - dfBlockMean;
6857 1874 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6858 1874 : dfBlockM2 += adfM2[i] + dfDelta * dfDelta * dfBlockValidCount *
6859 1874 : dfValidVectorCount /
6860 : dfNewValidCount;
6861 : }
6862 3204 : dfBlockValidCount = dfNewValidCount;
6863 : }
6864 : }
6865 :
6866 1351 : return iX;
6867 : }
6868 :
6869 : #endif
6870 :
6871 : /************************************************************************/
6872 : /* ComputeStatistics() */
6873 : /************************************************************************/
6874 :
6875 : /**
6876 : * \brief Compute image statistics.
6877 : *
6878 : * Returns the minimum, maximum, mean and standard deviation of all
6879 : * pixel values in this band. If approximate statistics are sufficient,
6880 : * the bApproxOK flag can be set to true in which case overviews, or a
6881 : * subset of image tiles may be used in computing the statistics.
6882 : *
6883 : * Once computed, the statistics will generally be "set" back on the
6884 : * raster band using SetStatistics().
6885 : *
6886 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6887 : *
6888 : * This method is the same as the C function GDALComputeRasterStatistics().
6889 : *
6890 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6891 : * or a subset of all tiles.
6892 : *
6893 : * @param pdfMin Location into which to load image minimum (may be NULL).
6894 : *
6895 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6896 : *
6897 : * @param pdfMean Location into which to load image mean (may be NULL).
6898 : *
6899 : * @param pdfStdDev Location into which to load image standard deviation
6900 : * (may be NULL).
6901 : *
6902 : * @param pfnProgress a function to call to report progress, or NULL.
6903 : *
6904 : * @param pProgressData application data to pass to the progress function.
6905 : *
6906 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6907 : * is terminated by the user.
6908 : */
6909 :
6910 510 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6911 : double *pdfMax, double *pdfMean,
6912 : double *pdfStdDev,
6913 : GDALProgressFunc pfnProgress,
6914 : void *pProgressData)
6915 :
6916 : {
6917 510 : if (pfnProgress == nullptr)
6918 182 : pfnProgress = GDALDummyProgress;
6919 :
6920 : /* -------------------------------------------------------------------- */
6921 : /* If we have overview bands, use them for statistics. */
6922 : /* -------------------------------------------------------------------- */
6923 510 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6924 : {
6925 : GDALRasterBand *poBand =
6926 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6927 :
6928 3 : if (poBand != this)
6929 : {
6930 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6931 : pdfMean, pdfStdDev,
6932 3 : pfnProgress, pProgressData);
6933 3 : if (eErr == CE_None)
6934 : {
6935 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6936 : {
6937 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6938 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6939 : }
6940 :
6941 : /* transfer metadata from overview band to this */
6942 : const char *pszPercentValid =
6943 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6944 :
6945 3 : if (pszPercentValid != nullptr)
6946 : {
6947 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6948 3 : pszPercentValid);
6949 : }
6950 : }
6951 3 : return eErr;
6952 : }
6953 : }
6954 :
6955 507 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6956 : {
6957 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6958 0 : return CE_Failure;
6959 : }
6960 :
6961 : /* -------------------------------------------------------------------- */
6962 : /* Read actual data and compute statistics. */
6963 : /* -------------------------------------------------------------------- */
6964 : // Using Welford algorithm:
6965 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6966 : // to compute standard deviation in a more numerically robust way than
6967 : // the difference of the sum of square values with the square of the sum.
6968 : // dfMean and dfM2 are updated at each sample.
6969 : // dfM2 is the sum of square of differences to the current mean.
6970 507 : double dfMin = std::numeric_limits<double>::infinity();
6971 507 : double dfMax = -std::numeric_limits<double>::infinity();
6972 507 : double dfMean = 0.0;
6973 507 : double dfM2 = 0.0;
6974 :
6975 : GDALRasterIOExtraArg sExtraArg;
6976 507 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6977 :
6978 507 : GDALNoDataValues sNoDataValues(this, eDataType);
6979 507 : GDALRasterBand *poMaskBand = nullptr;
6980 507 : if (!sNoDataValues.bGotNoDataValue)
6981 : {
6982 474 : const int l_nMaskFlags = GetMaskFlags();
6983 520 : if (l_nMaskFlags != GMF_ALL_VALID &&
6984 46 : GetColorInterpretation() != GCI_AlphaBand)
6985 : {
6986 46 : poMaskBand = GetMaskBand();
6987 : }
6988 : }
6989 :
6990 507 : bool bSignedByte = false;
6991 507 : if (eDataType == GDT_Byte)
6992 : {
6993 210 : EnablePixelTypeSignedByteWarning(false);
6994 : const char *pszPixelType =
6995 210 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6996 210 : EnablePixelTypeSignedByteWarning(true);
6997 210 : bSignedByte =
6998 210 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6999 : }
7000 :
7001 507 : GUIntBig nSampleCount = 0;
7002 507 : GUIntBig nValidCount = 0;
7003 :
7004 507 : if (bApproxOK && HasArbitraryOverviews())
7005 : {
7006 : /* --------------------------------------------------------------------
7007 : */
7008 : /* Figure out how much the image should be reduced to get an */
7009 : /* approximate value. */
7010 : /* --------------------------------------------------------------------
7011 : */
7012 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7013 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7014 :
7015 0 : int nXReduced = nRasterXSize;
7016 0 : int nYReduced = nRasterYSize;
7017 0 : if (dfReduction > 1.0)
7018 : {
7019 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7020 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7021 :
7022 : // Catch the case of huge resizing ratios here
7023 0 : if (nXReduced == 0)
7024 0 : nXReduced = 1;
7025 0 : if (nYReduced == 0)
7026 0 : nYReduced = 1;
7027 : }
7028 :
7029 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7030 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7031 :
7032 : const CPLErr eErr =
7033 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7034 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7035 0 : if (eErr != CE_None)
7036 : {
7037 0 : CPLFree(pData);
7038 0 : return eErr;
7039 : }
7040 :
7041 0 : GByte *pabyMaskData = nullptr;
7042 0 : if (poMaskBand)
7043 : {
7044 : pabyMaskData =
7045 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7046 0 : if (!pabyMaskData)
7047 : {
7048 0 : CPLFree(pData);
7049 0 : return CE_Failure;
7050 : }
7051 :
7052 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7053 : pabyMaskData, nXReduced, nYReduced,
7054 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7055 : {
7056 0 : CPLFree(pData);
7057 0 : CPLFree(pabyMaskData);
7058 0 : return CE_Failure;
7059 : }
7060 : }
7061 :
7062 : /* this isn't the fastest way to do this, but is easier for now */
7063 0 : for (int iY = 0; iY < nYReduced; iY++)
7064 : {
7065 0 : for (int iX = 0; iX < nXReduced; iX++)
7066 : {
7067 0 : const int iOffset = iX + iY * nXReduced;
7068 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7069 0 : continue;
7070 :
7071 0 : bool bValid = true;
7072 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7073 0 : iOffset, sNoDataValues, bValid);
7074 0 : if (!bValid)
7075 0 : continue;
7076 :
7077 0 : dfMin = std::min(dfMin, dfValue);
7078 0 : dfMax = std::max(dfMax, dfValue);
7079 :
7080 0 : nValidCount++;
7081 0 : if (dfMin == dfMax)
7082 : {
7083 0 : if (nValidCount == 1)
7084 0 : dfMean = dfMin;
7085 : }
7086 : else
7087 : {
7088 0 : const double dfDelta = dfValue - dfMean;
7089 0 : dfMean += dfDelta / nValidCount;
7090 0 : dfM2 += dfDelta * (dfValue - dfMean);
7091 : }
7092 : }
7093 : }
7094 :
7095 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7096 :
7097 0 : CPLFree(pData);
7098 0 : CPLFree(pabyMaskData);
7099 : }
7100 :
7101 : else // No arbitrary overviews.
7102 : {
7103 507 : if (!InitBlockInfo())
7104 240 : return CE_Failure;
7105 :
7106 : /* --------------------------------------------------------------------
7107 : */
7108 : /* Figure out the ratio of blocks we will read to get an */
7109 : /* approximate value. */
7110 : /* --------------------------------------------------------------------
7111 : */
7112 507 : int nSampleRate = 1;
7113 507 : if (bApproxOK)
7114 : {
7115 43 : nSampleRate = static_cast<int>(std::max(
7116 86 : 1.0,
7117 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7118 : // We want to avoid probing only the first column of blocks for
7119 : // a square shaped raster, because it is not unlikely that it may
7120 : // be padding only (#6378)
7121 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7122 1 : nSampleRate += 1;
7123 : }
7124 507 : if (nSampleRate == 1)
7125 473 : bApproxOK = false;
7126 :
7127 : // Particular case for GDT_Byte and GUInt16 that only use integral types
7128 : // for each block, and possibly for the whole raster.
7129 507 : if (!poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7130 268 : eDataType == GDT_UInt16))
7131 : {
7132 : // We can do integer computation on the whole raster in the Byte case
7133 : // only if the number of pixels explored is lower than
7134 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7135 : // Should be 99.99999% of cases.
7136 : // For GUInt16, this limits to raster of 4 giga pixels
7137 :
7138 : const bool bIntegerStats =
7139 433 : ((eDataType == GDT_Byte &&
7140 193 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7141 193 : nSampleRate <
7142 193 : GUINTBIG_MAX / (255U * 255U) /
7143 193 : (static_cast<GUInt64>(nBlockXSize) *
7144 193 : static_cast<GUInt64>(nBlockYSize))) ||
7145 47 : (eDataType == GDT_UInt16 &&
7146 47 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7147 47 : nSampleRate <
7148 47 : GUINTBIG_MAX / (65535U * 65535U) /
7149 47 : (static_cast<GUInt64>(nBlockXSize) *
7150 527 : static_cast<GUInt64>(nBlockYSize)))) &&
7151 : // Can be set to NO for easier debugging of the !bIntegerStats
7152 : // case which requires huge rasters to trigger
7153 240 : CPLTestBool(
7154 240 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7155 :
7156 240 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
7157 240 : GUInt32 nMin = nMaxValueType;
7158 240 : GUInt32 nMax = 0;
7159 240 : GUIntBig nSum = 0;
7160 240 : GUIntBig nSumSquare = 0;
7161 : // If no valid nodata, map to invalid value (256 for Byte)
7162 240 : const GUInt32 nNoDataValue =
7163 267 : (sNoDataValues.bGotNoDataValue &&
7164 27 : sNoDataValues.dfNoDataValue >= 0 &&
7165 27 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7166 27 : fabs(sNoDataValues.dfNoDataValue -
7167 27 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7168 : 1e-10)) < 1e-10)
7169 267 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7170 : : nMaxValueType + 1;
7171 :
7172 240 : for (GIntBig iSampleBlock = 0;
7173 13057 : iSampleBlock <
7174 13057 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7175 12817 : iSampleBlock += nSampleRate)
7176 : {
7177 12817 : const int iYBlock =
7178 12817 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7179 12817 : const int iXBlock =
7180 12817 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7181 :
7182 : GDALRasterBlock *const poBlock =
7183 12817 : GetLockedBlockRef(iXBlock, iYBlock);
7184 12817 : if (poBlock == nullptr)
7185 0 : return CE_Failure;
7186 :
7187 12817 : void *const pData = poBlock->GetDataRef();
7188 :
7189 12817 : int nXCheck = 0, nYCheck = 0;
7190 12817 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7191 :
7192 12817 : GUIntBig nBlockSum = 0;
7193 12817 : GUIntBig nBlockSumSquare = 0;
7194 12817 : GUIntBig nBlockSampleCount = 0;
7195 12817 : GUIntBig nBlockValidCount = 0;
7196 12817 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7197 12817 : GUIntBig &nBlockSumSquareRef =
7198 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7199 12817 : GUIntBig &nBlockSampleCountRef =
7200 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7201 12817 : GUIntBig &nBlockValidCountRef =
7202 : bIntegerStats ? nValidCount : nBlockValidCount;
7203 :
7204 12817 : if (eDataType == GDT_Byte)
7205 : {
7206 : ComputeStatisticsInternal<
7207 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7208 12135 : f(nXCheck, nBlockXSize, nYCheck,
7209 : static_cast<const GByte *>(pData),
7210 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7211 : nMax, nBlockSumRef, nBlockSumSquareRef,
7212 : nBlockSampleCountRef, nBlockValidCountRef);
7213 : }
7214 : else
7215 : {
7216 : ComputeStatisticsInternal<
7217 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7218 682 : f(nXCheck, nBlockXSize, nYCheck,
7219 : static_cast<const GUInt16 *>(pData),
7220 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7221 : nMax, nBlockSumRef, nBlockSumSquareRef,
7222 : nBlockSampleCountRef, nBlockValidCountRef);
7223 : }
7224 :
7225 12817 : poBlock->DropLock();
7226 :
7227 12817 : if (!bIntegerStats)
7228 : {
7229 169 : nSampleCount += nBlockSampleCount;
7230 169 : if (nBlockValidCount)
7231 : {
7232 : // Update the global mean and M2 (the difference of the
7233 : // square to the mean) from the values of the block
7234 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7235 169 : const double dfBlockValidCount =
7236 169 : static_cast<double>(nBlockValidCount);
7237 169 : const double dfBlockMean =
7238 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7239 : const double dfBlockM2 =
7240 169 : static_cast<double>(
7241 169 : GDALUInt128::Mul(nBlockSumSquare,
7242 169 : nBlockValidCount) -
7243 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7244 169 : dfBlockValidCount;
7245 169 : const double dfDelta = dfBlockMean - dfMean;
7246 169 : const auto nNewValidCount =
7247 169 : nValidCount + nBlockValidCount;
7248 169 : const double dfNewValidCount =
7249 : static_cast<double>(nNewValidCount);
7250 169 : dfMean +=
7251 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7252 169 : dfM2 +=
7253 169 : dfBlockM2 + dfDelta * dfDelta *
7254 169 : static_cast<double>(nValidCount) *
7255 169 : dfBlockValidCount / dfNewValidCount;
7256 169 : nValidCount = nNewValidCount;
7257 : }
7258 : }
7259 :
7260 12817 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7261 12817 : (static_cast<double>(nBlocksPerRow) *
7262 12817 : nBlocksPerColumn),
7263 : "Compute Statistics", pProgressData))
7264 : {
7265 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7266 : "User terminated");
7267 0 : return CE_Failure;
7268 : }
7269 : }
7270 :
7271 240 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7272 : {
7273 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7274 0 : return CE_Failure;
7275 : }
7276 :
7277 240 : double dfStdDev = 0;
7278 240 : if (bIntegerStats)
7279 : {
7280 216 : if (nValidCount)
7281 207 : dfMean = static_cast<double>(nSum) / nValidCount;
7282 :
7283 : // To avoid potential precision issues when doing the difference,
7284 : // we need to do that computation on 128 bit rather than casting
7285 : // to double
7286 : const GDALUInt128 nTmpForStdDev(
7287 216 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7288 432 : GDALUInt128::Mul(nSum, nSum));
7289 216 : dfStdDev =
7290 216 : nValidCount > 0
7291 216 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7292 : : 0.0;
7293 : }
7294 24 : else if (nValidCount > 0)
7295 : {
7296 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7297 : }
7298 :
7299 : /// Save computed information
7300 240 : if (nValidCount > 0)
7301 : {
7302 231 : if (bApproxOK)
7303 : {
7304 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7305 : }
7306 207 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7307 : {
7308 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7309 : }
7310 231 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7311 : }
7312 :
7313 240 : SetValidPercent(nSampleCount, nValidCount);
7314 :
7315 : /* --------------------------------------------------------------------
7316 : */
7317 : /* Record results. */
7318 : /* --------------------------------------------------------------------
7319 : */
7320 240 : if (pdfMin != nullptr)
7321 237 : *pdfMin = nValidCount ? nMin : 0;
7322 240 : if (pdfMax != nullptr)
7323 237 : *pdfMax = nValidCount ? nMax : 0;
7324 :
7325 240 : if (pdfMean != nullptr)
7326 233 : *pdfMean = dfMean;
7327 :
7328 240 : if (pdfStdDev != nullptr)
7329 233 : *pdfStdDev = dfStdDev;
7330 :
7331 240 : if (nValidCount > 0)
7332 231 : return CE_None;
7333 :
7334 9 : ReportError(CE_Failure, CPLE_AppDefined,
7335 : "Failed to compute statistics, no valid pixels found "
7336 : "in sampling.");
7337 9 : return CE_Failure;
7338 : }
7339 :
7340 267 : GByte *pabyMaskData = nullptr;
7341 267 : if (poMaskBand)
7342 : {
7343 : pabyMaskData = static_cast<GByte *>(
7344 46 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7345 46 : if (!pabyMaskData)
7346 : {
7347 0 : return CE_Failure;
7348 : }
7349 : }
7350 :
7351 267 : float fMin = std::numeric_limits<float>::infinity();
7352 267 : float fMax = -std::numeric_limits<float>::infinity();
7353 : const bool bFloat32Optim =
7354 44 : eDataType == GDT_Float32 && !pabyMaskData &&
7355 329 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7356 18 : CPLTestBool(
7357 267 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7358 :
7359 : #if (defined(__x86_64__) || defined(_M_X64))
7360 : const bool bFloat64Optim =
7361 13 : eDataType == GDT_Float64 && !pabyMaskData &&
7362 293 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7363 13 : CPLTestBool(
7364 267 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7365 : #endif
7366 :
7367 267 : for (GIntBig iSampleBlock = 0;
7368 5918 : iSampleBlock <
7369 5918 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7370 5651 : iSampleBlock += nSampleRate)
7371 : {
7372 5651 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7373 5651 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7374 :
7375 5651 : int nXCheck = 0, nYCheck = 0;
7376 5651 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7377 :
7378 6224 : if (poMaskBand &&
7379 573 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7380 573 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7381 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
7382 573 : 0, nBlockXSize, nullptr) != CE_None)
7383 : {
7384 0 : CPLFree(pabyMaskData);
7385 0 : return CE_Failure;
7386 : }
7387 :
7388 : GDALRasterBlock *const poBlock =
7389 5651 : GetLockedBlockRef(iXBlock, iYBlock);
7390 5651 : if (poBlock == nullptr)
7391 : {
7392 0 : CPLFree(pabyMaskData);
7393 0 : return CE_Failure;
7394 : }
7395 :
7396 5651 : const void *const pData = poBlock->GetDataRef();
7397 :
7398 5651 : if (bFloat32Optim)
7399 : {
7400 2330 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7401 0 : !std::isnan(sNoDataValues.fNoDataValue);
7402 2330 : float fBlockMean = 0.0f;
7403 2330 : float fBlockM2 = 0.0f;
7404 2330 : int nBlockValidCount = 0;
7405 7219 : for (int iY = 0; iY < nYCheck; iY++)
7406 : {
7407 4889 : const int iOffset = iY * nBlockXSize;
7408 4889 : if (nBlockValidCount && fMin != fMax)
7409 : {
7410 2432 : int iX = 0;
7411 : #if (defined(__x86_64__) || defined(_M_X64))
7412 2432 : if (bHasNoData)
7413 : {
7414 : iX = ComputeStatisticsFloat32_SSE2<
7415 : /* bCheckMinEqMax = */ false,
7416 0 : /* bHasNoData = */ true>(
7417 0 : static_cast<const float *>(pData) + iOffset,
7418 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7419 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7420 : }
7421 : else
7422 : {
7423 : iX = ComputeStatisticsFloat32_SSE2<
7424 : /* bCheckMinEqMax = */ false,
7425 2432 : /* bHasNoData = */ false>(
7426 2432 : static_cast<const float *>(pData) + iOffset,
7427 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7428 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7429 : }
7430 : #endif
7431 2961 : for (; iX < nXCheck; iX++)
7432 : {
7433 529 : const float fValue =
7434 529 : static_cast<const float *>(pData)[iOffset + iX];
7435 529 : if (std::isnan(fValue) ||
7436 0 : (bHasNoData &&
7437 0 : fValue == sNoDataValues.fNoDataValue))
7438 11 : continue;
7439 518 : fMin = std::min(fMin, fValue);
7440 518 : fMax = std::max(fMax, fValue);
7441 518 : ++nBlockValidCount;
7442 518 : const float fDelta = fValue - fBlockMean;
7443 518 : fBlockMean +=
7444 518 : fDelta / static_cast<float>(nBlockValidCount);
7445 518 : fBlockM2 += fDelta * (fValue - fBlockMean);
7446 2432 : }
7447 : }
7448 : else
7449 : {
7450 2457 : int iX = 0;
7451 2457 : if (nBlockValidCount == 0)
7452 : {
7453 2330 : for (; iX < nXCheck; iX++)
7454 : {
7455 2330 : const float fValue = static_cast<const float *>(
7456 2330 : pData)[iOffset + iX];
7457 2330 : if (std::isnan(fValue) ||
7458 0 : (bHasNoData &&
7459 0 : fValue == sNoDataValues.fNoDataValue))
7460 0 : continue;
7461 2330 : fMin = std::min(fMin, fValue);
7462 2330 : fMax = std::max(fMax, fValue);
7463 2330 : nBlockValidCount = 1;
7464 2330 : fBlockMean = fValue;
7465 2330 : iX++;
7466 2330 : break;
7467 : }
7468 : }
7469 : #if (defined(__x86_64__) || defined(_M_X64))
7470 2457 : if (bHasNoData)
7471 : {
7472 : iX = ComputeStatisticsFloat32_SSE2<
7473 : /* bCheckMinEqMax = */ true,
7474 0 : /* bHasNoData = */ true>(
7475 0 : static_cast<const float *>(pData) + iOffset,
7476 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7477 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7478 : }
7479 : else
7480 : {
7481 : iX = ComputeStatisticsFloat32_SSE2<
7482 : /* bCheckMinEqMax = */ true,
7483 2457 : /* bHasNoData = */ false>(
7484 2457 : static_cast<const float *>(pData) + iOffset,
7485 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7486 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7487 : }
7488 : #endif
7489 17534 : for (; iX < nXCheck; iX++)
7490 : {
7491 15077 : const float fValue =
7492 15077 : static_cast<const float *>(pData)[iOffset + iX];
7493 15077 : if (std::isnan(fValue) ||
7494 0 : (bHasNoData &&
7495 0 : fValue == sNoDataValues.fNoDataValue))
7496 1 : continue;
7497 15076 : fMin = std::min(fMin, fValue);
7498 15076 : fMax = std::max(fMax, fValue);
7499 15076 : ++nBlockValidCount;
7500 15076 : if (fMin != fMax)
7501 : {
7502 7123 : const float fDelta = fValue - fBlockMean;
7503 7123 : fBlockMean += fDelta / static_cast<float>(
7504 : nBlockValidCount);
7505 7123 : fBlockM2 += fDelta * (fValue - fBlockMean);
7506 : }
7507 : }
7508 : }
7509 : }
7510 :
7511 2330 : if (nBlockValidCount)
7512 : {
7513 : // Update the global mean and M2 (the difference of the
7514 : // square to the mean) from the values of the block
7515 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7516 2330 : const auto nNewValidCount = nValidCount + nBlockValidCount;
7517 2330 : const double dfBlockMean = static_cast<double>(fBlockMean);
7518 2330 : if (dfBlockMean != dfMean)
7519 : {
7520 1066 : const double dfBlockM2 = static_cast<double>(fBlockM2);
7521 1066 : if (nValidCount == 0)
7522 : {
7523 13 : dfMean = dfBlockMean;
7524 13 : dfM2 = dfBlockM2;
7525 : }
7526 : else
7527 : {
7528 1053 : const double dfBlockValidCount =
7529 1053 : static_cast<double>(nBlockValidCount);
7530 1053 : const double dfDelta = dfBlockMean - dfMean;
7531 1053 : const double dfNewValidCount =
7532 : static_cast<double>(nNewValidCount);
7533 1053 : dfMean +=
7534 1053 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7535 1053 : dfM2 += dfBlockM2 +
7536 1053 : dfDelta * dfDelta *
7537 1053 : static_cast<double>(nValidCount) *
7538 1053 : dfBlockValidCount / dfNewValidCount;
7539 : }
7540 : }
7541 2330 : nValidCount = nNewValidCount;
7542 : }
7543 : }
7544 :
7545 : #if (defined(__x86_64__) || defined(_M_X64))
7546 3321 : else if (bFloat64Optim)
7547 : {
7548 : const bool bHasNoData =
7549 545 : sNoDataValues.bGotNoDataValue &&
7550 263 : !std::isnan(sNoDataValues.dfNoDataValue);
7551 282 : double dfBlockMean = 0;
7552 282 : double dfBlockM2 = 0;
7553 282 : double dfBlockValidCount = 0;
7554 1633 : for (int iY = 0; iY < nYCheck; iY++)
7555 : {
7556 1351 : const int iOffset = iY * nBlockXSize;
7557 1351 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7558 : {
7559 813 : int iX = 0;
7560 813 : if (bHasNoData)
7561 : {
7562 : iX = ComputeStatisticsFloat64_SSE2<
7563 : /* bCheckMinEqMax = */ false,
7564 381 : /* bHasNoData = */ true>(
7565 381 : static_cast<const double *>(pData) + iOffset,
7566 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7567 : dfMax, dfBlockMean, dfBlockM2,
7568 : dfBlockValidCount);
7569 : }
7570 : else
7571 : {
7572 : iX = ComputeStatisticsFloat64_SSE2<
7573 : /* bCheckMinEqMax = */ false,
7574 432 : /* bHasNoData = */ false>(
7575 432 : static_cast<const double *>(pData) + iOffset,
7576 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7577 : dfMax, dfBlockMean, dfBlockM2,
7578 : dfBlockValidCount);
7579 : }
7580 1931 : for (; iX < nXCheck; iX++)
7581 : {
7582 1118 : const double dfValue = static_cast<const double *>(
7583 1118 : pData)[iOffset + iX];
7584 1625 : if (std::isnan(dfValue) ||
7585 507 : (bHasNoData &&
7586 507 : dfValue == sNoDataValues.dfNoDataValue))
7587 53 : continue;
7588 1065 : dfMin = std::min(dfMin, dfValue);
7589 1065 : dfMax = std::max(dfMax, dfValue);
7590 1065 : dfBlockValidCount += 1.0;
7591 1065 : const double dfDelta = dfValue - dfBlockMean;
7592 1065 : dfBlockMean += dfDelta / dfBlockValidCount;
7593 1065 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7594 813 : }
7595 : }
7596 : else
7597 : {
7598 538 : int iX = 0;
7599 538 : if (dfBlockValidCount == 0)
7600 : {
7601 7661 : for (; iX < nXCheck; iX++)
7602 : {
7603 7627 : const double dfValue =
7604 : static_cast<const double *>(
7605 7627 : pData)[iOffset + iX];
7606 15235 : if (std::isnan(dfValue) ||
7607 7608 : (bHasNoData &&
7608 7608 : dfValue == sNoDataValues.dfNoDataValue))
7609 7377 : continue;
7610 250 : dfMin = std::min(dfMin, dfValue);
7611 250 : dfMax = std::max(dfMax, dfValue);
7612 250 : dfBlockValidCount = 1;
7613 250 : dfBlockMean = dfValue;
7614 250 : iX++;
7615 250 : break;
7616 : }
7617 : }
7618 538 : if (bHasNoData)
7619 : {
7620 : iX = ComputeStatisticsFloat64_SSE2<
7621 : /* bCheckMinEqMax = */ true,
7622 392 : /* bHasNoData = */ true>(
7623 392 : static_cast<const double *>(pData) + iOffset,
7624 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7625 : dfMax, dfBlockMean, dfBlockM2,
7626 : dfBlockValidCount);
7627 : }
7628 : else
7629 : {
7630 : iX = ComputeStatisticsFloat64_SSE2<
7631 : /* bCheckMinEqMax = */ true,
7632 146 : /* bHasNoData = */ false>(
7633 146 : static_cast<const double *>(pData) + iOffset,
7634 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7635 : dfMax, dfBlockMean, dfBlockM2,
7636 : dfBlockValidCount);
7637 : }
7638 1081 : for (; iX < nXCheck; iX++)
7639 : {
7640 543 : const double dfValue = static_cast<const double *>(
7641 543 : pData)[iOffset + iX];
7642 1065 : if (std::isnan(dfValue) ||
7643 522 : (bHasNoData &&
7644 522 : dfValue == sNoDataValues.dfNoDataValue))
7645 140 : continue;
7646 403 : dfMin = std::min(dfMin, dfValue);
7647 403 : dfMax = std::max(dfMax, dfValue);
7648 403 : dfBlockValidCount += 1.0;
7649 403 : if (dfMin != dfMax)
7650 : {
7651 128 : const double dfDelta = dfValue - dfBlockMean;
7652 128 : dfBlockMean += dfDelta / dfBlockValidCount;
7653 128 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7654 : }
7655 : }
7656 : }
7657 : }
7658 :
7659 282 : if (dfBlockValidCount > 0)
7660 : {
7661 : // Update the global mean and M2 (the difference of the
7662 : // square to the mean) from the values of the block
7663 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7664 250 : const auto nNewValidCount =
7665 250 : nValidCount + static_cast<int>(dfBlockValidCount);
7666 250 : if (dfBlockMean != dfMean)
7667 : {
7668 237 : if (nValidCount == 0)
7669 : {
7670 11 : dfMean = dfBlockMean;
7671 11 : dfM2 = dfBlockM2;
7672 : }
7673 : else
7674 : {
7675 226 : const double dfDelta = dfBlockMean - dfMean;
7676 226 : const double dfNewValidCount =
7677 : static_cast<double>(nNewValidCount);
7678 226 : dfMean +=
7679 226 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7680 226 : dfM2 += dfBlockM2 +
7681 226 : dfDelta * dfDelta *
7682 226 : static_cast<double>(nValidCount) *
7683 226 : dfBlockValidCount / dfNewValidCount;
7684 : }
7685 : }
7686 250 : nValidCount = nNewValidCount;
7687 : }
7688 : }
7689 : #endif // (defined(__x86_64__) || defined(_M_X64))
7690 :
7691 : else
7692 : {
7693 : // This isn't the fastest way to do this, but is easier for now.
7694 8754 : for (int iY = 0; iY < nYCheck; iY++)
7695 : {
7696 5715 : if (nValidCount && dfMin != dfMax)
7697 : {
7698 212546 : for (int iX = 0; iX < nXCheck; iX++)
7699 : {
7700 209962 : const GPtrDiff_t iOffset =
7701 209962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7702 209962 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7703 9635 : continue;
7704 :
7705 200339 : bool bValid = true;
7706 : double dfValue =
7707 200339 : GetPixelValue(eDataType, bSignedByte, pData,
7708 200339 : iOffset, sNoDataValues, bValid);
7709 :
7710 200339 : if (!bValid)
7711 12 : continue;
7712 :
7713 200327 : dfMin = std::min(dfMin, dfValue);
7714 200327 : dfMax = std::max(dfMax, dfValue);
7715 :
7716 200327 : nValidCount++;
7717 200327 : const double dfDelta = dfValue - dfMean;
7718 200327 : dfMean += dfDelta / nValidCount;
7719 200327 : dfM2 += dfDelta * (dfValue - dfMean);
7720 2584 : }
7721 : }
7722 : else
7723 : {
7724 3131 : int iX = 0;
7725 3131 : if (nValidCount == 0)
7726 : {
7727 94577 : for (; iX < nXCheck; iX++)
7728 : {
7729 94520 : const GPtrDiff_t iOffset =
7730 94520 : iX +
7731 94520 : static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7732 94520 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7733 94282 : continue;
7734 :
7735 239 : bool bValid = true;
7736 239 : double dfValue = GetPixelValue(
7737 : eDataType, bSignedByte, pData, iOffset,
7738 : sNoDataValues, bValid);
7739 :
7740 239 : if (!bValid)
7741 1 : continue;
7742 :
7743 238 : dfMin = dfValue;
7744 238 : dfMax = dfValue;
7745 238 : dfMean = dfValue;
7746 238 : nValidCount = 1;
7747 238 : iX++;
7748 238 : break;
7749 : }
7750 : }
7751 227675 : for (; iX < nXCheck; iX++)
7752 : {
7753 224544 : const GPtrDiff_t iOffset =
7754 224544 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7755 224544 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7756 358 : continue;
7757 :
7758 224187 : bool bValid = true;
7759 : double dfValue =
7760 224187 : GetPixelValue(eDataType, bSignedByte, pData,
7761 224187 : iOffset, sNoDataValues, bValid);
7762 :
7763 224187 : if (!bValid)
7764 1 : continue;
7765 :
7766 224186 : dfMin = std::min(dfMin, dfValue);
7767 224186 : dfMax = std::max(dfMax, dfValue);
7768 :
7769 224186 : nValidCount++;
7770 224186 : if (dfMin != dfMax)
7771 : {
7772 2170 : const double dfDelta = dfValue - dfMean;
7773 2170 : dfMean += dfDelta / nValidCount;
7774 2170 : dfM2 += dfDelta * (dfValue - dfMean);
7775 : }
7776 : }
7777 : }
7778 : }
7779 : }
7780 :
7781 5651 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
7782 :
7783 5651 : poBlock->DropLock();
7784 :
7785 5651 : if (!pfnProgress(
7786 5651 : static_cast<double>(iSampleBlock) /
7787 5651 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
7788 : "Compute Statistics", pProgressData))
7789 : {
7790 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7791 0 : CPLFree(pabyMaskData);
7792 0 : return CE_Failure;
7793 : }
7794 : }
7795 :
7796 267 : if (bFloat32Optim)
7797 : {
7798 17 : dfMin = static_cast<double>(fMin);
7799 17 : dfMax = static_cast<double>(fMax);
7800 : }
7801 267 : CPLFree(pabyMaskData);
7802 : }
7803 :
7804 267 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7805 : {
7806 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7807 0 : return CE_Failure;
7808 : }
7809 :
7810 : /* -------------------------------------------------------------------- */
7811 : /* Save computed information. */
7812 : /* -------------------------------------------------------------------- */
7813 267 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7814 :
7815 267 : if (nValidCount > 0)
7816 : {
7817 266 : if (bApproxOK)
7818 : {
7819 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7820 : }
7821 258 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7822 : {
7823 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7824 : }
7825 266 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7826 : }
7827 : else
7828 : {
7829 1 : dfMin = 0.0;
7830 1 : dfMax = 0.0;
7831 : }
7832 :
7833 267 : SetValidPercent(nSampleCount, nValidCount);
7834 :
7835 : /* -------------------------------------------------------------------- */
7836 : /* Record results. */
7837 : /* -------------------------------------------------------------------- */
7838 267 : if (pdfMin != nullptr)
7839 264 : *pdfMin = dfMin;
7840 267 : if (pdfMax != nullptr)
7841 264 : *pdfMax = dfMax;
7842 :
7843 267 : if (pdfMean != nullptr)
7844 261 : *pdfMean = dfMean;
7845 :
7846 267 : if (pdfStdDev != nullptr)
7847 261 : *pdfStdDev = dfStdDev;
7848 :
7849 267 : if (nValidCount > 0)
7850 266 : return CE_None;
7851 :
7852 1 : ReportError(
7853 : CE_Failure, CPLE_AppDefined,
7854 : "Failed to compute statistics, no valid pixels found in sampling.");
7855 1 : return CE_Failure;
7856 : }
7857 :
7858 : /************************************************************************/
7859 : /* GDALComputeRasterStatistics() */
7860 : /************************************************************************/
7861 :
7862 : /**
7863 : * \brief Compute image statistics.
7864 : *
7865 : * @see GDALRasterBand::ComputeStatistics()
7866 : */
7867 :
7868 168 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7869 : int bApproxOK, double *pdfMin,
7870 : double *pdfMax, double *pdfMean,
7871 : double *pdfStdDev,
7872 : GDALProgressFunc pfnProgress,
7873 : void *pProgressData)
7874 :
7875 : {
7876 168 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7877 :
7878 168 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7879 :
7880 168 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7881 168 : pdfStdDev, pfnProgress, pProgressData);
7882 : }
7883 :
7884 : /************************************************************************/
7885 : /* SetStatistics() */
7886 : /************************************************************************/
7887 :
7888 : /**
7889 : * \brief Set statistics on band.
7890 : *
7891 : * This method can be used to store min/max/mean/standard deviation
7892 : * statistics on a raster band.
7893 : *
7894 : * The default implementation stores them as metadata, and will only work
7895 : * on formats that can save arbitrary metadata. This method cannot detect
7896 : * whether metadata will be properly saved and so may return CE_None even
7897 : * if the statistics will never be saved.
7898 : *
7899 : * This method is the same as the C function GDALSetRasterStatistics().
7900 : *
7901 : * @param dfMin minimum pixel value.
7902 : *
7903 : * @param dfMax maximum pixel value.
7904 : *
7905 : * @param dfMean mean (average) of all pixel values.
7906 : *
7907 : * @param dfStdDev Standard deviation of all pixel values.
7908 : *
7909 : * @return CE_None on success or CE_Failure on failure.
7910 : */
7911 :
7912 530 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7913 : double dfStdDev)
7914 :
7915 : {
7916 530 : char szValue[128] = {0};
7917 :
7918 530 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7919 530 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7920 :
7921 530 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7922 530 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7923 :
7924 530 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7925 530 : SetMetadataItem("STATISTICS_MEAN", szValue);
7926 :
7927 530 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7928 530 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7929 :
7930 530 : return CE_None;
7931 : }
7932 :
7933 : /************************************************************************/
7934 : /* GDALSetRasterStatistics() */
7935 : /************************************************************************/
7936 :
7937 : /**
7938 : * \brief Set statistics on band.
7939 : *
7940 : * @see GDALRasterBand::SetStatistics()
7941 : */
7942 :
7943 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7944 : double dfMax, double dfMean,
7945 : double dfStdDev)
7946 :
7947 : {
7948 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7949 :
7950 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7951 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7952 : }
7953 :
7954 : /************************************************************************/
7955 : /* ComputeRasterMinMax() */
7956 : /************************************************************************/
7957 :
7958 : template <class T, bool HAS_NODATA>
7959 120995 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7960 : T *pMax)
7961 : {
7962 120995 : T min0 = *pMin;
7963 120995 : T max0 = *pMax;
7964 120995 : T min1 = *pMin;
7965 120995 : T max1 = *pMax;
7966 : size_t i;
7967 215473 : for (i = 0; i + 1 < nElts; i += 2)
7968 : {
7969 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7970 : {
7971 94478 : min0 = std::min(min0, buffer[i]);
7972 94478 : max0 = std::max(max0, buffer[i]);
7973 : }
7974 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7975 : {
7976 94478 : min1 = std::min(min1, buffer[i + 1]);
7977 94478 : max1 = std::max(max1, buffer[i + 1]);
7978 : }
7979 : }
7980 120995 : T min = std::min(min0, min1);
7981 120995 : T max = std::max(max0, max1);
7982 120995 : if (i < nElts)
7983 : {
7984 119260 : if (!HAS_NODATA || buffer[i] != nodataValue)
7985 : {
7986 119280 : min = std::min(min, buffer[i]);
7987 119280 : max = std::max(max, buffer[i]);
7988 : }
7989 : }
7990 120995 : *pMin = min;
7991 120995 : *pMax = max;
7992 120995 : }
7993 :
7994 : template <GDALDataType eDataType, bool bSignedByte>
7995 : static void
7996 12305 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7997 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7998 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7999 : {
8000 12305 : double dfLocalMin = dfMin;
8001 12305 : double dfLocalMax = dfMax;
8002 :
8003 44959 : for (int iY = 0; iY < nYCheck; iY++)
8004 : {
8005 19143749 : for (int iX = 0; iX < nXCheck; iX++)
8006 : {
8007 19111163 : const GPtrDiff_t iOffset =
8008 19111163 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8009 19111163 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8010 3448532 : continue;
8011 19028200 : bool bValid = true;
8012 19028200 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8013 : iOffset, sNoDataValues, bValid);
8014 19028200 : if (!bValid)
8015 3365580 : continue;
8016 :
8017 15662589 : dfLocalMin = std::min(dfLocalMin, dfValue);
8018 15662589 : dfLocalMax = std::max(dfLocalMax, dfValue);
8019 : }
8020 : }
8021 :
8022 12305 : dfMin = dfLocalMin;
8023 12305 : dfMax = dfLocalMax;
8024 12305 : }
8025 :
8026 12305 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8027 : bool bSignedByte, int nXCheck, int nYCheck,
8028 : int nBlockXSize,
8029 : const GDALNoDataValues &sNoDataValues,
8030 : const GByte *pabyMaskData, double &dfMin,
8031 : double &dfMax)
8032 : {
8033 12305 : switch (eDataType)
8034 : {
8035 0 : case GDT_Unknown:
8036 0 : CPLAssert(false);
8037 : break;
8038 659 : case GDT_Byte:
8039 659 : if (bSignedByte)
8040 : {
8041 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
8042 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8043 : pabyMaskData, dfMin, dfMax);
8044 : }
8045 : else
8046 : {
8047 656 : ComputeMinMaxGeneric<GDT_Byte, false>(
8048 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8049 : pabyMaskData, dfMin, dfMax);
8050 : }
8051 659 : break;
8052 106 : case GDT_Int8:
8053 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8054 : nBlockXSize, sNoDataValues,
8055 : pabyMaskData, dfMin, dfMax);
8056 106 : break;
8057 968 : case GDT_UInt16:
8058 968 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8059 : nBlockXSize, sNoDataValues,
8060 : pabyMaskData, dfMin, dfMax);
8061 968 : break;
8062 1 : case GDT_Int16:
8063 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8064 : nBlockXSize, sNoDataValues,
8065 : pabyMaskData, dfMin, dfMax);
8066 1 : break;
8067 201 : case GDT_UInt32:
8068 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8069 : nBlockXSize, sNoDataValues,
8070 : pabyMaskData, dfMin, dfMax);
8071 201 : break;
8072 1089 : case GDT_Int32:
8073 1089 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8074 : nBlockXSize, sNoDataValues,
8075 : pabyMaskData, dfMin, dfMax);
8076 1089 : break;
8077 17 : case GDT_UInt64:
8078 17 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8079 : nBlockXSize, sNoDataValues,
8080 : pabyMaskData, dfMin, dfMax);
8081 17 : break;
8082 29 : case GDT_Int64:
8083 29 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8084 : nBlockXSize, sNoDataValues,
8085 : pabyMaskData, dfMin, dfMax);
8086 29 : break;
8087 0 : case GDT_Float16:
8088 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
8089 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8090 : pabyMaskData, dfMin, dfMax);
8091 0 : break;
8092 5638 : case GDT_Float32:
8093 5638 : ComputeMinMaxGeneric<GDT_Float32, false>(
8094 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8095 : pabyMaskData, dfMin, dfMax);
8096 5638 : break;
8097 3487 : case GDT_Float64:
8098 3487 : ComputeMinMaxGeneric<GDT_Float64, false>(
8099 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8100 : pabyMaskData, dfMin, dfMax);
8101 3487 : break;
8102 9 : case GDT_CInt16:
8103 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8104 : nBlockXSize, sNoDataValues,
8105 : pabyMaskData, dfMin, dfMax);
8106 9 : break;
8107 9 : case GDT_CInt32:
8108 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8109 : nBlockXSize, sNoDataValues,
8110 : pabyMaskData, dfMin, dfMax);
8111 9 : break;
8112 0 : case GDT_CFloat16:
8113 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8114 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8115 : pabyMaskData, dfMin, dfMax);
8116 0 : break;
8117 75 : case GDT_CFloat32:
8118 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8119 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8120 : pabyMaskData, dfMin, dfMax);
8121 75 : break;
8122 17 : case GDT_CFloat64:
8123 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8124 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8125 : pabyMaskData, dfMin, dfMax);
8126 17 : break;
8127 0 : case GDT_TypeCount:
8128 0 : CPLAssert(false);
8129 : break;
8130 : }
8131 12305 : }
8132 :
8133 787 : static bool ComputeMinMaxGenericIterBlocks(
8134 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8135 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8136 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8137 : double &dfMin, double &dfMax)
8138 :
8139 : {
8140 787 : GByte *pabyMaskData = nullptr;
8141 : int nBlockXSize, nBlockYSize;
8142 787 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8143 :
8144 787 : if (poMaskBand)
8145 : {
8146 : pabyMaskData =
8147 112 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8148 112 : if (!pabyMaskData)
8149 : {
8150 0 : return false;
8151 : }
8152 : }
8153 :
8154 13092 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8155 12305 : iSampleBlock += nSampleRate)
8156 : {
8157 12305 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8158 12305 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8159 :
8160 12305 : int nXCheck = 0, nYCheck = 0;
8161 12305 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8162 :
8163 18872 : if (poMaskBand &&
8164 6567 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8165 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8166 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
8167 : nBlockXSize, nullptr) != CE_None)
8168 : {
8169 0 : CPLFree(pabyMaskData);
8170 0 : return false;
8171 : }
8172 :
8173 12305 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8174 12305 : if (poBlock == nullptr)
8175 : {
8176 0 : CPLFree(pabyMaskData);
8177 0 : return false;
8178 : }
8179 :
8180 12305 : void *const pData = poBlock->GetDataRef();
8181 :
8182 12305 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8183 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8184 : dfMax);
8185 :
8186 12305 : poBlock->DropLock();
8187 : }
8188 :
8189 787 : CPLFree(pabyMaskData);
8190 787 : return true;
8191 : }
8192 :
8193 : /**
8194 : * \brief Compute the min/max values for a band.
8195 : *
8196 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8197 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8198 : * get an approximate min/max. If the band has a nodata value it will
8199 : * be excluded from the minimum and maximum.
8200 : *
8201 : * If bApprox is FALSE, then all pixels will be read and used to compute
8202 : * an exact range.
8203 : *
8204 : * This method is the same as the C function GDALComputeRasterMinMax().
8205 : *
8206 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8207 : * FALSE.
8208 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8209 : * maximum (adfMinMax[1]) are returned.
8210 : *
8211 : * @return CE_None on success or CE_Failure on failure.
8212 : */
8213 :
8214 1780 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8215 : {
8216 : /* -------------------------------------------------------------------- */
8217 : /* Does the driver already know the min/max? */
8218 : /* -------------------------------------------------------------------- */
8219 1780 : if (bApproxOK)
8220 : {
8221 23 : int bSuccessMin = FALSE;
8222 23 : int bSuccessMax = FALSE;
8223 :
8224 23 : double dfMin = GetMinimum(&bSuccessMin);
8225 23 : double dfMax = GetMaximum(&bSuccessMax);
8226 :
8227 23 : if (bSuccessMin && bSuccessMax)
8228 : {
8229 1 : adfMinMax[0] = dfMin;
8230 1 : adfMinMax[1] = dfMax;
8231 1 : return CE_None;
8232 : }
8233 : }
8234 :
8235 : /* -------------------------------------------------------------------- */
8236 : /* If we have overview bands, use them for min/max. */
8237 : /* -------------------------------------------------------------------- */
8238 : // cppcheck-suppress knownConditionTrueFalse
8239 1779 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8240 : {
8241 : GDALRasterBand *poBand =
8242 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8243 :
8244 0 : if (poBand != this)
8245 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8246 : }
8247 :
8248 : /* -------------------------------------------------------------------- */
8249 : /* Read actual data and compute minimum and maximum. */
8250 : /* -------------------------------------------------------------------- */
8251 1779 : GDALNoDataValues sNoDataValues(this, eDataType);
8252 1779 : GDALRasterBand *poMaskBand = nullptr;
8253 1779 : if (!sNoDataValues.bGotNoDataValue)
8254 : {
8255 1526 : const int l_nMaskFlags = GetMaskFlags();
8256 1638 : if (l_nMaskFlags != GMF_ALL_VALID &&
8257 112 : GetColorInterpretation() != GCI_AlphaBand)
8258 : {
8259 112 : poMaskBand = GetMaskBand();
8260 : }
8261 : }
8262 :
8263 1779 : bool bSignedByte = false;
8264 1779 : if (eDataType == GDT_Byte)
8265 : {
8266 778 : EnablePixelTypeSignedByteWarning(false);
8267 : const char *pszPixelType =
8268 778 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8269 778 : EnablePixelTypeSignedByteWarning(true);
8270 778 : bSignedByte =
8271 778 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8272 : }
8273 :
8274 : GDALRasterIOExtraArg sExtraArg;
8275 1779 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8276 :
8277 3558 : GUInt32 nMin = (eDataType == GDT_Byte)
8278 1779 : ? 255
8279 : : 65535; // used for GByte & GUInt16 cases
8280 1779 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8281 1779 : GInt16 nMinInt16 =
8282 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8283 1779 : GInt16 nMaxInt16 =
8284 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8285 1779 : double dfMin =
8286 : std::numeric_limits<double>::infinity(); // used for generic code path
8287 1779 : double dfMax =
8288 : -std::numeric_limits<double>::infinity(); // used for generic code path
8289 1779 : const bool bUseOptimizedPath =
8290 2698 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
8291 919 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8292 :
8293 : const auto ComputeMinMaxForBlock =
8294 20943 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8295 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8296 243461 : int nYCheck)
8297 : {
8298 20943 : if (eDataType == GDT_Byte && !bSignedByte)
8299 : {
8300 : const bool bHasNoData =
8301 11561 : sNoDataValues.bGotNoDataValue &&
8302 29664 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8303 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8304 11561 : sNoDataValues.dfNoDataValue;
8305 18103 : const GUInt32 nNoDataValue =
8306 18103 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8307 : : 0;
8308 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8309 : ComputeStatisticsInternal<GByte,
8310 : /* COMPUTE_OTHER_STATS = */ false>::
8311 18103 : f(nXCheck, nBufferWidth, nYCheck,
8312 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8313 18103 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8314 : }
8315 2840 : else if (eDataType == GDT_UInt16)
8316 : {
8317 : const bool bHasNoData =
8318 83 : sNoDataValues.bGotNoDataValue &&
8319 1494 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8320 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8321 83 : sNoDataValues.dfNoDataValue;
8322 1411 : const GUInt32 nNoDataValue =
8323 1411 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8324 : : 0;
8325 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8326 : ComputeStatisticsInternal<GUInt16,
8327 : /* COMPUTE_OTHER_STATS = */ false>::
8328 1411 : f(nXCheck, nBufferWidth, nYCheck,
8329 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8330 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8331 : }
8332 1429 : else if (eDataType == GDT_Int16)
8333 : {
8334 : const bool bHasNoData =
8335 1254 : sNoDataValues.bGotNoDataValue &&
8336 2683 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8337 1254 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8338 1254 : sNoDataValues.dfNoDataValue;
8339 1429 : if (bHasNoData)
8340 : {
8341 1254 : const int16_t nNoDataValue =
8342 1254 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8343 120957 : for (int iY = 0; iY < nYCheck; iY++)
8344 : {
8345 119703 : ComputeMinMax<int16_t, true>(
8346 119703 : static_cast<const int16_t *>(pData) +
8347 119703 : static_cast<size_t>(iY) * nBufferWidth,
8348 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8349 : }
8350 : }
8351 : else
8352 : {
8353 1467 : for (int iY = 0; iY < nYCheck; iY++)
8354 : {
8355 1292 : ComputeMinMax<int16_t, false>(
8356 1292 : static_cast<const int16_t *>(pData) +
8357 1292 : static_cast<size_t>(iY) * nBufferWidth,
8358 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8359 : }
8360 : }
8361 : }
8362 20943 : };
8363 :
8364 1779 : if (bApproxOK && HasArbitraryOverviews())
8365 : {
8366 : /* --------------------------------------------------------------------
8367 : */
8368 : /* Figure out how much the image should be reduced to get an */
8369 : /* approximate value. */
8370 : /* --------------------------------------------------------------------
8371 : */
8372 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8373 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8374 :
8375 0 : int nXReduced = nRasterXSize;
8376 0 : int nYReduced = nRasterYSize;
8377 0 : if (dfReduction > 1.0)
8378 : {
8379 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8380 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8381 :
8382 : // Catch the case of huge resizing ratios here
8383 0 : if (nXReduced == 0)
8384 0 : nXReduced = 1;
8385 0 : if (nYReduced == 0)
8386 0 : nYReduced = 1;
8387 : }
8388 :
8389 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8390 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8391 :
8392 : const CPLErr eErr =
8393 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8394 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8395 0 : if (eErr != CE_None)
8396 : {
8397 0 : CPLFree(pData);
8398 0 : return eErr;
8399 : }
8400 :
8401 0 : GByte *pabyMaskData = nullptr;
8402 0 : if (poMaskBand)
8403 : {
8404 : pabyMaskData =
8405 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8406 0 : if (!pabyMaskData)
8407 : {
8408 0 : CPLFree(pData);
8409 0 : return CE_Failure;
8410 : }
8411 :
8412 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8413 : pabyMaskData, nXReduced, nYReduced,
8414 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
8415 : {
8416 0 : CPLFree(pData);
8417 0 : CPLFree(pabyMaskData);
8418 0 : return CE_Failure;
8419 : }
8420 : }
8421 :
8422 0 : if (bUseOptimizedPath)
8423 : {
8424 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8425 : }
8426 : else
8427 : {
8428 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8429 : nYReduced, nXReduced, sNoDataValues,
8430 : pabyMaskData, dfMin, dfMax);
8431 : }
8432 :
8433 0 : CPLFree(pData);
8434 0 : CPLFree(pabyMaskData);
8435 : }
8436 :
8437 : else // No arbitrary overviews
8438 : {
8439 1779 : if (!InitBlockInfo())
8440 0 : return CE_Failure;
8441 :
8442 : /* --------------------------------------------------------------------
8443 : */
8444 : /* Figure out the ratio of blocks we will read to get an */
8445 : /* approximate value. */
8446 : /* --------------------------------------------------------------------
8447 : */
8448 1779 : int nSampleRate = 1;
8449 :
8450 1779 : if (bApproxOK)
8451 : {
8452 22 : nSampleRate = static_cast<int>(std::max(
8453 44 : 1.0,
8454 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8455 : // We want to avoid probing only the first column of blocks for
8456 : // a square shaped raster, because it is not unlikely that it may
8457 : // be padding only (#6378).
8458 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8459 0 : nSampleRate += 1;
8460 : }
8461 :
8462 1779 : if (bUseOptimizedPath)
8463 : {
8464 992 : for (GIntBig iSampleBlock = 0;
8465 21861 : iSampleBlock <
8466 21861 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8467 20869 : iSampleBlock += nSampleRate)
8468 : {
8469 20945 : const int iYBlock =
8470 20945 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8471 20945 : const int iXBlock =
8472 20945 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8473 :
8474 20945 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8475 20945 : if (poBlock == nullptr)
8476 2 : return CE_Failure;
8477 :
8478 20943 : void *const pData = poBlock->GetDataRef();
8479 :
8480 20943 : int nXCheck = 0, nYCheck = 0;
8481 20943 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8482 :
8483 20943 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8484 :
8485 20943 : poBlock->DropLock();
8486 :
8487 20943 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
8488 4110 : nMax == 255)
8489 74 : break;
8490 : }
8491 : }
8492 : else
8493 : {
8494 787 : const GIntBig nTotalBlocks =
8495 787 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8496 787 : if (!ComputeMinMaxGenericIterBlocks(
8497 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8498 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8499 : {
8500 0 : return CE_Failure;
8501 : }
8502 : }
8503 : }
8504 :
8505 1777 : if (bUseOptimizedPath)
8506 : {
8507 990 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
8508 : {
8509 885 : dfMin = nMin;
8510 885 : dfMax = nMax;
8511 : }
8512 105 : else if (eDataType == GDT_Int16)
8513 : {
8514 105 : dfMin = nMinInt16;
8515 105 : dfMax = nMaxInt16;
8516 : }
8517 : }
8518 :
8519 1777 : if (dfMin > dfMax)
8520 : {
8521 9 : adfMinMax[0] = 0;
8522 9 : adfMinMax[1] = 0;
8523 9 : ReportError(
8524 : CE_Failure, CPLE_AppDefined,
8525 : "Failed to compute min/max, no valid pixels found in sampling.");
8526 9 : return CE_Failure;
8527 : }
8528 :
8529 1768 : adfMinMax[0] = dfMin;
8530 1768 : adfMinMax[1] = dfMax;
8531 :
8532 1768 : return CE_None;
8533 : }
8534 :
8535 : /************************************************************************/
8536 : /* GDALComputeRasterMinMax() */
8537 : /************************************************************************/
8538 :
8539 : /**
8540 : * \brief Compute the min/max values for a band.
8541 : *
8542 : * @see GDALRasterBand::ComputeRasterMinMax()
8543 : *
8544 : * @note Prior to GDAL 3.6, this function returned void
8545 : */
8546 :
8547 1629 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8548 : double adfMinMax[2])
8549 :
8550 : {
8551 1629 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8552 :
8553 1629 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8554 1629 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8555 : }
8556 :
8557 : /************************************************************************/
8558 : /* ComputeRasterMinMaxLocation() */
8559 : /************************************************************************/
8560 :
8561 : /**
8562 : * \brief Compute the min/max values for a band, and their location.
8563 : *
8564 : * Pixels whose value matches the nodata value or are masked by the mask
8565 : * band are ignored.
8566 : *
8567 : * If the minimum or maximum value is hit in several locations, it is not
8568 : * specified which one will be returned.
8569 : *
8570 : * @param[out] pdfMin Pointer to the minimum value.
8571 : * @param[out] pdfMax Pointer to the maximum value.
8572 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8573 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8574 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8575 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8576 : *
8577 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8578 : * CE_Failure in case of error.
8579 : *
8580 : * @since GDAL 3.11
8581 : */
8582 :
8583 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8584 : double *pdfMax, int *pnMinX,
8585 : int *pnMinY, int *pnMaxX,
8586 : int *pnMaxY)
8587 : {
8588 8 : int nMinX = -1;
8589 8 : int nMinY = -1;
8590 8 : int nMaxX = -1;
8591 8 : int nMaxY = -1;
8592 8 : double dfMin = std::numeric_limits<double>::infinity();
8593 8 : double dfMax = -std::numeric_limits<double>::infinity();
8594 8 : if (pdfMin)
8595 5 : *pdfMin = dfMin;
8596 8 : if (pdfMax)
8597 5 : *pdfMax = dfMax;
8598 8 : if (pnMinX)
8599 6 : *pnMinX = nMinX;
8600 8 : if (pnMinY)
8601 6 : *pnMinY = nMinY;
8602 8 : if (pnMaxX)
8603 6 : *pnMaxX = nMaxX;
8604 8 : if (pnMaxY)
8605 6 : *pnMaxY = nMaxY;
8606 :
8607 8 : if (GDALDataTypeIsComplex(eDataType))
8608 : {
8609 0 : CPLError(CE_Failure, CPLE_NotSupported,
8610 : "Complex data type not supported");
8611 0 : return CE_Failure;
8612 : }
8613 :
8614 8 : if (!InitBlockInfo())
8615 0 : return CE_Failure;
8616 :
8617 8 : GDALNoDataValues sNoDataValues(this, eDataType);
8618 8 : GDALRasterBand *poMaskBand = nullptr;
8619 8 : if (!sNoDataValues.bGotNoDataValue)
8620 : {
8621 8 : const int l_nMaskFlags = GetMaskFlags();
8622 9 : if (l_nMaskFlags != GMF_ALL_VALID &&
8623 1 : GetColorInterpretation() != GCI_AlphaBand)
8624 : {
8625 1 : poMaskBand = GetMaskBand();
8626 : }
8627 : }
8628 :
8629 8 : bool bSignedByte = false;
8630 8 : if (eDataType == GDT_Byte)
8631 : {
8632 7 : EnablePixelTypeSignedByteWarning(false);
8633 : const char *pszPixelType =
8634 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8635 7 : EnablePixelTypeSignedByteWarning(true);
8636 7 : bSignedByte =
8637 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8638 : }
8639 :
8640 8 : GByte *pabyMaskData = nullptr;
8641 8 : if (poMaskBand)
8642 : {
8643 : pabyMaskData =
8644 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8645 1 : if (!pabyMaskData)
8646 : {
8647 0 : return CE_Failure;
8648 : }
8649 : }
8650 :
8651 8 : const GIntBig nTotalBlocks =
8652 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8653 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8654 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8655 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8656 : {
8657 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8658 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8659 :
8660 11 : int nXCheck = 0, nYCheck = 0;
8661 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8662 :
8663 13 : if (poMaskBand &&
8664 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8665 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8666 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
8667 2 : nBlockXSize, nullptr) != CE_None)
8668 : {
8669 0 : CPLFree(pabyMaskData);
8670 0 : return CE_Failure;
8671 : }
8672 :
8673 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8674 11 : if (poBlock == nullptr)
8675 : {
8676 0 : CPLFree(pabyMaskData);
8677 0 : return CE_Failure;
8678 : }
8679 :
8680 11 : void *const pData = poBlock->GetDataRef();
8681 :
8682 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8683 : {
8684 4 : for (int iY = 0; iY < nYCheck; ++iY)
8685 : {
8686 6 : for (int iX = 0; iX < nXCheck; ++iX)
8687 : {
8688 4 : const GPtrDiff_t iOffset =
8689 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8690 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8691 2 : continue;
8692 2 : bool bValid = true;
8693 : double dfValue =
8694 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8695 : sNoDataValues, bValid);
8696 2 : if (!bValid)
8697 0 : continue;
8698 2 : if (dfValue < dfMin)
8699 : {
8700 2 : dfMin = dfValue;
8701 2 : nMinX = iXBlock * nBlockXSize + iX;
8702 2 : nMinY = iYBlock * nBlockYSize + iY;
8703 : }
8704 2 : if (dfValue > dfMax)
8705 : {
8706 1 : dfMax = dfValue;
8707 1 : nMaxX = iXBlock * nBlockXSize + iX;
8708 1 : nMaxY = iYBlock * nBlockYSize + iY;
8709 : }
8710 : }
8711 2 : }
8712 : }
8713 : else
8714 : {
8715 9 : size_t pos_min = 0;
8716 9 : size_t pos_max = 0;
8717 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8718 9 : if (bNeedsMin && bNeedsMax)
8719 : {
8720 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
8721 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8722 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8723 10 : sNoDataValues.dfNoDataValue);
8724 : }
8725 4 : else if (bNeedsMin)
8726 : {
8727 1 : pos_min = gdal::min_element(
8728 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8729 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8730 : sNoDataValues.dfNoDataValue);
8731 : }
8732 3 : else if (bNeedsMax)
8733 : {
8734 2 : pos_max = gdal::max_element(
8735 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8736 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8737 : sNoDataValues.dfNoDataValue);
8738 : }
8739 :
8740 9 : if (bNeedsMin)
8741 : {
8742 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8743 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8744 6 : bool bValid = true;
8745 : const double dfMinValueBlock =
8746 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
8747 : sNoDataValues, bValid);
8748 6 : if (bValid && dfMinValueBlock < dfMin)
8749 : {
8750 5 : dfMin = dfMinValueBlock;
8751 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
8752 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
8753 : }
8754 : }
8755 :
8756 9 : if (bNeedsMax)
8757 : {
8758 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
8759 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
8760 7 : bool bValid = true;
8761 : const double dfMaxValueBlock =
8762 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
8763 : sNoDataValues, bValid);
8764 7 : if (bValid && dfMaxValueBlock > dfMax)
8765 : {
8766 5 : dfMax = dfMaxValueBlock;
8767 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
8768 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
8769 : }
8770 : }
8771 : }
8772 :
8773 11 : poBlock->DropLock();
8774 :
8775 11 : if (eDataType == GDT_Byte)
8776 : {
8777 10 : if (bNeedsMin && dfMin == 0)
8778 : {
8779 1 : bNeedsMin = false;
8780 : }
8781 10 : if (bNeedsMax && dfMax == 255)
8782 : {
8783 4 : bNeedsMax = false;
8784 : }
8785 10 : if (!bNeedsMin && !bNeedsMax)
8786 : {
8787 3 : break;
8788 : }
8789 : }
8790 : }
8791 :
8792 8 : CPLFree(pabyMaskData);
8793 :
8794 8 : if (pdfMin)
8795 5 : *pdfMin = dfMin;
8796 8 : if (pdfMax)
8797 5 : *pdfMax = dfMax;
8798 8 : if (pnMinX)
8799 6 : *pnMinX = nMinX;
8800 8 : if (pnMinY)
8801 6 : *pnMinY = nMinY;
8802 8 : if (pnMaxX)
8803 6 : *pnMaxX = nMaxX;
8804 8 : if (pnMaxY)
8805 6 : *pnMaxY = nMaxY;
8806 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8807 8 : : CE_None;
8808 : }
8809 :
8810 : /************************************************************************/
8811 : /* GDALComputeRasterMinMaxLocation() */
8812 : /************************************************************************/
8813 :
8814 : /**
8815 : * \brief Compute the min/max values for a band, and their location.
8816 : *
8817 : * @see GDALRasterBand::ComputeRasterMinMax()
8818 : * @since GDAL 3.11
8819 : */
8820 :
8821 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8822 : double *pdfMax, int *pnMinX, int *pnMinY,
8823 : int *pnMaxX, int *pnMaxY)
8824 :
8825 : {
8826 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8827 :
8828 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8829 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8830 6 : pnMaxX, pnMaxY);
8831 : }
8832 :
8833 : /************************************************************************/
8834 : /* SetDefaultHistogram() */
8835 : /************************************************************************/
8836 :
8837 : /* FIXME : add proper documentation */
8838 : /**
8839 : * \brief Set default histogram.
8840 : *
8841 : * This method is the same as the C function GDALSetDefaultHistogram() and
8842 : * GDALSetDefaultHistogramEx()
8843 : */
8844 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8845 : double /* dfMax */,
8846 : int /* nBuckets */,
8847 : GUIntBig * /* panHistogram */)
8848 :
8849 : {
8850 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8851 0 : ReportError(CE_Failure, CPLE_NotSupported,
8852 : "SetDefaultHistogram() not implemented for this format.");
8853 :
8854 0 : return CE_Failure;
8855 : }
8856 :
8857 : /************************************************************************/
8858 : /* GDALSetDefaultHistogram() */
8859 : /************************************************************************/
8860 :
8861 : /**
8862 : * \brief Set default histogram.
8863 : *
8864 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8865 : * 2 billion.
8866 : *
8867 : * @see GDALRasterBand::SetDefaultHistogram()
8868 : * @see GDALSetRasterHistogramEx()
8869 : */
8870 :
8871 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8872 : double dfMax, int nBuckets,
8873 : int *panHistogram)
8874 :
8875 : {
8876 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8877 :
8878 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8879 :
8880 : GUIntBig *panHistogramTemp =
8881 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8882 0 : if (panHistogramTemp == nullptr)
8883 : {
8884 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8885 : "Out of memory in GDALSetDefaultHistogram().");
8886 0 : return CE_Failure;
8887 : }
8888 :
8889 0 : for (int i = 0; i < nBuckets; ++i)
8890 : {
8891 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8892 : }
8893 :
8894 : const CPLErr eErr =
8895 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8896 :
8897 0 : CPLFree(panHistogramTemp);
8898 :
8899 0 : return eErr;
8900 : }
8901 :
8902 : /************************************************************************/
8903 : /* GDALSetDefaultHistogramEx() */
8904 : /************************************************************************/
8905 :
8906 : /**
8907 : * \brief Set default histogram.
8908 : *
8909 : * @see GDALRasterBand::SetDefaultHistogram()
8910 : *
8911 : */
8912 :
8913 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8914 : double dfMin, double dfMax,
8915 : int nBuckets,
8916 : GUIntBig *panHistogram)
8917 :
8918 : {
8919 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8920 :
8921 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8922 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8923 : }
8924 :
8925 : /************************************************************************/
8926 : /* GetDefaultRAT() */
8927 : /************************************************************************/
8928 :
8929 : /**
8930 : * \brief Fetch default Raster Attribute Table.
8931 : *
8932 : * A RAT will be returned if there is a default one associated with the
8933 : * band, otherwise NULL is returned. The returned RAT is owned by the
8934 : * band and should not be deleted by the application.
8935 : *
8936 : * This method is the same as the C function GDALGetDefaultRAT().
8937 : *
8938 : * @return NULL, or a pointer to an internal RAT owned by the band.
8939 : */
8940 :
8941 180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8942 :
8943 : {
8944 180 : return nullptr;
8945 : }
8946 :
8947 : /************************************************************************/
8948 : /* GDALGetDefaultRAT() */
8949 : /************************************************************************/
8950 :
8951 : /**
8952 : * \brief Fetch default Raster Attribute Table.
8953 : *
8954 : * @see GDALRasterBand::GetDefaultRAT()
8955 : */
8956 :
8957 1147 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8958 :
8959 : {
8960 1147 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8961 :
8962 1147 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8963 1147 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8964 : }
8965 :
8966 : /************************************************************************/
8967 : /* SetDefaultRAT() */
8968 : /************************************************************************/
8969 :
8970 : /**
8971 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8972 : * \brief Set default Raster Attribute Table.
8973 : *
8974 : * Associates a default RAT with the band. If not implemented for the
8975 : * format a CPLE_NotSupported error will be issued. If successful a copy
8976 : * of the RAT is made, the original remains owned by the caller.
8977 : *
8978 : * This method is the same as the C function GDALSetDefaultRAT().
8979 : *
8980 : * @param poRAT the RAT to assign to the band.
8981 : *
8982 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8983 : * failing.
8984 : */
8985 :
8986 : /**/
8987 : /**/
8988 :
8989 : CPLErr
8990 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8991 : {
8992 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8993 : {
8994 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8995 0 : ReportError(CE_Failure, CPLE_NotSupported,
8996 : "SetDefaultRAT() not implemented for this format.");
8997 0 : CPLPopErrorHandler();
8998 : }
8999 0 : return CE_Failure;
9000 : }
9001 :
9002 : /************************************************************************/
9003 : /* GDALSetDefaultRAT() */
9004 : /************************************************************************/
9005 :
9006 : /**
9007 : * \brief Set default Raster Attribute Table.
9008 : *
9009 : * @see GDALRasterBand::GDALSetDefaultRAT()
9010 : */
9011 :
9012 25 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9013 : GDALRasterAttributeTableH hRAT)
9014 :
9015 : {
9016 25 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9017 :
9018 25 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9019 :
9020 25 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9021 : }
9022 :
9023 : /************************************************************************/
9024 : /* GetMaskBand() */
9025 : /************************************************************************/
9026 :
9027 : /**
9028 : * \brief Return the mask band associated with the band.
9029 : *
9030 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9031 : * that returns one of four default implementations :
9032 : * <ul>
9033 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9034 : * </li>
9035 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9036 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9037 : * GMF_NODATA | GMF_PER_DATASET.
9038 : * </li>
9039 : * <li>If the band has a nodata value set, an instance of the new
9040 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9041 : * GMF_NODATA.
9042 : * </li>
9043 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9044 : * to apply to this band (specific rules yet to be determined) and that is of
9045 : * type GDT_Byte then that alpha band will be returned, and the flags
9046 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9047 : * </li>
9048 : * <li>If neither of the above apply, an instance of the new
9049 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9050 : * pixels. The null flags will return GMF_ALL_VALID.
9051 : * </li>
9052 : * </ul>
9053 : *
9054 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9055 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9056 : *
9057 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9058 : * dataset, with the same name as the main dataset and suffixed with .msk,
9059 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9060 : * main dataset.
9061 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9062 : * level, where xx matches the band number of a band of the main dataset. The
9063 : * value of those items is a combination of the flags GMF_ALL_VALID,
9064 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9065 : * a band, then the other rules explained above will be used to generate a
9066 : * on-the-fly mask band.
9067 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9068 : *
9069 : * This method is the same as the C function GDALGetMaskBand().
9070 : *
9071 : * @return a valid mask band.
9072 : *
9073 : *
9074 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9075 : *
9076 : */
9077 810236 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9078 :
9079 : {
9080 396439 : const auto HasNoData = [this]()
9081 : {
9082 131825 : int bHaveNoDataRaw = FALSE;
9083 131825 : bool bHaveNoData = false;
9084 131825 : if (eDataType == GDT_Int64)
9085 : {
9086 203 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
9087 203 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9088 : }
9089 131622 : else if (eDataType == GDT_UInt64)
9090 : {
9091 151 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9092 151 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9093 : }
9094 : else
9095 : {
9096 131471 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
9097 131471 : if (bHaveNoDataRaw &&
9098 131471 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9099 : {
9100 1122 : bHaveNoData = true;
9101 : }
9102 : }
9103 131824 : return bHaveNoData;
9104 810236 : };
9105 :
9106 810236 : if (poMask != nullptr)
9107 : {
9108 711896 : if (poMask.IsOwned())
9109 : {
9110 332343 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9111 : {
9112 33565 : if (HasNoData())
9113 : {
9114 9 : InvalidateMaskBand();
9115 : }
9116 : }
9117 299550 : else if (auto poNoDataMaskBand =
9118 299170 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9119 : {
9120 394 : int bHaveNoDataRaw = FALSE;
9121 394 : bool bIsSame = false;
9122 394 : if (eDataType == GDT_Int64)
9123 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9124 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9125 10 : bHaveNoDataRaw;
9126 377 : else if (eDataType == GDT_UInt64)
9127 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9128 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9129 10 : bHaveNoDataRaw;
9130 : else
9131 : {
9132 : const double dfNoDataValue =
9133 360 : GetNoDataValue(&bHaveNoDataRaw);
9134 360 : if (bHaveNoDataRaw)
9135 : {
9136 357 : bIsSame =
9137 357 : std::isnan(dfNoDataValue)
9138 357 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9139 322 : : poNoDataMaskBand->m_dfNoDataValue ==
9140 : dfNoDataValue;
9141 : }
9142 : }
9143 394 : if (!bIsSame)
9144 23 : InvalidateMaskBand();
9145 : }
9146 : }
9147 :
9148 712952 : if (poMask)
9149 712537 : return poMask.get();
9150 : }
9151 :
9152 : /* -------------------------------------------------------------------- */
9153 : /* Check for a mask in a .msk file. */
9154 : /* -------------------------------------------------------------------- */
9155 98375 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9156 : {
9157 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9158 47 : if (poMask != nullptr)
9159 : {
9160 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9161 45 : return poMask.get();
9162 : }
9163 : }
9164 :
9165 : /* -------------------------------------------------------------------- */
9166 : /* Check for NODATA_VALUES metadata. */
9167 : /* -------------------------------------------------------------------- */
9168 98330 : if (poDS != nullptr)
9169 : {
9170 : const char *pszGDALNoDataValues =
9171 98313 : poDS->GetMetadataItem("NODATA_VALUES");
9172 98314 : if (pszGDALNoDataValues != nullptr)
9173 : {
9174 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9175 : pszGDALNoDataValues, " ", FALSE, FALSE);
9176 :
9177 : // Make sure we have as many values as bands.
9178 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9179 68 : poDS->GetRasterCount() != 0)
9180 : {
9181 : // Make sure that all bands have the same data type
9182 : // This is clearly not a fundamental condition, just a
9183 : // condition to make implementation easier.
9184 68 : GDALDataType eDT = GDT_Unknown;
9185 68 : int i = 0; // Used after for.
9186 270 : for (; i < poDS->GetRasterCount(); ++i)
9187 : {
9188 202 : if (i == 0)
9189 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9190 134 : else if (eDT !=
9191 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9192 : {
9193 0 : break;
9194 : }
9195 : }
9196 68 : if (i == poDS->GetRasterCount())
9197 : {
9198 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9199 : try
9200 : {
9201 68 : poMask.reset(
9202 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9203 : }
9204 0 : catch (const std::bad_alloc &)
9205 : {
9206 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9207 0 : poMask.reset();
9208 : }
9209 68 : CSLDestroy(papszGDALNoDataValues);
9210 68 : return poMask.get();
9211 : }
9212 : else
9213 : {
9214 0 : ReportError(CE_Warning, CPLE_AppDefined,
9215 : "All bands should have the same type in "
9216 : "order the NODATA_VALUES metadata item "
9217 : "to be used as a mask.");
9218 : }
9219 : }
9220 : else
9221 : {
9222 0 : ReportError(
9223 : CE_Warning, CPLE_AppDefined,
9224 : "NODATA_VALUES metadata item doesn't have the same number "
9225 : "of values as the number of bands. "
9226 : "Ignoring it for mask.");
9227 : }
9228 :
9229 0 : CSLDestroy(papszGDALNoDataValues);
9230 : }
9231 : }
9232 :
9233 : /* -------------------------------------------------------------------- */
9234 : /* Check for nodata case. */
9235 : /* -------------------------------------------------------------------- */
9236 98263 : if (HasNoData())
9237 : {
9238 1148 : nMaskFlags = GMF_NODATA;
9239 : try
9240 : {
9241 1148 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9242 : }
9243 0 : catch (const std::bad_alloc &)
9244 : {
9245 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9246 0 : poMask.reset();
9247 : }
9248 1148 : return poMask.get();
9249 : }
9250 :
9251 : /* -------------------------------------------------------------------- */
9252 : /* Check for alpha case. */
9253 : /* -------------------------------------------------------------------- */
9254 97099 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9255 194812 : this == poDS->GetRasterBand(1) &&
9256 599 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9257 : {
9258 231 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
9259 : {
9260 187 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9261 187 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9262 187 : return poMask.get();
9263 : }
9264 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9265 : {
9266 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9267 : try
9268 : {
9269 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9270 46 : poDS->GetRasterBand(2)));
9271 : }
9272 0 : catch (const std::bad_alloc &)
9273 : {
9274 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9275 0 : poMask.reset();
9276 : }
9277 23 : return poMask.get();
9278 : }
9279 : }
9280 :
9281 96889 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9282 3099 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9283 194520 : this == poDS->GetRasterBand(3)) &&
9284 2421 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9285 : {
9286 1546 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
9287 : {
9288 1490 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9289 1490 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9290 1490 : return poMask.get();
9291 : }
9292 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9293 : {
9294 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9295 : try
9296 : {
9297 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9298 84 : poDS->GetRasterBand(4)));
9299 : }
9300 0 : catch (const std::bad_alloc &)
9301 : {
9302 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9303 0 : poMask.reset();
9304 : }
9305 42 : return poMask.get();
9306 : }
9307 : }
9308 :
9309 : /* -------------------------------------------------------------------- */
9310 : /* Fallback to all valid case. */
9311 : /* -------------------------------------------------------------------- */
9312 95372 : nMaskFlags = GMF_ALL_VALID;
9313 : try
9314 : {
9315 95372 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9316 : }
9317 0 : catch (const std::bad_alloc &)
9318 : {
9319 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9320 0 : poMask.reset();
9321 : }
9322 :
9323 95371 : return poMask.get();
9324 : }
9325 :
9326 : /************************************************************************/
9327 : /* GDALGetMaskBand() */
9328 : /************************************************************************/
9329 :
9330 : /**
9331 : * \brief Return the mask band associated with the band.
9332 : *
9333 : * @see GDALRasterBand::GetMaskBand()
9334 : */
9335 :
9336 11042 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9337 :
9338 : {
9339 11042 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9340 :
9341 11042 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9342 11042 : return poBand->GetMaskBand();
9343 : }
9344 :
9345 : /************************************************************************/
9346 : /* GetMaskFlags() */
9347 : /************************************************************************/
9348 :
9349 : /**
9350 : * \brief Return the status flags of the mask band associated with the band.
9351 : *
9352 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9353 : * the following available definitions that may be extended in the future:
9354 : * <ul>
9355 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9356 : * 255. When used this will normally be the only flag set.
9357 : * </li>
9358 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9359 : * dataset.
9360 : * </li>
9361 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9362 : * and may have values other than 0 and 255.
9363 : * </li>
9364 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9365 : * nodata values. (mutually exclusive of GMF_ALPHA)
9366 : * </li>
9367 : * </ul>
9368 : *
9369 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9370 : * that returns one of four default implementations:
9371 : * <ul>
9372 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9373 : * </li>
9374 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9375 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9376 : * GMF_NODATA | GMF_PER_DATASET.
9377 : * </li>
9378 : * <li>If the band has a nodata value set, an instance of the new
9379 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9380 : * GMF_NODATA.
9381 : * </li>
9382 : * <li>If there is no nodata value, but the dataset has an alpha band that
9383 : * seems to apply to this band (specific rules yet to be determined) and that is
9384 : * of type GDT_Byte then that alpha band will be returned, and the flags
9385 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9386 : * </li>
9387 : * <li>If neither of the above apply, an instance of the new
9388 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9389 : * pixels. The null flags will return GMF_ALL_VALID.
9390 : * </li>
9391 : * </ul>
9392 : *
9393 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9394 : * dataset, with the same name as the main dataset and suffixed with .msk,
9395 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9396 : * main dataset.
9397 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9398 : * level, where xx matches the band number of a band of the main dataset. The
9399 : * value of those items is a combination of the flags GMF_ALL_VALID,
9400 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9401 : * a band, then the other rules explained above will be used to generate a
9402 : * on-the-fly mask band.
9403 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9404 : *
9405 : * This method is the same as the C function GDALGetMaskFlags().
9406 : *
9407 : *
9408 : * @return a valid mask band.
9409 : *
9410 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9411 : *
9412 : */
9413 156727 : int GDALRasterBand::GetMaskFlags()
9414 :
9415 : {
9416 : // If we don't have a band yet, force this now so that the masks value
9417 : // will be initialized.
9418 :
9419 156727 : if (poMask == nullptr)
9420 96655 : GetMaskBand();
9421 :
9422 156721 : return nMaskFlags;
9423 : }
9424 :
9425 : /************************************************************************/
9426 : /* GDALGetMaskFlags() */
9427 : /************************************************************************/
9428 :
9429 : /**
9430 : * \brief Return the status flags of the mask band associated with the band.
9431 : *
9432 : * @see GDALRasterBand::GetMaskFlags()
9433 : */
9434 :
9435 8740 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9436 :
9437 : {
9438 8740 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9439 :
9440 8740 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9441 8740 : return poBand->GetMaskFlags();
9442 : }
9443 :
9444 : /************************************************************************/
9445 : /* InvalidateMaskBand() */
9446 : /************************************************************************/
9447 :
9448 : //! @cond Doxygen_Suppress
9449 1848850 : void GDALRasterBand::InvalidateMaskBand()
9450 : {
9451 1848850 : poMask.reset();
9452 1848840 : nMaskFlags = 0;
9453 1848840 : }
9454 :
9455 : //! @endcond
9456 :
9457 : /************************************************************************/
9458 : /* CreateMaskBand() */
9459 : /************************************************************************/
9460 :
9461 : /**
9462 : * \brief Adds a mask band to the current band
9463 : *
9464 : * The default implementation of the CreateMaskBand() method is implemented
9465 : * based on similar rules to the .ovr handling implemented using the
9466 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9467 : * be created with the same basename as the original file, and it will have
9468 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9469 : * The mask images will be deflate compressed tiled images with the same
9470 : * block size as the original image if possible.
9471 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9472 : * level, where xx matches the band number of a band of the main dataset. The
9473 : * value of those items will be the one of the nFlagsIn parameter.
9474 : *
9475 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9476 : * it might be invalidated by CreateMaskBand(). So you have to call
9477 : * GetMaskBand() again.
9478 : *
9479 : * This method is the same as the C function GDALCreateMaskBand().
9480 : *
9481 : *
9482 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9483 : *
9484 : * @return CE_None on success or CE_Failure on an error.
9485 : *
9486 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9487 : * @see GDALDataset::CreateMaskBand()
9488 : *
9489 : */
9490 :
9491 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9492 :
9493 : {
9494 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9495 : {
9496 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9497 10 : if (eErr != CE_None)
9498 1 : return eErr;
9499 :
9500 9 : InvalidateMaskBand();
9501 :
9502 9 : return CE_None;
9503 : }
9504 :
9505 0 : ReportError(CE_Failure, CPLE_NotSupported,
9506 : "CreateMaskBand() not supported for this band.");
9507 :
9508 0 : return CE_Failure;
9509 : }
9510 :
9511 : /************************************************************************/
9512 : /* GDALCreateMaskBand() */
9513 : /************************************************************************/
9514 :
9515 : /**
9516 : * \brief Adds a mask band to the current band
9517 : *
9518 : * @see GDALRasterBand::CreateMaskBand()
9519 : */
9520 :
9521 34 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9522 :
9523 : {
9524 34 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9525 :
9526 34 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9527 34 : return poBand->CreateMaskBand(nFlags);
9528 : }
9529 :
9530 : /************************************************************************/
9531 : /* IsMaskBand() */
9532 : /************************************************************************/
9533 :
9534 : /**
9535 : * \brief Returns whether a band is a mask band.
9536 : *
9537 : * Mask band must be understood in the broad term: it can be a per-dataset
9538 : * mask band, an alpha band, or an implicit mask band.
9539 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9540 : *
9541 : * This method is the same as the C function GDALIsMaskBand().
9542 : *
9543 : * @return true if the band is a mask band.
9544 : *
9545 : * @see GDALDataset::CreateMaskBand()
9546 : *
9547 : * @since GDAL 3.5.0
9548 : *
9549 : */
9550 :
9551 444 : bool GDALRasterBand::IsMaskBand() const
9552 : {
9553 : // The GeoTIFF driver, among others, override this method to
9554 : // also handle external .msk bands.
9555 444 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9556 444 : GCI_AlphaBand;
9557 : }
9558 :
9559 : /************************************************************************/
9560 : /* GDALIsMaskBand() */
9561 : /************************************************************************/
9562 :
9563 : /**
9564 : * \brief Returns whether a band is a mask band.
9565 : *
9566 : * Mask band must be understood in the broad term: it can be a per-dataset
9567 : * mask band, an alpha band, or an implicit mask band.
9568 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9569 : *
9570 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9571 : *
9572 : * @return true if the band is a mask band.
9573 : *
9574 : * @see GDALRasterBand::IsMaskBand()
9575 : *
9576 : * @since GDAL 3.5.0
9577 : *
9578 : */
9579 :
9580 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9581 :
9582 : {
9583 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9584 :
9585 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9586 37 : return poBand->IsMaskBand();
9587 : }
9588 :
9589 : /************************************************************************/
9590 : /* GetMaskValueRange() */
9591 : /************************************************************************/
9592 :
9593 : /**
9594 : * \brief Returns the range of values that a mask band can take.
9595 : *
9596 : * @return the range of values that a mask band can take.
9597 : *
9598 : * @since GDAL 3.5.0
9599 : *
9600 : */
9601 :
9602 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9603 : {
9604 0 : return GMVR_UNKNOWN;
9605 : }
9606 :
9607 : /************************************************************************/
9608 : /* GetIndexColorTranslationTo() */
9609 : /************************************************************************/
9610 :
9611 : /**
9612 : * \brief Compute translation table for color tables.
9613 : *
9614 : * When the raster band has a palette index, it may be useful to compute
9615 : * the "translation" of this palette to the palette of another band.
9616 : * The translation tries to do exact matching first, and then approximate
9617 : * matching if no exact matching is possible.
9618 : * This method returns a table such that table[i] = j where i is an index
9619 : * of the 'this' rasterband and j the corresponding index for the reference
9620 : * rasterband.
9621 : *
9622 : * This method is thought as internal to GDAL and is used for drivers
9623 : * like RPFTOC.
9624 : *
9625 : * The implementation only supports 1-byte palette rasterbands.
9626 : *
9627 : * @param poReferenceBand the raster band
9628 : * @param pTranslationTable an already allocated translation table (at least 256
9629 : * bytes), or NULL to let the method allocate it
9630 : * @param pApproximateMatching a pointer to a flag that is set if the matching
9631 : * is approximate. May be NULL.
9632 : *
9633 : * @return a translation table if the two bands are palette index and that they
9634 : * do not match or NULL in other cases. The table must be freed with CPLFree if
9635 : * NULL was passed for pTranslationTable.
9636 : */
9637 :
9638 : unsigned char *
9639 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9640 : unsigned char *pTranslationTable,
9641 : int *pApproximateMatching)
9642 : {
9643 4 : if (poReferenceBand == nullptr)
9644 0 : return nullptr;
9645 :
9646 : // cppcheck-suppress knownConditionTrueFalse
9647 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9648 : // cppcheck-suppress knownConditionTrueFalse
9649 4 : GetColorInterpretation() == GCI_PaletteIndex &&
9650 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
9651 4 : GetRasterDataType() == GDT_Byte)
9652 : {
9653 4 : const GDALColorTable *srcColorTable = GetColorTable();
9654 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9655 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
9656 : {
9657 4 : const int nEntries = srcColorTable->GetColorEntryCount();
9658 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
9659 :
9660 4 : int bHasNoDataValueSrc = FALSE;
9661 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9662 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9663 4 : dfNoDataValueSrc <= 255 &&
9664 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9665 0 : bHasNoDataValueSrc = FALSE;
9666 4 : const int noDataValueSrc =
9667 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
9668 :
9669 4 : int bHasNoDataValueRef = FALSE;
9670 : const double dfNoDataValueRef =
9671 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
9672 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
9673 3 : dfNoDataValueRef <= 255 &&
9674 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
9675 1 : bHasNoDataValueRef = FALSE;
9676 4 : const int noDataValueRef =
9677 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
9678 :
9679 4 : bool samePalette = false;
9680 :
9681 4 : if (pApproximateMatching)
9682 3 : *pApproximateMatching = FALSE;
9683 :
9684 4 : if (nEntries == nRefEntries &&
9685 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
9686 3 : (bHasNoDataValueSrc == FALSE ||
9687 : noDataValueSrc == noDataValueRef))
9688 : {
9689 3 : samePalette = true;
9690 654 : for (int i = 0; i < nEntries; ++i)
9691 : {
9692 651 : if (noDataValueSrc == i)
9693 3 : continue;
9694 : const GDALColorEntry *entry =
9695 648 : srcColorTable->GetColorEntry(i);
9696 : const GDALColorEntry *entryRef =
9697 648 : destColorTable->GetColorEntry(i);
9698 648 : if (entry->c1 != entryRef->c1 ||
9699 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
9700 : {
9701 0 : samePalette = false;
9702 : }
9703 : }
9704 : }
9705 :
9706 4 : if (!samePalette)
9707 : {
9708 1 : if (pTranslationTable == nullptr)
9709 : {
9710 : pTranslationTable = static_cast<unsigned char *>(
9711 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
9712 1 : if (pTranslationTable == nullptr)
9713 1 : return nullptr;
9714 : }
9715 :
9716 : // Trying to remap the product palette on the subdataset
9717 : // palette.
9718 5 : for (int i = 0; i < nEntries; ++i)
9719 : {
9720 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
9721 : noDataValueSrc == i)
9722 0 : continue;
9723 : const GDALColorEntry *entry =
9724 4 : srcColorTable->GetColorEntry(i);
9725 4 : bool bMatchFound = false;
9726 13 : for (int j = 0; j < nRefEntries; ++j)
9727 : {
9728 10 : if (bHasNoDataValueRef && noDataValueRef == j)
9729 0 : continue;
9730 : const GDALColorEntry *entryRef =
9731 10 : destColorTable->GetColorEntry(j);
9732 10 : if (entry->c1 == entryRef->c1 &&
9733 2 : entry->c2 == entryRef->c2 &&
9734 2 : entry->c3 == entryRef->c3)
9735 : {
9736 1 : pTranslationTable[i] =
9737 : static_cast<unsigned char>(j);
9738 1 : bMatchFound = true;
9739 1 : break;
9740 : }
9741 : }
9742 4 : if (!bMatchFound)
9743 : {
9744 : // No exact match. Looking for closest color now.
9745 3 : int best_j = 0;
9746 3 : int best_distance = 0;
9747 3 : if (pApproximateMatching)
9748 0 : *pApproximateMatching = TRUE;
9749 12 : for (int j = 0; j < nRefEntries; ++j)
9750 : {
9751 : const GDALColorEntry *entryRef =
9752 9 : destColorTable->GetColorEntry(j);
9753 9 : int distance = (entry->c1 - entryRef->c1) *
9754 9 : (entry->c1 - entryRef->c1) +
9755 9 : (entry->c2 - entryRef->c2) *
9756 9 : (entry->c2 - entryRef->c2) +
9757 9 : (entry->c3 - entryRef->c3) *
9758 9 : (entry->c3 - entryRef->c3);
9759 9 : if (j == 0 || distance < best_distance)
9760 : {
9761 7 : best_j = j;
9762 7 : best_distance = distance;
9763 : }
9764 : }
9765 3 : pTranslationTable[i] =
9766 : static_cast<unsigned char>(best_j);
9767 : }
9768 : }
9769 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
9770 0 : pTranslationTable[noDataValueSrc] =
9771 : static_cast<unsigned char>(noDataValueRef);
9772 :
9773 1 : return pTranslationTable;
9774 : }
9775 : }
9776 : }
9777 3 : return nullptr;
9778 : }
9779 :
9780 : /************************************************************************/
9781 : /* SetFlushBlockErr() */
9782 : /************************************************************************/
9783 :
9784 : /**
9785 : * \brief Store that an error occurred while writing a dirty block.
9786 : *
9787 : * This function stores the fact that an error occurred while writing a dirty
9788 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
9789 : * flushed when the block cache get full, it is not convenient/possible to
9790 : * report that a dirty block could not be written correctly. This function
9791 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
9792 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
9793 : * places where the user can easily match the error with the relevant dataset.
9794 : */
9795 :
9796 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
9797 : {
9798 0 : eFlushBlockErr = eErr;
9799 0 : }
9800 :
9801 : /************************************************************************/
9802 : /* IncDirtyBlocks() */
9803 : /************************************************************************/
9804 :
9805 : /**
9806 : * \brief Increment/decrement the number of dirty blocks
9807 : */
9808 :
9809 796475 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9810 : {
9811 796475 : if (poBandBlockCache)
9812 796475 : poBandBlockCache->IncDirtyBlocks(nInc);
9813 796477 : }
9814 :
9815 : /************************************************************************/
9816 : /* ReportError() */
9817 : /************************************************************************/
9818 :
9819 : #ifndef DOXYGEN_XML
9820 : /**
9821 : * \brief Emits an error related to a raster band.
9822 : *
9823 : * This function is a wrapper for regular CPLError(). The only difference
9824 : * with CPLError() is that it prepends the error message with the dataset
9825 : * name and the band number.
9826 : *
9827 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9828 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9829 : * @param fmt a printf() style format string. Any additional arguments
9830 : * will be treated as arguments to fill in this format in a manner
9831 : * similar to printf().
9832 : *
9833 : */
9834 :
9835 2474 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9836 : const char *fmt, ...) const
9837 : {
9838 : va_list args;
9839 :
9840 2474 : va_start(args, fmt);
9841 :
9842 2474 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9843 2474 : pszDSName = CPLGetFilename(pszDSName);
9844 2474 : if (pszDSName[0] != '\0')
9845 : {
9846 2403 : CPLError(eErrClass, err_no, "%s",
9847 4806 : CPLString()
9848 2403 : .Printf("%s, band %d: ", pszDSName, GetBand())
9849 4806 : .append(CPLString().vPrintf(fmt, args))
9850 : .c_str());
9851 : }
9852 : else
9853 : {
9854 71 : CPLErrorV(eErrClass, err_no, fmt, args);
9855 : }
9856 :
9857 2474 : va_end(args);
9858 2474 : }
9859 : #endif
9860 :
9861 : /************************************************************************/
9862 : /* GetVirtualMemAuto() */
9863 : /************************************************************************/
9864 :
9865 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9866 : *
9867 : * Only supported on Linux and Unix systems with mmap() for now.
9868 : *
9869 : * This method allows creating a virtual memory object for a GDALRasterBand,
9870 : * that exposes the whole image data as a virtual array.
9871 : *
9872 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9873 : * specialized implementation, such as for raw files, may also directly use
9874 : * mechanisms of the operating system to create a view of the underlying file
9875 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9876 : *
9877 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9878 : * offer a specialized implementation with direct file mapping, provided that
9879 : * some requirements are met :
9880 : * - for all drivers, the dataset must be backed by a "real" file in the file
9881 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9882 : * must match the native ordering of the CPU.
9883 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9884 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9885 : * the file in sequential order, and be equally spaced (which is generally the
9886 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9887 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9888 : *
9889 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9890 : * CPLVirtualMemFree() must be called before the raster band object is
9891 : * destroyed.
9892 : *
9893 : * If p is such a pointer and base_type the type matching
9894 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9895 : * accessed with
9896 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9897 : *
9898 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9899 : *
9900 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9901 : * read/write the band.
9902 : *
9903 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9904 : * one pixel value in the buffer to the start of the next pixel value within a
9905 : * scanline.
9906 : *
9907 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9908 : * one scanline in the buffer to the start of the next.
9909 : *
9910 : * @param papszOptions NULL terminated list of options.
9911 : * If a specialized implementation exists, defining
9912 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9913 : * used. On the contrary, defining
9914 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9915 : * being used (thus only allowing efficient implementations to be used). When
9916 : * requiring or falling back to the default implementation, the following
9917 : * options are available : CACHE_SIZE (in bytes, defaults to
9918 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9919 : * to FALSE)
9920 : *
9921 : * @return a virtual memory object that must be unreferenced by
9922 : * CPLVirtualMemFree(), or NULL in case of failure.
9923 : *
9924 : */
9925 :
9926 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9927 : int *pnPixelSpace,
9928 : GIntBig *pnLineSpace,
9929 : char **papszOptions)
9930 : {
9931 9 : const char *pszImpl = CSLFetchNameValueDef(
9932 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9933 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9934 8 : EQUAL(pszImpl, "FALSE"))
9935 : {
9936 1 : return nullptr;
9937 : }
9938 :
9939 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9940 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9941 8 : if (pnPixelSpace)
9942 8 : *pnPixelSpace = nPixelSpace;
9943 8 : if (pnLineSpace)
9944 8 : *pnLineSpace = nLineSpace;
9945 : const size_t nCacheSize =
9946 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9947 : const size_t nPageSizeHint =
9948 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9949 8 : const bool bSingleThreadUsage = CPLTestBool(
9950 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9951 8 : return GDALRasterBandGetVirtualMem(
9952 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9953 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9954 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9955 8 : papszOptions);
9956 : }
9957 :
9958 : /************************************************************************/
9959 : /* GDALGetVirtualMemAuto() */
9960 : /************************************************************************/
9961 :
9962 : /**
9963 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9964 : *
9965 : * @see GDALRasterBand::GetVirtualMemAuto()
9966 : */
9967 :
9968 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9969 : int *pnPixelSpace, GIntBig *pnLineSpace,
9970 : CSLConstList papszOptions)
9971 : {
9972 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9973 :
9974 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9975 :
9976 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9977 31 : const_cast<char **>(papszOptions));
9978 : }
9979 :
9980 : /************************************************************************/
9981 : /* GDALGetDataCoverageStatus() */
9982 : /************************************************************************/
9983 :
9984 : /**
9985 : * \brief Get the coverage status of a sub-window of the raster.
9986 : *
9987 : * Returns whether a sub-window of the raster contains only data, only empty
9988 : * blocks or a mix of both. This function can be used to determine quickly
9989 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9990 : * be sparse.
9991 : *
9992 : * Empty blocks are blocks that are generally not physically present in the
9993 : * file, and when read through GDAL, contain only pixels whose value is the
9994 : * nodata value when it is set, or whose value is 0 when the nodata value is
9995 : * not set.
9996 : *
9997 : * The query is done in an efficient way without reading the actual pixel
9998 : * values. If not possible, or not implemented at all by the driver,
9999 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10000 : * be returned.
10001 : *
10002 : * The values that can be returned by the function are the following,
10003 : * potentially combined with the binary or operator :
10004 : * <ul>
10005 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10006 : * GetDataCoverageStatus(). This flag should be returned together with
10007 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10008 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10009 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10010 : * the queried window. This is typically identified by the concept of missing
10011 : * block in formats that supports it.
10012 : * </li>
10013 : * </ul>
10014 : *
10015 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10016 : * should be interpreted more as hint of potential presence of data. For example
10017 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10018 : * nodata value), instead of using the missing block mechanism,
10019 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10020 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10021 : *
10022 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10023 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10024 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10025 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10026 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10027 : * the function will exit, so that you can potentially refine the requested area
10028 : * to find which particular region(s) have missing blocks.
10029 : *
10030 : * @see GDALRasterBand::GetDataCoverageStatus()
10031 : *
10032 : * @param hBand raster band
10033 : *
10034 : * @param nXOff The pixel offset to the top left corner of the region
10035 : * of the band to be queried. This would be zero to start from the left side.
10036 : *
10037 : * @param nYOff The line offset to the top left corner of the region
10038 : * of the band to be queried. This would be zero to start from the top.
10039 : *
10040 : * @param nXSize The width of the region of the band to be queried in pixels.
10041 : *
10042 : * @param nYSize The height of the region of the band to be queried in lines.
10043 : *
10044 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10045 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10046 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10047 : * as the computation of the coverage matches the mask, the computation will be
10048 : * stopped. *pdfDataPct will not be valid in that case.
10049 : *
10050 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10051 : * to the (approximate) percentage in [0,100] of pixels in the queried
10052 : * sub-window that have valid values. The implementation might not always be
10053 : * able to compute it, in which case it will be set to a negative value.
10054 : *
10055 : * @return a binary-or'ed combination of possible values
10056 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10057 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10058 : */
10059 :
10060 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10061 : int nYOff, int nXSize, int nYSize,
10062 : int nMaskFlagStop, double *pdfDataPct)
10063 : {
10064 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10065 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10066 :
10067 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10068 :
10069 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10070 29 : nMaskFlagStop, pdfDataPct);
10071 : }
10072 :
10073 : /************************************************************************/
10074 : /* GetDataCoverageStatus() */
10075 : /************************************************************************/
10076 :
10077 : /**
10078 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10079 : * int nYOff,
10080 : * int nXSize,
10081 : * int nYSize,
10082 : * int nMaskFlagStop,
10083 : * double* pdfDataPct)
10084 : * \brief Get the coverage status of a sub-window of the raster.
10085 : *
10086 : * Returns whether a sub-window of the raster contains only data, only empty
10087 : * blocks or a mix of both. This function can be used to determine quickly
10088 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10089 : * be sparse.
10090 : *
10091 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10092 : * value when it is set, or whose value is 0 when the nodata value is not set.
10093 : *
10094 : * The query is done in an efficient way without reading the actual pixel
10095 : * values. If not possible, or not implemented at all by the driver,
10096 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10097 : * be returned.
10098 : *
10099 : * The values that can be returned by the function are the following,
10100 : * potentially combined with the binary or operator :
10101 : * <ul>
10102 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10103 : * GetDataCoverageStatus(). This flag should be returned together with
10104 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10105 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10106 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10107 : * the queried window. This is typically identified by the concept of missing
10108 : * block in formats that supports it.
10109 : * </li>
10110 : * </ul>
10111 : *
10112 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10113 : * should be interpreted more as hint of potential presence of data. For example
10114 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10115 : * nodata value), instead of using the missing block mechanism,
10116 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10117 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10118 : *
10119 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10120 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10121 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10122 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10123 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10124 : * the function will exit, so that you can potentially refine the requested area
10125 : * to find which particular region(s) have missing blocks.
10126 : *
10127 : * @see GDALGetDataCoverageStatus()
10128 : *
10129 : * @param nXOff The pixel offset to the top left corner of the region
10130 : * of the band to be queried. This would be zero to start from the left side.
10131 : *
10132 : * @param nYOff The line offset to the top left corner of the region
10133 : * of the band to be queried. This would be zero to start from the top.
10134 : *
10135 : * @param nXSize The width of the region of the band to be queried in pixels.
10136 : *
10137 : * @param nYSize The height of the region of the band to be queried in lines.
10138 : *
10139 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10140 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10141 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10142 : * as the computation of the coverage matches the mask, the computation will be
10143 : * stopped. *pdfDataPct will not be valid in that case.
10144 : *
10145 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10146 : * to the (approximate) percentage in [0,100] of pixels in the queried
10147 : * sub-window that have valid values. The implementation might not always be
10148 : * able to compute it, in which case it will be set to a negative value.
10149 : *
10150 : * @return a binary-or'ed combination of possible values
10151 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10152 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10153 : */
10154 :
10155 : /**
10156 : * \brief Get the coverage status of a sub-window of the raster.
10157 : *
10158 : * Returns whether a sub-window of the raster contains only data, only empty
10159 : * blocks or a mix of both. This function can be used to determine quickly
10160 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10161 : * be sparse.
10162 : *
10163 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10164 : * value when it is set, or whose value is 0 when the nodata value is not set.
10165 : *
10166 : * The query is done in an efficient way without reading the actual pixel
10167 : * values. If not possible, or not implemented at all by the driver,
10168 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10169 : * be returned.
10170 : *
10171 : * The values that can be returned by the function are the following,
10172 : * potentially combined with the binary or operator :
10173 : * <ul>
10174 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10175 : * GetDataCoverageStatus(). This flag should be returned together with
10176 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10177 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10178 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10179 : * the queried window. This is typically identified by the concept of missing
10180 : * block in formats that supports it.
10181 : * </li>
10182 : * </ul>
10183 : *
10184 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10185 : * should be interpreted more as hint of potential presence of data. For example
10186 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10187 : * nodata value), instead of using the missing block mechanism,
10188 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10189 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10190 : *
10191 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10192 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10193 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10194 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10195 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10196 : * the function will exit, so that you can potentially refine the requested area
10197 : * to find which particular region(s) have missing blocks.
10198 : *
10199 : * @see GDALGetDataCoverageStatus()
10200 : *
10201 : * @param nXOff The pixel offset to the top left corner of the region
10202 : * of the band to be queried. This would be zero to start from the left side.
10203 : *
10204 : * @param nYOff The line offset to the top left corner of the region
10205 : * of the band to be queried. This would be zero to start from the top.
10206 : *
10207 : * @param nXSize The width of the region of the band to be queried in pixels.
10208 : *
10209 : * @param nYSize The height of the region of the band to be queried in lines.
10210 : *
10211 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10212 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10213 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10214 : * as the computation of the coverage matches the mask, the computation will be
10215 : * stopped. *pdfDataPct will not be valid in that case.
10216 : *
10217 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10218 : * to the (approximate) percentage in [0,100] of pixels in the queried
10219 : * sub-window that have valid values. The implementation might not always be
10220 : * able to compute it, in which case it will be set to a negative value.
10221 : *
10222 : * @return a binary-or'ed combination of possible values
10223 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10224 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10225 : */
10226 :
10227 4693 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10228 : int nYSize, int nMaskFlagStop,
10229 : double *pdfDataPct)
10230 : {
10231 4693 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
10232 4693 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
10233 4693 : nYOff + nYSize > nRasterYSize)
10234 : {
10235 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10236 0 : if (pdfDataPct)
10237 0 : *pdfDataPct = 0.0;
10238 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10239 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10240 : }
10241 4693 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10242 4693 : pdfDataPct);
10243 : }
10244 :
10245 : /************************************************************************/
10246 : /* IGetDataCoverageStatus() */
10247 : /************************************************************************/
10248 :
10249 685 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10250 : int /*nXSize*/, int /*nYSize*/,
10251 : int /*nMaskFlagStop*/,
10252 : double *pdfDataPct)
10253 : {
10254 685 : if (pdfDataPct != nullptr)
10255 0 : *pdfDataPct = 100.0;
10256 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10257 685 : GDAL_DATA_COVERAGE_STATUS_DATA;
10258 : }
10259 :
10260 : //! @cond Doxygen_Suppress
10261 : /************************************************************************/
10262 : /* EnterReadWrite() */
10263 : /************************************************************************/
10264 :
10265 7797730 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10266 : {
10267 7797730 : if (poDS != nullptr)
10268 7031350 : return poDS->EnterReadWrite(eRWFlag);
10269 766378 : return FALSE;
10270 : }
10271 :
10272 : /************************************************************************/
10273 : /* LeaveReadWrite() */
10274 : /************************************************************************/
10275 :
10276 1128950 : void GDALRasterBand::LeaveReadWrite()
10277 : {
10278 1128950 : if (poDS != nullptr)
10279 1128960 : poDS->LeaveReadWrite();
10280 1128950 : }
10281 :
10282 : /************************************************************************/
10283 : /* InitRWLock() */
10284 : /************************************************************************/
10285 :
10286 3978190 : void GDALRasterBand::InitRWLock()
10287 : {
10288 3978190 : if (poDS != nullptr)
10289 3977780 : poDS->InitRWLock();
10290 3978180 : }
10291 :
10292 : //! @endcond
10293 :
10294 : // clang-format off
10295 :
10296 : /**
10297 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10298 : * \brief Set metadata.
10299 : *
10300 : * CAUTION: depending on the format, older values of the updated information
10301 : * might still be found in the file in a "ghost" state, even if no longer
10302 : * accessible through the GDAL API. This is for example the case of the GTiff
10303 : * format (this is not a exhaustive list)
10304 : *
10305 : * The C function GDALSetMetadata() does the same thing as this method.
10306 : *
10307 : * @param papszMetadata the metadata in name=value string list format to
10308 : * apply.
10309 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10310 : * domain.
10311 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10312 : * metadata has been accepted, but is likely not maintained persistently
10313 : * by the underlying object between sessions.
10314 : */
10315 :
10316 : /**
10317 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10318 : * \brief Set single metadata item.
10319 : *
10320 : * CAUTION: depending on the format, older values of the updated information
10321 : * might still be found in the file in a "ghost" state, even if no longer
10322 : * accessible through the GDAL API. This is for example the case of the GTiff
10323 : * format (this is not a exhaustive list)
10324 : *
10325 : * The C function GDALSetMetadataItem() does the same thing as this method.
10326 : *
10327 : * @param pszName the key for the metadata item to fetch.
10328 : * @param pszValue the value to assign to the key.
10329 : * @param pszDomain the domain to set within, use NULL for the default domain.
10330 : *
10331 : * @return CE_None on success, or an error code on failure.
10332 : */
10333 :
10334 : // clang-format on
10335 :
10336 : //! @cond Doxygen_Suppress
10337 : /************************************************************************/
10338 : /* EnablePixelTypeSignedByteWarning() */
10339 : /************************************************************************/
10340 :
10341 157057 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10342 : {
10343 157057 : m_bEnablePixelTypeSignedByteWarning = b;
10344 157057 : }
10345 :
10346 4902 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10347 : {
10348 4902 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10349 4902 : }
10350 :
10351 : //! @endcond
10352 :
10353 : /************************************************************************/
10354 : /* GetMetadataItem() */
10355 : /************************************************************************/
10356 :
10357 621068 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10358 : const char *pszDomain)
10359 : {
10360 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10361 621068 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
10362 462472 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10363 321871 : EQUAL(pszName, "PIXELTYPE"))
10364 : {
10365 2 : CPLError(CE_Warning, CPLE_AppDefined,
10366 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10367 : "used to signal signed 8-bit raster. Change your code to "
10368 : "test for the new GDT_Int8 data type instead.");
10369 : }
10370 621068 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10371 : }
10372 :
10373 : /************************************************************************/
10374 : /* WindowIterator */
10375 : /************************************************************************/
10376 :
10377 : //! @cond Doxygen_Suppress
10378 :
10379 560 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10380 : int nRasterYSize,
10381 : int nBlockXSize, int nBlockYSize,
10382 560 : int nRow, int nCol)
10383 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10384 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10385 560 : m_col(nCol)
10386 : {
10387 560 : }
10388 :
10389 768 : bool GDALRasterBand::WindowIterator::operator==(
10390 : const WindowIterator &other) const
10391 : {
10392 251 : return m_row == other.m_row && m_col == other.m_col &&
10393 251 : m_nRasterXSize == other.m_nRasterXSize &&
10394 251 : m_nRasterYSize == other.m_nRasterYSize &&
10395 1270 : m_nBlockXSize == other.m_nBlockXSize &&
10396 1019 : m_nBlockYSize == other.m_nBlockYSize;
10397 : }
10398 :
10399 742 : bool GDALRasterBand::WindowIterator::operator!=(
10400 : const WindowIterator &other) const
10401 : {
10402 742 : return !(*this == other);
10403 : }
10404 :
10405 : GDALRasterBand::WindowIterator::value_type
10406 516 : GDALRasterBand::WindowIterator::operator*() const
10407 : {
10408 : GDALRasterWindow ret;
10409 516 : ret.nXOff = m_col * m_nBlockXSize;
10410 516 : ret.nYOff = m_row * m_nBlockYSize;
10411 516 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10412 516 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10413 :
10414 516 : return ret;
10415 : }
10416 :
10417 514 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10418 : {
10419 514 : m_col++;
10420 514 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10421 : {
10422 430 : m_col = 0;
10423 430 : m_row++;
10424 : }
10425 514 : return *this;
10426 : }
10427 :
10428 297 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10429 297 : const GDALRasterBand &band, size_t maxSize)
10430 297 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
10431 297 : m_nBlockXSize(-1), m_nBlockYSize(-1)
10432 : {
10433 : #ifdef CSA_BUILD
10434 : assert(this);
10435 : #endif
10436 : int nXSize, nYSize;
10437 :
10438 297 : CPLErrorStateBackuper state(CPLQuietErrorHandler);
10439 297 : band.GetBlockSize(&nXSize, &nYSize);
10440 297 : if (nXSize < 1 || nYSize < 0)
10441 : {
10442 : // If invalid block size is reported, assume scanlines
10443 4 : nXSize = m_nRasterXSize;
10444 4 : nYSize = 1;
10445 : }
10446 :
10447 297 : if (maxSize == 0)
10448 : {
10449 234 : m_nBlockXSize = nXSize;
10450 234 : m_nBlockYSize = nYSize;
10451 234 : return;
10452 : }
10453 :
10454 63 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10455 63 : const double dfBlocksPerChunk =
10456 63 : static_cast<double>(maxSize) /
10457 63 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10458 :
10459 63 : if (dfBlocksPerChunk < dfBlocksPerRow)
10460 : {
10461 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10462 14 : m_nRasterXSize,
10463 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10464 14 : m_nBlockYSize = nYSize;
10465 : }
10466 : else
10467 : {
10468 49 : m_nBlockXSize = m_nRasterXSize;
10469 49 : m_nBlockYSize = static_cast<int>(std::min<double>(
10470 49 : m_nRasterYSize,
10471 49 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10472 : }
10473 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10474 : {
10475 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10476 : {
10477 : nXSize = m_nRasterXSize;
10478 : nYSize = 1;
10479 : }
10480 : }
10481 : }
10482 :
10483 : GDALRasterBand::WindowIterator
10484 266 : GDALRasterBand::WindowIteratorWrapper::begin() const
10485 : {
10486 266 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10487 266 : m_nBlockYSize, 0, 0);
10488 : }
10489 :
10490 : GDALRasterBand::WindowIterator
10491 266 : GDALRasterBand::WindowIteratorWrapper::end() const
10492 : {
10493 266 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10494 266 : m_nBlockYSize,
10495 266 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10496 : }
10497 :
10498 55 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10499 : {
10500 55 : return static_cast<uint64_t>(
10501 55 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10502 55 : static_cast<uint64_t>(
10503 55 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10504 : }
10505 :
10506 : //! @endcond
10507 :
10508 : /** Return an object whose begin() and end() methods can be used to iterate
10509 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10510 : * band. The iteration order is from left to right, then from top to bottom.
10511 : *
10512 : \code{.cpp}
10513 : std::vector<double> pixelValues;
10514 : for (const auto& window : poBand->IterateWindows()) {
10515 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10516 : window.nXSize, window.nYSize);
10517 : // check eErr
10518 : }
10519 : \endcode
10520 : *
10521 : *
10522 : * @param maxSize The maximum number of pixels in each window. If set to
10523 : * zero (the default), or a number smaller than the block size,
10524 : * the window size will be the same as the block size.
10525 : * @since GDAL 3.12
10526 : */
10527 : GDALRasterBand::WindowIteratorWrapper
10528 297 : GDALRasterBand::IterateWindows(size_t maxSize) const
10529 : {
10530 297 : return WindowIteratorWrapper(*this, maxSize);
10531 : }
10532 :
10533 : /************************************************************************/
10534 : /* GDALMDArrayFromRasterBand */
10535 : /************************************************************************/
10536 :
10537 : class GDALMDArrayFromRasterBand final : public GDALMDArray
10538 : {
10539 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10540 :
10541 : GDALDataset *m_poDS;
10542 : GDALRasterBand *m_poBand;
10543 : GDALExtendedDataType m_dt;
10544 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10545 : std::string m_osUnit;
10546 : std::vector<GByte> m_pabyNoData{};
10547 : std::shared_ptr<GDALMDArray> m_varX{};
10548 : std::shared_ptr<GDALMDArray> m_varY{};
10549 : std::string m_osFilename{};
10550 :
10551 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10552 : const size_t *count, const GInt64 *arrayStep,
10553 : const GPtrDiff_t *bufferStride,
10554 : const GDALExtendedDataType &bufferDataType,
10555 : void *pBuffer) const;
10556 :
10557 : protected:
10558 34 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10559 68 : : GDALAbstractMDArray(std::string(),
10560 68 : std::string(poDS->GetDescription()) +
10561 : CPLSPrintf(" band %d", poBand->GetBand())),
10562 68 : GDALMDArray(std::string(),
10563 68 : std::string(poDS->GetDescription()) +
10564 : CPLSPrintf(" band %d", poBand->GetBand())),
10565 : m_poDS(poDS), m_poBand(poBand),
10566 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10567 170 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10568 : {
10569 34 : m_poDS->Reference();
10570 :
10571 34 : int bHasNoData = false;
10572 34 : if (m_poBand->GetRasterDataType() == GDT_Int64)
10573 : {
10574 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10575 0 : if (bHasNoData)
10576 : {
10577 0 : m_pabyNoData.resize(m_dt.GetSize());
10578 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10579 : m_dt.GetNumericDataType(), 0, 1);
10580 : }
10581 : }
10582 34 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10583 : {
10584 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10585 0 : if (bHasNoData)
10586 : {
10587 0 : m_pabyNoData.resize(m_dt.GetSize());
10588 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10589 : m_dt.GetNumericDataType(), 0, 1);
10590 : }
10591 : }
10592 : else
10593 : {
10594 34 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10595 34 : if (bHasNoData)
10596 : {
10597 1 : m_pabyNoData.resize(m_dt.GetSize());
10598 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10599 : m_dt.GetNumericDataType(), 0, 1);
10600 : }
10601 : }
10602 :
10603 34 : const int nXSize = poBand->GetXSize();
10604 34 : const int nYSize = poBand->GetYSize();
10605 :
10606 34 : auto poSRS = m_poDS->GetSpatialRef();
10607 68 : std::string osTypeY;
10608 68 : std::string osTypeX;
10609 68 : std::string osDirectionY;
10610 68 : std::string osDirectionX;
10611 34 : if (poSRS && poSRS->GetAxesCount() == 2)
10612 : {
10613 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10614 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
10615 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
10616 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
10617 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
10618 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10619 : {
10620 8 : if (mapping == std::vector<int>{1, 2})
10621 : {
10622 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10623 8 : osDirectionY = "NORTH";
10624 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10625 8 : osDirectionX = "EAST";
10626 : }
10627 : }
10628 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
10629 : {
10630 16 : if (mapping == std::vector<int>{2, 1})
10631 : {
10632 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10633 16 : osDirectionY = "NORTH";
10634 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10635 16 : osDirectionX = "EAST";
10636 : }
10637 : }
10638 : }
10639 :
10640 170 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
10641 : "/", "Y", osTypeY, osDirectionY, nYSize),
10642 68 : std::make_shared<GDALDimensionWeakIndexingVar>(
10643 102 : "/", "X", osTypeX, osDirectionX, nXSize)};
10644 :
10645 34 : GDALGeoTransform gt;
10646 34 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
10647 : {
10648 50 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
10649 50 : gt[0], gt[1], 0.5);
10650 25 : m_dims[1]->SetIndexingVariable(m_varX);
10651 :
10652 50 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
10653 50 : gt[3], gt[5], 0.5);
10654 25 : m_dims[0]->SetIndexingVariable(m_varY);
10655 : }
10656 34 : }
10657 :
10658 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
10659 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10660 : const GDALExtendedDataType &bufferDataType,
10661 : void *pDstBuffer) const override;
10662 :
10663 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
10664 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10665 : const GDALExtendedDataType &bufferDataType,
10666 : const void *pSrcBuffer) override
10667 : {
10668 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
10669 : bufferStride, bufferDataType,
10670 1 : const_cast<void *>(pSrcBuffer));
10671 : }
10672 :
10673 : public:
10674 68 : ~GDALMDArrayFromRasterBand() override
10675 34 : {
10676 34 : m_poDS->ReleaseRef();
10677 68 : }
10678 :
10679 34 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
10680 : GDALRasterBand *poBand)
10681 : {
10682 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
10683 68 : new GDALMDArrayFromRasterBand(poDS, poBand)));
10684 34 : array->SetSelf(array);
10685 68 : return array;
10686 : }
10687 :
10688 5 : bool IsWritable() const override
10689 : {
10690 5 : return m_poDS->GetAccess() == GA_Update;
10691 : }
10692 :
10693 122 : const std::string &GetFilename() const override
10694 : {
10695 122 : return m_osFilename;
10696 : }
10697 :
10698 : const std::vector<std::shared_ptr<GDALDimension>> &
10699 343 : GetDimensions() const override
10700 : {
10701 343 : return m_dims;
10702 : }
10703 :
10704 158 : const GDALExtendedDataType &GetDataType() const override
10705 : {
10706 158 : return m_dt;
10707 : }
10708 :
10709 5 : const std::string &GetUnit() const override
10710 : {
10711 5 : return m_osUnit;
10712 : }
10713 :
10714 32 : const void *GetRawNoDataValue() const override
10715 : {
10716 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
10717 : }
10718 :
10719 4 : double GetOffset(bool *pbHasOffset,
10720 : GDALDataType *peStorageType) const override
10721 : {
10722 4 : int bHasOffset = false;
10723 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
10724 4 : if (pbHasOffset)
10725 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
10726 4 : if (peStorageType)
10727 1 : *peStorageType = GDT_Unknown;
10728 4 : return dfRes;
10729 : }
10730 :
10731 4 : double GetScale(bool *pbHasScale,
10732 : GDALDataType *peStorageType) const override
10733 : {
10734 4 : int bHasScale = false;
10735 4 : double dfRes = m_poBand->GetScale(&bHasScale);
10736 4 : if (pbHasScale)
10737 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
10738 4 : if (peStorageType)
10739 1 : *peStorageType = GDT_Unknown;
10740 4 : return dfRes;
10741 : }
10742 :
10743 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
10744 : {
10745 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
10746 88 : if (!poSrcSRS)
10747 2 : return nullptr;
10748 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
10749 :
10750 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
10751 86 : constexpr int iYDim = 0;
10752 86 : constexpr int iXDim = 1;
10753 258 : for (auto &m : axisMapping)
10754 : {
10755 172 : if (m == 1)
10756 86 : m = iXDim + 1;
10757 86 : else if (m == 2)
10758 86 : m = iYDim + 1;
10759 : else
10760 0 : m = 0;
10761 : }
10762 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
10763 86 : return poSRS;
10764 : }
10765 :
10766 32 : std::vector<GUInt64> GetBlockSize() const override
10767 : {
10768 32 : int nBlockXSize = 0;
10769 32 : int nBlockYSize = 0;
10770 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
10771 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
10772 32 : static_cast<GUInt64>(nBlockXSize)};
10773 : }
10774 :
10775 : std::vector<std::shared_ptr<GDALAttribute>>
10776 23 : GetAttributes(CSLConstList) const override
10777 : {
10778 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
10779 23 : auto papszMD = m_poBand->GetMetadata();
10780 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
10781 : {
10782 2 : char *pszKey = nullptr;
10783 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
10784 2 : if (pszKey && pszValue)
10785 : {
10786 : res.emplace_back(
10787 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
10788 : }
10789 2 : CPLFree(pszKey);
10790 : }
10791 23 : return res;
10792 : }
10793 : };
10794 :
10795 39 : bool GDALMDArrayFromRasterBand::IRead(
10796 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
10797 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
10798 : void *pDstBuffer) const
10799 : {
10800 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
10801 39 : bufferDataType, pDstBuffer);
10802 : }
10803 :
10804 : /************************************************************************/
10805 : /* ReadWrite() */
10806 : /************************************************************************/
10807 :
10808 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
10809 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10810 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10811 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10812 : {
10813 40 : constexpr size_t iDimX = 1;
10814 40 : constexpr size_t iDimY = 0;
10815 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10816 : arrayStartIdx, count, arrayStep, bufferStride,
10817 40 : bufferDataType, pBuffer);
10818 : }
10819 :
10820 : /************************************************************************/
10821 : /* GDALMDRasterIOFromBand() */
10822 : /************************************************************************/
10823 :
10824 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10825 : size_t iDimX, size_t iDimY,
10826 : const GUInt64 *arrayStartIdx, const size_t *count,
10827 : const GInt64 *arrayStep,
10828 : const GPtrDiff_t *bufferStride,
10829 : const GDALExtendedDataType &bufferDataType,
10830 : void *pBuffer)
10831 : {
10832 73 : const auto eDT(bufferDataType.GetNumericDataType());
10833 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10834 73 : const int nX =
10835 73 : arrayStep[iDimX] > 0
10836 73 : ? static_cast<int>(arrayStartIdx[iDimX])
10837 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10838 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10839 73 : const int nY =
10840 73 : arrayStep[iDimY] > 0
10841 73 : ? static_cast<int>(arrayStartIdx[iDimY])
10842 6 : : static_cast<int>(arrayStartIdx[iDimY] -
10843 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10844 73 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10845 73 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10846 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10847 73 : int nStrideXSign = 1;
10848 73 : if (arrayStep[iDimX] < 0)
10849 : {
10850 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10851 2 : nStrideXSign = -1;
10852 : }
10853 73 : int nStrideYSign = 1;
10854 73 : if (arrayStep[iDimY] < 0)
10855 : {
10856 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10857 6 : nStrideYSign = -1;
10858 : }
10859 :
10860 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10861 73 : static_cast<int>(count[iDimX]),
10862 73 : static_cast<int>(count[iDimY]), eDT,
10863 : static_cast<GSpacing>(
10864 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10865 : static_cast<GSpacing>(
10866 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10867 73 : nullptr) == CE_None;
10868 : }
10869 :
10870 : /************************************************************************/
10871 : /* AsMDArray() */
10872 : /************************************************************************/
10873 :
10874 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10875 : *
10876 : * The band must be linked to a GDALDataset. If this dataset is not already
10877 : * marked as shared, it will be, so that the returned array holds a reference
10878 : * to it.
10879 : *
10880 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10881 : * returned array will have an associated indexing variable.
10882 : *
10883 : * This is the same as the C function GDALRasterBandAsMDArray().
10884 : *
10885 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10886 : *
10887 : * @return a new array, or nullptr.
10888 : *
10889 : * @since GDAL 3.1
10890 : */
10891 34 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10892 : {
10893 34 : if (!poDS)
10894 : {
10895 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10896 0 : return nullptr;
10897 : }
10898 34 : if (!poDS->GetShared())
10899 : {
10900 33 : poDS->MarkAsShared();
10901 : }
10902 : return GDALMDArrayFromRasterBand::Create(
10903 34 : poDS, const_cast<GDALRasterBand *>(this));
10904 : }
10905 :
10906 : /************************************************************************/
10907 : /* InterpolateAtPoint() */
10908 : /************************************************************************/
10909 :
10910 : /**
10911 : * \brief Interpolates the value between pixels using a resampling algorithm,
10912 : * taking pixel/line coordinates as input.
10913 : *
10914 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10915 : * @param dfLine line coordinate as a double, where interpolation should be done.
10916 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10917 : * @param pdfRealValue pointer to real part of interpolated value
10918 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10919 : *
10920 : * @return CE_None on success, or an error code on failure.
10921 : * @since GDAL 3.10
10922 : */
10923 :
10924 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10925 : GDALRIOResampleAlg eInterpolation,
10926 : double *pdfRealValue,
10927 : double *pdfImagValue) const
10928 : {
10929 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10930 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10931 : eInterpolation != GRIORA_CubicSpline)
10932 : {
10933 2 : CPLError(CE_Failure, CPLE_AppDefined,
10934 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10935 : "methods "
10936 : "allowed");
10937 :
10938 2 : return CE_Failure;
10939 : }
10940 :
10941 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10942 165 : if (!m_poPointsCache)
10943 85 : m_poPointsCache = new GDALDoublePointsCache();
10944 :
10945 : const bool res =
10946 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10947 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10948 :
10949 165 : return res ? CE_None : CE_Failure;
10950 : }
10951 :
10952 : /************************************************************************/
10953 : /* GDALRasterInterpolateAtPoint() */
10954 : /************************************************************************/
10955 :
10956 : /**
10957 : * \brief Interpolates the value between pixels using
10958 : * a resampling algorithm
10959 : *
10960 : * @see GDALRasterBand::InterpolateAtPoint()
10961 : * @since GDAL 3.10
10962 : */
10963 :
10964 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10965 : double dfLine,
10966 : GDALRIOResampleAlg eInterpolation,
10967 : double *pdfRealValue, double *pdfImagValue)
10968 : {
10969 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10970 :
10971 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10972 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10973 144 : pdfRealValue, pdfImagValue);
10974 : }
10975 :
10976 : /************************************************************************/
10977 : /* InterpolateAtGeolocation() */
10978 : /************************************************************************/
10979 :
10980 : /**
10981 : * \brief Interpolates the value between pixels using a resampling algorithm,
10982 : * taking georeferenced coordinates as input.
10983 : *
10984 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10985 : * must be in the "natural" SRS of the dataset, that is the one returned by
10986 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10987 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10988 : * array (generally WGS 84) if there is a geolocation array.
10989 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10990 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10991 : * be a easting, and dfGeolocY a northing.
10992 : *
10993 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10994 : * expressed in that CRS, and that tuple must be conformant with the
10995 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10996 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10997 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10998 : * before calling this method, and in that case, dfGeolocX must be a longitude
10999 : * or an easting value, and dfGeolocX a latitude or a northing value.
11000 : *
11001 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11002 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11003 : * it for details on how that transformation is done.
11004 : *
11005 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11006 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11007 : * where interpolation should be done.
11008 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11009 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11010 : * where interpolation should be done.
11011 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11012 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11013 : * @param pdfRealValue pointer to real part of interpolated value
11014 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11015 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11016 : *
11017 : * @return CE_None on success, or an error code on failure.
11018 : * @since GDAL 3.11
11019 : */
11020 :
11021 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11022 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11023 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11024 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11025 : {
11026 : double dfPixel;
11027 : double dfLine;
11028 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11029 : &dfLine,
11030 15 : papszTransformerOptions) != CE_None)
11031 : {
11032 1 : return CE_Failure;
11033 : }
11034 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11035 14 : pdfImagValue);
11036 : }
11037 :
11038 : /************************************************************************/
11039 : /* GDALRasterInterpolateAtGeolocation() */
11040 : /************************************************************************/
11041 :
11042 : /**
11043 : * \brief Interpolates the value between pixels using a resampling algorithm,
11044 : * taking georeferenced coordinates as input.
11045 : *
11046 : * @see GDALRasterBand::InterpolateAtGeolocation()
11047 : * @since GDAL 3.11
11048 : */
11049 :
11050 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11051 : double dfGeolocX, double dfGeolocY,
11052 : OGRSpatialReferenceH hSRS,
11053 : GDALRIOResampleAlg eInterpolation,
11054 : double *pdfRealValue,
11055 : double *pdfImagValue,
11056 : CSLConstList papszTransformerOptions)
11057 : {
11058 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11059 :
11060 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11061 15 : return poBand->InterpolateAtGeolocation(
11062 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11063 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11064 : }
11065 :
11066 : /************************************************************************/
11067 : /* GDALRasterBand::SplitRasterIO() */
11068 : /************************************************************************/
11069 :
11070 : //! @cond Doxygen_Suppress
11071 :
11072 : /** Implements IRasterIO() by dividing the request in 2.
11073 : *
11074 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11075 : *
11076 : * Return CE_Warning if the split could not be done, CE_None in case of
11077 : * success and CE_Failure in case of error.
11078 : *
11079 : * @since 3.12
11080 : */
11081 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11082 : [[maybe_unused]] int nXSize,
11083 : [[maybe_unused]] int nYSize, void *pData,
11084 : int nBufXSize, int nBufYSize,
11085 : GDALDataType eBufType,
11086 : GSpacing nPixelSpace, GSpacing nLineSpace,
11087 : GDALRasterIOExtraArg *psExtraArg)
11088 : {
11089 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11090 :
11091 999 : GByte *pabyData = static_cast<GByte *>(pData);
11092 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11093 : {
11094 : GDALRasterIOExtraArg sArg;
11095 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11096 499 : const int nHalfHeight = nBufYSize / 2;
11097 :
11098 499 : sArg.pfnProgress = GDALScaledProgress;
11099 499 : sArg.pProgressData = GDALCreateScaledProgress(
11100 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11101 499 : if (sArg.pProgressData == nullptr)
11102 499 : sArg.pfnProgress = nullptr;
11103 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11104 : pabyData, nBufXSize, nHalfHeight, eBufType,
11105 499 : nPixelSpace, nLineSpace, &sArg);
11106 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11107 :
11108 499 : if (eErr == CE_None)
11109 : {
11110 499 : sArg.pfnProgress = GDALScaledProgress;
11111 499 : sArg.pProgressData = GDALCreateScaledProgress(
11112 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11113 499 : if (sArg.pProgressData == nullptr)
11114 499 : sArg.pfnProgress = nullptr;
11115 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11116 : nBufYSize - nHalfHeight,
11117 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11118 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11119 499 : nLineSpace, &sArg);
11120 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11121 : }
11122 499 : return eErr;
11123 : }
11124 500 : else if (nBufXSize >= 2)
11125 : {
11126 : GDALRasterIOExtraArg sArg;
11127 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11128 500 : const int nHalfWidth = nBufXSize / 2;
11129 :
11130 500 : sArg.pfnProgress = GDALScaledProgress;
11131 500 : sArg.pProgressData = GDALCreateScaledProgress(
11132 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11133 500 : if (sArg.pProgressData == nullptr)
11134 500 : sArg.pfnProgress = nullptr;
11135 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11136 : pabyData, nHalfWidth, nBufYSize, eBufType,
11137 500 : nPixelSpace, nLineSpace, &sArg);
11138 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11139 :
11140 500 : if (eErr == CE_None)
11141 : {
11142 500 : sArg.pfnProgress = GDALScaledProgress;
11143 500 : sArg.pProgressData = GDALCreateScaledProgress(
11144 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11145 500 : if (sArg.pProgressData == nullptr)
11146 500 : sArg.pfnProgress = nullptr;
11147 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11148 : nBufXSize - nHalfWidth, nBufYSize,
11149 500 : pabyData + nHalfWidth * nPixelSpace,
11150 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11151 500 : nPixelSpace, nLineSpace, &sArg);
11152 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11153 : }
11154 500 : return eErr;
11155 : }
11156 :
11157 0 : return CE_Warning;
11158 : }
11159 :
11160 : //! @endcond
11161 :
11162 : /************************************************************************/
11163 : /* ThrowIfNotSameDimensions() */
11164 : /************************************************************************/
11165 :
11166 : //! @cond Doxygen_Suppress
11167 : /* static */
11168 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11169 : const GDALRasterBand &second)
11170 : {
11171 320 : if (first.GetXSize() != second.GetXSize() ||
11172 151 : first.GetYSize() != second.GetYSize())
11173 : {
11174 36 : throw std::runtime_error("Bands do not have the same dimensions");
11175 : }
11176 133 : }
11177 :
11178 : //! @endcond
11179 :
11180 : /************************************************************************/
11181 : /* GDALRasterBandUnaryOp() */
11182 : /************************************************************************/
11183 :
11184 : /** Apply a unary operation on this band.
11185 : *
11186 : * The resulting band is lazy evaluated. A reference is taken on the input
11187 : * dataset.
11188 : *
11189 : * @since 3.12
11190 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11191 : */
11192 : GDALComputedRasterBandH
11193 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11194 : GDALRasterAlgebraUnaryOperation eOp)
11195 : {
11196 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11197 6 : GDALComputedRasterBand::Operation cppOp{};
11198 6 : switch (eOp)
11199 : {
11200 2 : case GRAUO_LOGICAL_NOT:
11201 : return new GDALComputedRasterBand(
11202 : GDALComputedRasterBand::Operation::OP_NE,
11203 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11204 1 : case GRAUO_ABS:
11205 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11206 1 : break;
11207 1 : case GRAUO_SQRT:
11208 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11209 1 : break;
11210 1 : case GRAUO_LOG:
11211 : #ifndef HAVE_MUPARSER
11212 : CPLError(
11213 : CE_Failure, CPLE_NotSupported,
11214 : "log(band) not available on a GDAL build without muparser");
11215 : return nullptr;
11216 : #else
11217 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11218 1 : break;
11219 : #endif
11220 1 : case GRAUO_LOG10:
11221 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11222 1 : break;
11223 : }
11224 : return new GDALComputedRasterBand(cppOp,
11225 4 : *(GDALRasterBand::FromHandle(hBand)));
11226 : }
11227 :
11228 : /************************************************************************/
11229 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11230 : /************************************************************************/
11231 :
11232 : static GDALComputedRasterBand::Operation
11233 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11234 : GDALRasterAlgebraBinaryOperation eOp)
11235 : {
11236 120 : switch (eOp)
11237 : {
11238 26 : case GRABO_ADD:
11239 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11240 2 : case GRABO_SUB:
11241 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11242 24 : case GRABO_MUL:
11243 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11244 3 : case GRABO_DIV:
11245 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11246 6 : case GRABO_GT:
11247 6 : return GDALComputedRasterBand::Operation::OP_GT;
11248 8 : case GRABO_GE:
11249 8 : return GDALComputedRasterBand::Operation::OP_GE;
11250 6 : case GRABO_LT:
11251 6 : return GDALComputedRasterBand::Operation::OP_LT;
11252 6 : case GRABO_LE:
11253 6 : return GDALComputedRasterBand::Operation::OP_LE;
11254 6 : case GRABO_EQ:
11255 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11256 6 : case GRABO_NE:
11257 6 : break;
11258 12 : case GRABO_LOGICAL_AND:
11259 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11260 12 : case GRABO_LOGICAL_OR:
11261 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11262 3 : case GRABO_POW:
11263 3 : return GDALComputedRasterBand::Operation::OP_POW;
11264 : }
11265 6 : return GDALComputedRasterBand::Operation::OP_NE;
11266 : }
11267 :
11268 : /************************************************************************/
11269 : /* GDALRasterBandBinaryOpBand() */
11270 : /************************************************************************/
11271 :
11272 : /** Apply a binary operation on this band with another one.
11273 : *
11274 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11275 : * "hBand1 - hBand2".
11276 : *
11277 : * The resulting band is lazy evaluated. A reference is taken on both input
11278 : * datasets.
11279 : *
11280 : * @since 3.12
11281 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11282 : */
11283 : GDALComputedRasterBandH
11284 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11285 : GDALRasterAlgebraBinaryOperation eOp,
11286 : GDALRasterBandH hOtherBand)
11287 : {
11288 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11289 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11290 : #ifndef HAVE_MUPARSER
11291 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11292 : {
11293 : CPLError(
11294 : CE_Failure, CPLE_NotSupported,
11295 : "Band comparison operators not available on a GDAL build without "
11296 : "muparser");
11297 : return nullptr;
11298 : }
11299 : else if (eOp == GRABO_POW)
11300 : {
11301 : CPLError(
11302 : CE_Failure, CPLE_NotSupported,
11303 : "pow(band, band) not available on a GDAL build without muparser");
11304 : return nullptr;
11305 : }
11306 : #endif
11307 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11308 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11309 : try
11310 : {
11311 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11312 : }
11313 13 : catch (const std::exception &e)
11314 : {
11315 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11316 13 : return nullptr;
11317 : }
11318 : return new GDALComputedRasterBand(
11319 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11320 44 : secondBand);
11321 : }
11322 :
11323 : /************************************************************************/
11324 : /* GDALRasterBandBinaryOpDouble() */
11325 : /************************************************************************/
11326 :
11327 : /** Apply a binary operation on this band with a constant
11328 : *
11329 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11330 : * "hBand - constant".
11331 : *
11332 : * The resulting band is lazy evaluated. A reference is taken on the input
11333 : * dataset.
11334 : *
11335 : * @since 3.12
11336 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11337 : */
11338 : GDALComputedRasterBandH
11339 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11340 : GDALRasterAlgebraBinaryOperation eOp,
11341 : double constant)
11342 : {
11343 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11344 : #ifndef HAVE_MUPARSER
11345 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11346 : {
11347 : CPLError(
11348 : CE_Failure, CPLE_NotSupported,
11349 : "Band comparison operators not available on a GDAL build without "
11350 : "muparser");
11351 : return nullptr;
11352 : }
11353 : #endif
11354 : return new GDALComputedRasterBand(
11355 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11356 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11357 : }
11358 :
11359 : /************************************************************************/
11360 : /* GDALRasterBandBinaryOpDoubleToBand() */
11361 : /************************************************************************/
11362 :
11363 : /** Apply a binary operation on the constant with this band
11364 : *
11365 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11366 : * "constant - hBand".
11367 : *
11368 : * The resulting band is lazy evaluated. A reference is taken on the input
11369 : * dataset.
11370 : *
11371 : * @since 3.12
11372 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11373 : */
11374 : GDALComputedRasterBandH
11375 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11376 : GDALRasterAlgebraBinaryOperation eOp,
11377 : GDALRasterBandH hBand)
11378 : {
11379 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11380 : #ifndef HAVE_MUPARSER
11381 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11382 : {
11383 : CPLError(
11384 : CE_Failure, CPLE_NotSupported,
11385 : "Band comparison operators not available on a GDAL build without "
11386 : "muparser");
11387 : return nullptr;
11388 : }
11389 : #endif
11390 18 : switch (eOp)
11391 : {
11392 15 : case GRABO_ADD:
11393 : case GRABO_MUL:
11394 : {
11395 : return new GDALComputedRasterBand(
11396 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11397 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11398 : }
11399 :
11400 2 : case GRABO_DIV:
11401 : case GRABO_GT:
11402 : case GRABO_GE:
11403 : case GRABO_LT:
11404 : case GRABO_LE:
11405 : case GRABO_EQ:
11406 : case GRABO_NE:
11407 : case GRABO_LOGICAL_AND:
11408 : case GRABO_LOGICAL_OR:
11409 : case GRABO_POW:
11410 : {
11411 : return new GDALComputedRasterBand(
11412 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11413 2 : *(GDALRasterBand::FromHandle(hBand)));
11414 : }
11415 :
11416 1 : case GRABO_SUB:
11417 : {
11418 1 : break;
11419 : }
11420 : }
11421 :
11422 : return new GDALComputedRasterBand(
11423 : GDALComputedRasterBand::Operation::OP_ADD,
11424 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11425 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11426 1 : constant);
11427 : }
11428 :
11429 : /************************************************************************/
11430 : /* operator+() */
11431 : /************************************************************************/
11432 :
11433 : /** Add this band with another one.
11434 : *
11435 : * The resulting band is lazy evaluated. A reference is taken on both input
11436 : * datasets.
11437 : *
11438 : * @since 3.12
11439 : * @throw std::runtime_error if both bands do not have the same dimensions.
11440 : */
11441 : GDALComputedRasterBand
11442 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11443 : {
11444 8 : ThrowIfNotSameDimensions(*this, other);
11445 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11446 7 : *this, other);
11447 : }
11448 :
11449 : /************************************************************************/
11450 : /* operator+() */
11451 : /************************************************************************/
11452 :
11453 : /** Add this band with a constant.
11454 : *
11455 : * The resulting band is lazy evaluated. A reference is taken on the input
11456 : * dataset.
11457 : *
11458 : * @since 3.12
11459 : */
11460 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11461 : {
11462 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11463 13 : *this, constant);
11464 : }
11465 :
11466 : /************************************************************************/
11467 : /* operator+() */
11468 : /************************************************************************/
11469 :
11470 : /** Add a band with a constant.
11471 : *
11472 : * The resulting band is lazy evaluated. A reference is taken on the input
11473 : * dataset.
11474 : *
11475 : * @since 3.12
11476 : */
11477 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11478 : {
11479 1 : return other + constant;
11480 : }
11481 :
11482 : /************************************************************************/
11483 : /* operator-() */
11484 : /************************************************************************/
11485 :
11486 : /** Return a band whose value is the opposite value of the band for each
11487 : * pixel.
11488 : *
11489 : * The resulting band is lazy evaluated. A reference is taken on the input
11490 : * dataset.
11491 : *
11492 : * @since 3.12
11493 : */
11494 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
11495 : {
11496 2 : return 0 - *this;
11497 : }
11498 :
11499 : /************************************************************************/
11500 : /* operator-() */
11501 : /************************************************************************/
11502 :
11503 : /** Subtract this band with another one.
11504 : *
11505 : * The resulting band is lazy evaluated. A reference is taken on both input
11506 : * datasets.
11507 : *
11508 : * @since 3.12
11509 : * @throw std::runtime_error if both bands do not have the same dimensions.
11510 : */
11511 : GDALComputedRasterBand
11512 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
11513 : {
11514 2 : ThrowIfNotSameDimensions(*this, other);
11515 : return GDALComputedRasterBand(
11516 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11517 : }
11518 :
11519 : /************************************************************************/
11520 : /* operator-() */
11521 : /************************************************************************/
11522 :
11523 : /** Subtract this band with a constant.
11524 : *
11525 : * The resulting band is lazy evaluated. A reference is taken on the input
11526 : * dataset.
11527 : *
11528 : * @since 3.12
11529 : */
11530 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11531 : {
11532 : return GDALComputedRasterBand(
11533 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11534 : }
11535 :
11536 : /************************************************************************/
11537 : /* operator-() */
11538 : /************************************************************************/
11539 :
11540 : /** Subtract a constant with a band.
11541 : *
11542 : * The resulting band is lazy evaluated. A reference is taken on the input
11543 : * dataset.
11544 : *
11545 : * @since 3.12
11546 : */
11547 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11548 : {
11549 6 : return other * (-1.0) + constant;
11550 : }
11551 :
11552 : /************************************************************************/
11553 : /* operator*() */
11554 : /************************************************************************/
11555 :
11556 : /** Multiply this band with another one.
11557 : *
11558 : * The resulting band is lazy evaluated. A reference is taken on both input
11559 : * datasets.
11560 : *
11561 : * @since 3.12
11562 : * @throw std::runtime_error if both bands do not have the same dimensions.
11563 : */
11564 : GDALComputedRasterBand
11565 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
11566 : {
11567 2 : ThrowIfNotSameDimensions(*this, other);
11568 : return GDALComputedRasterBand(
11569 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11570 : }
11571 :
11572 : /************************************************************************/
11573 : /* operator*() */
11574 : /************************************************************************/
11575 :
11576 : /** Multiply this band by a constant.
11577 : *
11578 : * The resulting band is lazy evaluated. A reference is taken on the input
11579 : * dataset.
11580 : *
11581 : * @since 3.12
11582 : */
11583 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11584 : {
11585 : return GDALComputedRasterBand(
11586 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11587 : }
11588 :
11589 : /************************************************************************/
11590 : /* operator*() */
11591 : /************************************************************************/
11592 :
11593 : /** Multiply a band with a constant.
11594 : *
11595 : * The resulting band is lazy evaluated. A reference is taken on the input
11596 : * dataset.
11597 : *
11598 : * @since 3.12
11599 : */
11600 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
11601 : {
11602 2 : return other * constant;
11603 : }
11604 :
11605 : /************************************************************************/
11606 : /* operator/() */
11607 : /************************************************************************/
11608 :
11609 : /** Divide this band with another one.
11610 : *
11611 : * The resulting band is lazy evaluated. A reference is taken on both input
11612 : * datasets.
11613 : *
11614 : * @since 3.12
11615 : * @throw std::runtime_error if both bands do not have the same dimensions.
11616 : */
11617 : GDALComputedRasterBand
11618 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
11619 : {
11620 2 : ThrowIfNotSameDimensions(*this, other);
11621 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11622 2 : *this, other);
11623 : }
11624 :
11625 : /************************************************************************/
11626 : /* operator/() */
11627 : /************************************************************************/
11628 :
11629 : /** Divide this band by a constant.
11630 : *
11631 : * The resulting band is lazy evaluated. A reference is taken on the input
11632 : * dataset.
11633 : *
11634 : * @since 3.12
11635 : */
11636 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
11637 : {
11638 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11639 0 : *this, constant);
11640 : }
11641 :
11642 : /************************************************************************/
11643 : /* operator/() */
11644 : /************************************************************************/
11645 :
11646 : /** Divide a constant by a band.
11647 : *
11648 : * The resulting band is lazy evaluated. A reference is taken on the input
11649 : * dataset.
11650 : *
11651 : * @since 3.12
11652 : */
11653 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
11654 : {
11655 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11656 1 : constant, other);
11657 : }
11658 :
11659 : /************************************************************************/
11660 : /* ThrowIfNotMuparser() */
11661 : /************************************************************************/
11662 :
11663 : #ifndef HAVE_MUPARSER
11664 : static GDALComputedRasterBand ThrowIfNotMuparser()
11665 : {
11666 : throw std::runtime_error("Operator not available on a "
11667 : "GDAL build without muparser");
11668 : }
11669 : #endif
11670 :
11671 : /************************************************************************/
11672 : /* operator>() */
11673 : /************************************************************************/
11674 :
11675 : /** Return a band whose value is 1 if the pixel value of the left operand
11676 : * is greater than the pixel value of the right operand.
11677 : *
11678 : * The resulting band is lazy evaluated. A reference is taken on the input
11679 : * dataset.
11680 : *
11681 : * @since 3.12
11682 : */
11683 : GDALComputedRasterBand
11684 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
11685 : {
11686 : #ifndef HAVE_MUPARSER
11687 : (void)other;
11688 : return ThrowIfNotMuparser();
11689 : #else
11690 3 : ThrowIfNotSameDimensions(*this, other);
11691 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11692 2 : *this, other);
11693 : #endif
11694 : }
11695 :
11696 : /************************************************************************/
11697 : /* operator>() */
11698 : /************************************************************************/
11699 :
11700 : /** Return a band whose value is 1 if the pixel value of the left operand
11701 : * is greater than the constant.
11702 : *
11703 : * The resulting band is lazy evaluated. A reference is taken on the input
11704 : * dataset.
11705 : *
11706 : * @since 3.12
11707 : */
11708 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
11709 : {
11710 : #ifndef HAVE_MUPARSER
11711 : (void)constant;
11712 : return ThrowIfNotMuparser();
11713 : #else
11714 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11715 3 : *this, constant);
11716 : #endif
11717 : }
11718 :
11719 : /************************************************************************/
11720 : /* operator>() */
11721 : /************************************************************************/
11722 :
11723 : /** Return a band whose value is 1 if the constant is greater than the pixel
11724 : * value of the right operand.
11725 : *
11726 : * The resulting band is lazy evaluated. A reference is taken on the input
11727 : * dataset.
11728 : *
11729 : * @since 3.12
11730 : */
11731 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
11732 : {
11733 : #ifndef HAVE_MUPARSER
11734 : (void)constant;
11735 : (void)other;
11736 : return ThrowIfNotMuparser();
11737 : #else
11738 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11739 2 : constant, other);
11740 : #endif
11741 : }
11742 :
11743 : /************************************************************************/
11744 : /* operator>=() */
11745 : /************************************************************************/
11746 :
11747 : /** Return a band whose value is 1 if the pixel value of the left operand
11748 : * is greater or equal to the pixel value of the right operand.
11749 : *
11750 : * The resulting band is lazy evaluated. A reference is taken on the input
11751 : * dataset.
11752 : *
11753 : * @since 3.12
11754 : */
11755 : GDALComputedRasterBand
11756 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
11757 : {
11758 : #ifndef HAVE_MUPARSER
11759 : (void)other;
11760 : return ThrowIfNotMuparser();
11761 : #else
11762 4 : ThrowIfNotSameDimensions(*this, other);
11763 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11764 3 : *this, other);
11765 : #endif
11766 : }
11767 :
11768 : /************************************************************************/
11769 : /* operator>=() */
11770 : /************************************************************************/
11771 :
11772 : /** Return a band whose value is 1 if the pixel value of the left operand
11773 : * is greater or equal to the constant.
11774 : *
11775 : * The resulting band is lazy evaluated. A reference is taken on the input
11776 : * dataset.
11777 : *
11778 : * @since 3.12
11779 : */
11780 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
11781 : {
11782 : #ifndef HAVE_MUPARSER
11783 : (void)constant;
11784 : return ThrowIfNotMuparser();
11785 : #else
11786 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11787 3 : *this, constant);
11788 : #endif
11789 : }
11790 :
11791 : /************************************************************************/
11792 : /* operator>=() */
11793 : /************************************************************************/
11794 :
11795 : /** Return a band whose value is 1 if the constant is greater or equal to
11796 : * the pixel value of the right operand.
11797 : *
11798 : * The resulting band is lazy evaluated. A reference is taken on the input
11799 : * dataset.
11800 : *
11801 : * @since 3.12
11802 : */
11803 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
11804 : {
11805 : #ifndef HAVE_MUPARSER
11806 : (void)constant;
11807 : (void)other;
11808 : return ThrowIfNotMuparser();
11809 : #else
11810 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11811 2 : constant, other);
11812 : #endif
11813 : }
11814 :
11815 : /************************************************************************/
11816 : /* operator<() */
11817 : /************************************************************************/
11818 :
11819 : /** Return a band whose value is 1 if the pixel value of the left operand
11820 : * is lesser than the pixel value of the right operand.
11821 : *
11822 : * The resulting band is lazy evaluated. A reference is taken on the input
11823 : * dataset.
11824 : *
11825 : * @since 3.12
11826 : */
11827 : GDALComputedRasterBand
11828 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
11829 : {
11830 : #ifndef HAVE_MUPARSER
11831 : (void)other;
11832 : return ThrowIfNotMuparser();
11833 : #else
11834 3 : ThrowIfNotSameDimensions(*this, other);
11835 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11836 2 : *this, other);
11837 : #endif
11838 : }
11839 :
11840 : /************************************************************************/
11841 : /* operator<() */
11842 : /************************************************************************/
11843 :
11844 : /** Return a band whose value is 1 if the pixel value of the left operand
11845 : * is lesser than the constant.
11846 : *
11847 : * The resulting band is lazy evaluated. A reference is taken on the input
11848 : * dataset.
11849 : *
11850 : * @since 3.12
11851 : */
11852 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11853 : {
11854 : #ifndef HAVE_MUPARSER
11855 : (void)constant;
11856 : return ThrowIfNotMuparser();
11857 : #else
11858 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11859 3 : *this, constant);
11860 : #endif
11861 : }
11862 :
11863 : /************************************************************************/
11864 : /* operator<() */
11865 : /************************************************************************/
11866 :
11867 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11868 : * value of the right operand.
11869 : *
11870 : * The resulting band is lazy evaluated. A reference is taken on the input
11871 : * dataset.
11872 : *
11873 : * @since 3.12
11874 : */
11875 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11876 : {
11877 : #ifndef HAVE_MUPARSER
11878 : (void)constant;
11879 : (void)other;
11880 : return ThrowIfNotMuparser();
11881 : #else
11882 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11883 2 : constant, other);
11884 : #endif
11885 : }
11886 :
11887 : /************************************************************************/
11888 : /* operator<=() */
11889 : /************************************************************************/
11890 :
11891 : /** Return a band whose value is 1 if the pixel value of the left operand
11892 : * is lesser or equal to the pixel value of the right operand.
11893 : *
11894 : * The resulting band is lazy evaluated. A reference is taken on the input
11895 : * dataset.
11896 : *
11897 : * @since 3.12
11898 : */
11899 : GDALComputedRasterBand
11900 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11901 : {
11902 : #ifndef HAVE_MUPARSER
11903 : (void)other;
11904 : return ThrowIfNotMuparser();
11905 : #else
11906 4 : ThrowIfNotSameDimensions(*this, other);
11907 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11908 3 : *this, other);
11909 : #endif
11910 : }
11911 :
11912 : /************************************************************************/
11913 : /* operator<=() */
11914 : /************************************************************************/
11915 :
11916 : /** Return a band whose value is 1 if the pixel value of the left operand
11917 : * is lesser or equal to the constant.
11918 : *
11919 : * The resulting band is lazy evaluated. A reference is taken on the input
11920 : * dataset.
11921 : *
11922 : * @since 3.12
11923 : */
11924 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11925 : {
11926 : #ifndef HAVE_MUPARSER
11927 : (void)constant;
11928 : return ThrowIfNotMuparser();
11929 : #else
11930 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11931 3 : *this, constant);
11932 : #endif
11933 : }
11934 :
11935 : /************************************************************************/
11936 : /* operator<=() */
11937 : /************************************************************************/
11938 :
11939 : /** Return a band whose value is 1 if the constant is lesser or equal to
11940 : * the pixel value of the right operand.
11941 : *
11942 : * The resulting band is lazy evaluated. A reference is taken on the input
11943 : * dataset.
11944 : *
11945 : * @since 3.12
11946 : */
11947 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11948 : {
11949 : #ifndef HAVE_MUPARSER
11950 : (void)constant;
11951 : (void)other;
11952 : return ThrowIfNotMuparser();
11953 : #else
11954 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11955 2 : constant, other);
11956 : #endif
11957 : }
11958 :
11959 : /************************************************************************/
11960 : /* operator==() */
11961 : /************************************************************************/
11962 :
11963 : /** Return a band whose value is 1 if the pixel value of the left operand
11964 : * is equal to the pixel value of the right operand.
11965 : *
11966 : * The resulting band is lazy evaluated. A reference is taken on the input
11967 : * dataset.
11968 : *
11969 : * @since 3.12
11970 : */
11971 : GDALComputedRasterBand
11972 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11973 : {
11974 : #ifndef HAVE_MUPARSER
11975 : (void)other;
11976 : return ThrowIfNotMuparser();
11977 : #else
11978 3 : ThrowIfNotSameDimensions(*this, other);
11979 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11980 2 : *this, other);
11981 : #endif
11982 : }
11983 :
11984 : /************************************************************************/
11985 : /* operator==() */
11986 : /************************************************************************/
11987 :
11988 : /** Return a band whose value is 1 if the pixel value of the left operand
11989 : * is equal to the constant.
11990 : *
11991 : * The resulting band is lazy evaluated. A reference is taken on the input
11992 : * dataset.
11993 : *
11994 : * @since 3.12
11995 : */
11996 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11997 : {
11998 : #ifndef HAVE_MUPARSER
11999 : (void)constant;
12000 : return ThrowIfNotMuparser();
12001 : #else
12002 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12003 8 : *this, constant);
12004 : #endif
12005 : }
12006 :
12007 : /************************************************************************/
12008 : /* operator==() */
12009 : /************************************************************************/
12010 :
12011 : /** Return a band whose value is 1 if the constant is equal to
12012 : * the pixel value of the right operand.
12013 : *
12014 : * The resulting band is lazy evaluated. A reference is taken on the input
12015 : * dataset.
12016 : *
12017 : * @since 3.12
12018 : */
12019 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12020 : {
12021 : #ifndef HAVE_MUPARSER
12022 : (void)constant;
12023 : (void)other;
12024 : return ThrowIfNotMuparser();
12025 : #else
12026 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12027 2 : constant, other);
12028 : #endif
12029 : }
12030 :
12031 : /************************************************************************/
12032 : /* operator!=() */
12033 : /************************************************************************/
12034 :
12035 : /** Return a band whose value is 1 if the pixel value of the left operand
12036 : * is different from the pixel value of the right operand.
12037 : *
12038 : * The resulting band is lazy evaluated. A reference is taken on the input
12039 : * dataset.
12040 : *
12041 : * @since 3.12
12042 : */
12043 : GDALComputedRasterBand
12044 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12045 : {
12046 : #ifndef HAVE_MUPARSER
12047 : (void)other;
12048 : return ThrowIfNotMuparser();
12049 : #else
12050 3 : ThrowIfNotSameDimensions(*this, other);
12051 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12052 2 : *this, other);
12053 : #endif
12054 : }
12055 :
12056 : /************************************************************************/
12057 : /* operator!=() */
12058 : /************************************************************************/
12059 :
12060 : /** Return a band whose value is 1 if the pixel value of the left operand
12061 : * is different from the constant.
12062 : *
12063 : * The resulting band is lazy evaluated. A reference is taken on the input
12064 : * dataset.
12065 : *
12066 : * @since 3.12
12067 : */
12068 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12069 : {
12070 : #ifndef HAVE_MUPARSER
12071 : (void)constant;
12072 : return ThrowIfNotMuparser();
12073 : #else
12074 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12075 6 : *this, constant);
12076 : #endif
12077 : }
12078 :
12079 : /************************************************************************/
12080 : /* operator!=() */
12081 : /************************************************************************/
12082 :
12083 : /** Return a band whose value is 1 if the constant is different from
12084 : * the pixel value of the right operand.
12085 : *
12086 : * The resulting band is lazy evaluated. A reference is taken on the input
12087 : * dataset.
12088 : *
12089 : * @since 3.12
12090 : */
12091 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12092 : {
12093 : #ifndef HAVE_MUPARSER
12094 : (void)constant;
12095 : (void)other;
12096 : return ThrowIfNotMuparser();
12097 : #else
12098 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12099 2 : constant, other);
12100 : #endif
12101 : }
12102 :
12103 : #if defined(__GNUC__)
12104 : #pragma GCC diagnostic push
12105 : #pragma GCC diagnostic ignored "-Weffc++"
12106 : #endif
12107 :
12108 : /************************************************************************/
12109 : /* operator&&() */
12110 : /************************************************************************/
12111 :
12112 : /** Return a band whose value is 1 if the pixel value of the left and right
12113 : * operands is true.
12114 : *
12115 : * The resulting band is lazy evaluated. A reference is taken on the input
12116 : * dataset.
12117 : *
12118 : * @since 3.12
12119 : */
12120 : GDALComputedRasterBand
12121 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12122 : {
12123 : #ifndef HAVE_MUPARSER
12124 : (void)other;
12125 : return ThrowIfNotMuparser();
12126 : #else
12127 3 : ThrowIfNotSameDimensions(*this, other);
12128 : return GDALComputedRasterBand(
12129 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12130 : #endif
12131 : }
12132 :
12133 : /************************************************************************/
12134 : /* operator&&() */
12135 : /************************************************************************/
12136 :
12137 : /** Return a band whose value is 1 if the pixel value of the left operand
12138 : * is true, as well as the constant
12139 : *
12140 : * The resulting band is lazy evaluated. A reference is taken on the input
12141 : * dataset.
12142 : *
12143 : * @since 3.12
12144 : */
12145 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12146 : {
12147 : #ifndef HAVE_MUPARSER
12148 : (void)constant;
12149 : return ThrowIfNotMuparser();
12150 : #else
12151 : return GDALComputedRasterBand(
12152 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12153 : #endif
12154 : }
12155 :
12156 : /************************************************************************/
12157 : /* operator&&() */
12158 : /************************************************************************/
12159 :
12160 : /** Return a band whose value is 1 if the constant is true, as well as
12161 : * the pixel value of the right operand.
12162 : *
12163 : * The resulting band is lazy evaluated. A reference is taken on the input
12164 : * dataset.
12165 : *
12166 : * @since 3.12
12167 : */
12168 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12169 : {
12170 : #ifndef HAVE_MUPARSER
12171 : (void)constant;
12172 : (void)other;
12173 : return ThrowIfNotMuparser();
12174 : #else
12175 : return GDALComputedRasterBand(
12176 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12177 : #endif
12178 : }
12179 :
12180 : /************************************************************************/
12181 : /* operator||() */
12182 : /************************************************************************/
12183 :
12184 : /** Return a band whose value is 1 if the pixel value of the left or right
12185 : * operands is true.
12186 : *
12187 : * The resulting band is lazy evaluated. A reference is taken on the input
12188 : * dataset.
12189 : *
12190 : * @since 3.12
12191 : */
12192 : GDALComputedRasterBand
12193 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12194 : {
12195 : #ifndef HAVE_MUPARSER
12196 : (void)other;
12197 : return ThrowIfNotMuparser();
12198 : #else
12199 4 : ThrowIfNotSameDimensions(*this, other);
12200 : return GDALComputedRasterBand(
12201 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12202 : #endif
12203 : }
12204 :
12205 : /************************************************************************/
12206 : /* operator||() */
12207 : /************************************************************************/
12208 :
12209 : /** Return a band whose value is 1 if the pixel value of the left operand
12210 : * is true, or if the constant is true
12211 : *
12212 : * The resulting band is lazy evaluated. A reference is taken on the input
12213 : * dataset.
12214 : *
12215 : * @since 3.12
12216 : */
12217 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12218 : {
12219 : #ifndef HAVE_MUPARSER
12220 : (void)constant;
12221 : return ThrowIfNotMuparser();
12222 : #else
12223 : return GDALComputedRasterBand(
12224 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12225 : #endif
12226 : }
12227 :
12228 : /************************************************************************/
12229 : /* operator||() */
12230 : /************************************************************************/
12231 :
12232 : /** Return a band whose value is 1 if the constant is true, or
12233 : * the pixel value of the right operand is true
12234 : *
12235 : * The resulting band is lazy evaluated. A reference is taken on the input
12236 : * dataset.
12237 : *
12238 : * @since 3.12
12239 : */
12240 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12241 : {
12242 : #ifndef HAVE_MUPARSER
12243 : (void)constant;
12244 : (void)other;
12245 : return ThrowIfNotMuparser();
12246 : #else
12247 : return GDALComputedRasterBand(
12248 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12249 : #endif
12250 : }
12251 :
12252 : #if defined(__GNUC__)
12253 : #pragma GCC diagnostic pop
12254 : #endif
12255 :
12256 : /************************************************************************/
12257 : /* operator!() */
12258 : /************************************************************************/
12259 :
12260 : /** Return a band whose value is the logical negation of the pixel value
12261 : *
12262 : * The resulting band is lazy evaluated. A reference is taken on the input
12263 : * dataset.
12264 : *
12265 : * @since 3.12
12266 : */
12267 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12268 : {
12269 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12270 2 : *this, true);
12271 : }
12272 :
12273 : namespace gdal
12274 : {
12275 :
12276 : /************************************************************************/
12277 : /* IfThenElse() */
12278 : /************************************************************************/
12279 :
12280 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12281 : * is not zero, or the one from elseBand otherwise.
12282 : *
12283 : * Variants of this method exits where thenBand and/or elseBand can be double
12284 : * values.
12285 : *
12286 : * The resulting band is lazy evaluated. A reference is taken on the input
12287 : * datasets.
12288 : *
12289 : * This method is the same as the C function GDALRasterBandIfThenElse()
12290 : *
12291 : * @since 3.12
12292 : */
12293 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12294 : const GDALRasterBand &thenBand,
12295 : const GDALRasterBand &elseBand)
12296 : {
12297 : #ifndef HAVE_MUPARSER
12298 : (void)condBand;
12299 : (void)thenBand;
12300 : (void)elseBand;
12301 : return ThrowIfNotMuparser();
12302 : #else
12303 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12304 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12305 : return GDALComputedRasterBand(
12306 : GDALComputedRasterBand::Operation::OP_TERNARY,
12307 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12308 : #endif
12309 : }
12310 :
12311 : //! @cond Doxygen_Suppress
12312 :
12313 : /************************************************************************/
12314 : /* IfThenElse() */
12315 : /************************************************************************/
12316 :
12317 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12318 : * is not zero, or the one from elseBand otherwise.
12319 : *
12320 : * The resulting band is lazy evaluated. A reference is taken on the input
12321 : * datasets.
12322 : *
12323 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12324 : * with thenBand = (condBand * 0) + thenValue
12325 : *
12326 : * @since 3.12
12327 : */
12328 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12329 : double thenValue,
12330 : const GDALRasterBand &elseBand)
12331 : {
12332 : #ifndef HAVE_MUPARSER
12333 : (void)condBand;
12334 : (void)thenValue;
12335 : (void)elseBand;
12336 : return ThrowIfNotMuparser();
12337 : #else
12338 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12339 : auto thenBand =
12340 1 : (condBand * 0)
12341 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12342 1 : thenValue;
12343 : return GDALComputedRasterBand(
12344 : GDALComputedRasterBand::Operation::OP_TERNARY,
12345 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12346 : #endif
12347 : }
12348 :
12349 : /************************************************************************/
12350 : /* IfThenElse() */
12351 : /************************************************************************/
12352 :
12353 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12354 : * is not zero, or the one from elseValue otherwise.
12355 : *
12356 : * The resulting band is lazy evaluated. A reference is taken on the input
12357 : * datasets.
12358 : *
12359 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12360 : * with elseBand = (condBand * 0) + elseValue
12361 :
12362 : * @since 3.12
12363 : */
12364 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12365 : const GDALRasterBand &thenBand,
12366 : double elseValue)
12367 : {
12368 : #ifndef HAVE_MUPARSER
12369 : (void)condBand;
12370 : (void)thenBand;
12371 : (void)elseValue;
12372 : return ThrowIfNotMuparser();
12373 : #else
12374 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12375 : auto elseBand =
12376 1 : (condBand * 0)
12377 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12378 1 : elseValue;
12379 : return GDALComputedRasterBand(
12380 : GDALComputedRasterBand::Operation::OP_TERNARY,
12381 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12382 : #endif
12383 : }
12384 :
12385 : /************************************************************************/
12386 : /* IfThenElse() */
12387 : /************************************************************************/
12388 :
12389 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12390 : * is not zero, or the one from elseValue otherwise.
12391 : *
12392 : * The resulting band is lazy evaluated. A reference is taken on the input
12393 : * datasets.
12394 : *
12395 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12396 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12397 : *
12398 : * @since 3.12
12399 : */
12400 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12401 : double thenValue, double elseValue)
12402 : {
12403 : #ifndef HAVE_MUPARSER
12404 : (void)condBand;
12405 : (void)thenValue;
12406 : (void)elseValue;
12407 : return ThrowIfNotMuparser();
12408 : #else
12409 : auto thenBand =
12410 3 : (condBand * 0)
12411 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12412 6 : thenValue;
12413 : auto elseBand =
12414 3 : (condBand * 0)
12415 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12416 3 : elseValue;
12417 : return GDALComputedRasterBand(
12418 : GDALComputedRasterBand::Operation::OP_TERNARY,
12419 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12420 : #endif
12421 : }
12422 :
12423 : //! @endcond
12424 :
12425 : } // namespace gdal
12426 :
12427 : /************************************************************************/
12428 : /* GDALRasterBandIfThenElse() */
12429 : /************************************************************************/
12430 :
12431 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12432 : * is not zero, or the one from hElseBand otherwise.
12433 : *
12434 : * The resulting band is lazy evaluated. A reference is taken on the input
12435 : * datasets.
12436 : *
12437 : * This function is the same as the C++ method gdal::IfThenElse()
12438 : *
12439 : * @since 3.12
12440 : */
12441 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12442 : GDALRasterBandH hThenBand,
12443 : GDALRasterBandH hElseBand)
12444 : {
12445 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12446 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12447 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12448 : #ifndef HAVE_MUPARSER
12449 : CPLError(CE_Failure, CPLE_NotSupported,
12450 : "Band comparison operators not available on a GDAL build without "
12451 : "muparser");
12452 : return nullptr;
12453 : #else
12454 :
12455 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12456 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12457 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12458 : try
12459 : {
12460 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12461 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12462 : }
12463 2 : catch (const std::exception &e)
12464 : {
12465 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12466 2 : return nullptr;
12467 : }
12468 : return new GDALComputedRasterBand(
12469 : GDALComputedRasterBand::Operation::OP_TERNARY,
12470 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12471 : #endif
12472 : }
12473 :
12474 : /************************************************************************/
12475 : /* GDALRasterBand::AsType() */
12476 : /************************************************************************/
12477 :
12478 : /** Cast this band to another type.
12479 : *
12480 : * The resulting band is lazy evaluated. A reference is taken on the input
12481 : * dataset.
12482 : *
12483 : * This method is the same as the C function GDALRasterBandAsDataType()
12484 : *
12485 : * @since 3.12
12486 : */
12487 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12488 : {
12489 10 : if (dt == GDT_Unknown)
12490 : {
12491 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12492 : }
12493 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12494 9 : *this, dt);
12495 : }
12496 :
12497 : /************************************************************************/
12498 : /* GDALRasterBandAsDataType() */
12499 : /************************************************************************/
12500 :
12501 : /** Cast this band to another type.
12502 : *
12503 : * The resulting band is lazy evaluated. A reference is taken on the input
12504 : * dataset.
12505 : *
12506 : * This function is the same as the C++ method GDALRasterBand::AsType()
12507 : *
12508 : * @since 3.12
12509 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12510 : */
12511 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12512 : GDALDataType eDT)
12513 : {
12514 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
12515 16 : if (eDT == GDT_Unknown)
12516 : {
12517 1 : CPLError(CE_Failure, CPLE_NotSupported,
12518 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12519 1 : return nullptr;
12520 : }
12521 : return new GDALComputedRasterBand(
12522 : GDALComputedRasterBand::Operation::OP_CAST,
12523 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
12524 : }
12525 :
12526 : /************************************************************************/
12527 : /* GetBandVector() */
12528 : /************************************************************************/
12529 :
12530 : static std::vector<const GDALRasterBand *>
12531 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12532 : {
12533 10 : std::vector<const GDALRasterBand *> bands;
12534 27 : for (size_t i = 0; i < nBandCount; ++i)
12535 : {
12536 20 : if (i > 0)
12537 : {
12538 10 : GDALRasterBand::ThrowIfNotSameDimensions(
12539 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
12540 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
12541 : }
12542 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12543 : }
12544 7 : return bands;
12545 : }
12546 :
12547 : /************************************************************************/
12548 : /* GDALOperationOnNBands() */
12549 : /************************************************************************/
12550 :
12551 : static GDALComputedRasterBandH
12552 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12553 : GDALRasterBandH *pahBands)
12554 : {
12555 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
12556 11 : if (nBandCount == 0)
12557 : {
12558 1 : CPLError(CE_Failure, CPLE_AppDefined,
12559 : "At least one band should be passed");
12560 1 : return nullptr;
12561 : }
12562 :
12563 20 : std::vector<const GDALRasterBand *> bands;
12564 : try
12565 : {
12566 10 : bands = GetBandVector(nBandCount, pahBands);
12567 : }
12568 3 : catch (const std::exception &e)
12569 : {
12570 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12571 3 : return nullptr;
12572 : }
12573 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12574 : }
12575 :
12576 : /************************************************************************/
12577 : /* GDALMaximumOfNBands() */
12578 : /************************************************************************/
12579 :
12580 : /** Return a band whose each pixel value is the maximum of the corresponding
12581 : * pixel values in the input bands.
12582 : *
12583 : * The resulting band is lazy evaluated. A reference is taken on input
12584 : * datasets.
12585 : *
12586 : * This function is the same as the C ++ method gdal::max()
12587 : *
12588 : * @since 3.12
12589 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12590 : */
12591 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12592 : GDALRasterBandH *pahBands)
12593 : {
12594 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12595 4 : nBandCount, pahBands);
12596 : }
12597 :
12598 : /************************************************************************/
12599 : /* gdal::max() */
12600 : /************************************************************************/
12601 :
12602 : namespace gdal
12603 : {
12604 : /** Return a band whose each pixel value is the maximum of the corresponding
12605 : * pixel values in the inputs (bands or constants)
12606 : *
12607 : * The resulting band is lazy evaluated. A reference is taken on input
12608 : * datasets.
12609 : *
12610 : * Two or more bands can be passed.
12611 : *
12612 : * This method is the same as the C function GDALMaximumOfNBands()
12613 : *
12614 : * @since 3.12
12615 : * @throw std::runtime_error if bands do not have the same dimensions.
12616 : */
12617 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
12618 : const GDALRasterBand &second)
12619 : {
12620 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12621 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
12622 1 : first, second);
12623 : }
12624 : } // namespace gdal
12625 :
12626 : /************************************************************************/
12627 : /* GDALRasterBandMaxConstant() */
12628 : /************************************************************************/
12629 :
12630 : /** Return a band whose each pixel value is the maximum of the corresponding
12631 : * pixel values in the input band and the constant.
12632 : *
12633 : * The resulting band is lazy evaluated. A reference is taken on the input
12634 : * dataset.
12635 : *
12636 : * This function is the same as the C ++ method gdal::max()
12637 : *
12638 : * @since 3.12
12639 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12640 : */
12641 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
12642 : double dfConstant)
12643 : {
12644 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12645 : GDALComputedRasterBand::Operation::OP_MAX,
12646 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12647 6 : dfConstant));
12648 : }
12649 :
12650 : /************************************************************************/
12651 : /* GDALMinimumOfNBands() */
12652 : /************************************************************************/
12653 :
12654 : /** Return a band whose each pixel value is the minimum of the corresponding
12655 : * pixel values in the input bands.
12656 : *
12657 : * The resulting band is lazy evaluated. A reference is taken on input
12658 : * datasets.
12659 : *
12660 : * This function is the same as the C ++ method gdal::min()
12661 : *
12662 : * @since 3.12
12663 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12664 : */
12665 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
12666 : GDALRasterBandH *pahBands)
12667 : {
12668 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
12669 4 : nBandCount, pahBands);
12670 : }
12671 :
12672 : /************************************************************************/
12673 : /* gdal::min() */
12674 : /************************************************************************/
12675 :
12676 : namespace gdal
12677 : {
12678 : /** Return a band whose each pixel value is the minimum of the corresponding
12679 : * pixel values in the inputs (bands or constants)
12680 : *
12681 : * The resulting band is lazy evaluated. A reference is taken on input
12682 : * datasets.
12683 : *
12684 : * Two or more bands can be passed.
12685 : *
12686 : * This method is the same as the C function GDALMinimumOfNBands()
12687 : *
12688 : * @since 3.12
12689 : * @throw std::runtime_error if bands do not have the same dimensions.
12690 : */
12691 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
12692 : const GDALRasterBand &second)
12693 : {
12694 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12695 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
12696 0 : first, second);
12697 : }
12698 : } // namespace gdal
12699 :
12700 : /************************************************************************/
12701 : /* GDALRasterBandMinConstant() */
12702 : /************************************************************************/
12703 :
12704 : /** Return a band whose each pixel value is the minimum of the corresponding
12705 : * pixel values in the input band and the constant.
12706 : *
12707 : * The resulting band is lazy evaluated. A reference is taken on the input
12708 : * dataset.
12709 : *
12710 : * This function is the same as the C ++ method gdal::min()
12711 : *
12712 : * @since 3.12
12713 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12714 : */
12715 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
12716 : double dfConstant)
12717 : {
12718 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12719 : GDALComputedRasterBand::Operation::OP_MIN,
12720 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12721 6 : dfConstant));
12722 : }
12723 :
12724 : /************************************************************************/
12725 : /* GDALMeanOfNBands() */
12726 : /************************************************************************/
12727 :
12728 : /** Return a band whose each pixel value is the arithmetic mean of the
12729 : * corresponding pixel values in the input bands.
12730 : *
12731 : * The resulting band is lazy evaluated. A reference is taken on input
12732 : * datasets.
12733 : *
12734 : * This function is the same as the C ++ method gdal::mean()
12735 : *
12736 : * @since 3.12
12737 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12738 : */
12739 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
12740 : GDALRasterBandH *pahBands)
12741 : {
12742 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
12743 3 : nBandCount, pahBands);
12744 : }
12745 :
12746 : /************************************************************************/
12747 : /* gdal::mean() */
12748 : /************************************************************************/
12749 :
12750 : namespace gdal
12751 : {
12752 :
12753 : /** Return a band whose each pixel value is the arithmetic mean of the
12754 : * corresponding pixel values in the input bands.
12755 : *
12756 : * The resulting band is lazy evaluated. A reference is taken on input
12757 : * datasets.
12758 : *
12759 : * Two or more bands can be passed.
12760 : *
12761 : * This method is the same as the C function GDALMeanOfNBands()
12762 : *
12763 : * @since 3.12
12764 : * @throw std::runtime_error if bands do not have the same dimensions.
12765 : */
12766 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
12767 : const GDALRasterBand &second)
12768 : {
12769 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12770 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
12771 0 : first, second);
12772 : }
12773 : } // namespace gdal
12774 :
12775 : /************************************************************************/
12776 : /* gdal::abs() */
12777 : /************************************************************************/
12778 :
12779 : namespace gdal
12780 : {
12781 :
12782 : /** Return a band whose each pixel value is the absolute value (or module
12783 : * for complex data type) of the corresponding pixel value in the input band.
12784 : *
12785 : * The resulting band is lazy evaluated. A reference is taken on input
12786 : * datasets.
12787 : *
12788 : * @since 3.12
12789 : */
12790 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
12791 : {
12792 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12793 1 : band);
12794 : }
12795 : } // namespace gdal
12796 :
12797 : /************************************************************************/
12798 : /* gdal::fabs() */
12799 : /************************************************************************/
12800 :
12801 : namespace gdal
12802 : {
12803 :
12804 : /** Return a band whose each pixel value is the absolute value (or module
12805 : * for complex data type) of the corresponding pixel value in the input band.
12806 : *
12807 : * The resulting band is lazy evaluated. A reference is taken on input
12808 : * datasets.
12809 : *
12810 : * @since 3.12
12811 : */
12812 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
12813 : {
12814 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12815 1 : band);
12816 : }
12817 : } // namespace gdal
12818 :
12819 : /************************************************************************/
12820 : /* gdal::sqrt() */
12821 : /************************************************************************/
12822 :
12823 : namespace gdal
12824 : {
12825 :
12826 : /** Return a band whose each pixel value is the square root of the
12827 : * corresponding pixel value in the input band.
12828 : *
12829 : * The resulting band is lazy evaluated. A reference is taken on input
12830 : * datasets.
12831 : *
12832 : * @since 3.12
12833 : */
12834 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12835 : {
12836 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12837 1 : band);
12838 : }
12839 : } // namespace gdal
12840 :
12841 : /************************************************************************/
12842 : /* gdal::log() */
12843 : /************************************************************************/
12844 :
12845 : namespace gdal
12846 : {
12847 :
12848 : /** Return a band whose each pixel value is the natural logarithm of the
12849 : * corresponding pixel value in the input band.
12850 : *
12851 : * The resulting band is lazy evaluated. A reference is taken on input
12852 : * datasets.
12853 : *
12854 : * @since 3.12
12855 : */
12856 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12857 : {
12858 : #ifndef HAVE_MUPARSER
12859 : (void)band;
12860 : return ThrowIfNotMuparser();
12861 : #else
12862 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12863 1 : band);
12864 : #endif
12865 : }
12866 : } // namespace gdal
12867 :
12868 : /************************************************************************/
12869 : /* gdal::log10() */
12870 : /************************************************************************/
12871 :
12872 : namespace gdal
12873 : {
12874 :
12875 : /** Return a band whose each pixel value is the logarithm base 10 of the
12876 : * corresponding pixel value in the input band.
12877 : *
12878 : * The resulting band is lazy evaluated. A reference is taken on input
12879 : * datasets.
12880 : *
12881 : * @since 3.12
12882 : */
12883 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12884 : {
12885 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12886 1 : band);
12887 : }
12888 : } // namespace gdal
12889 :
12890 : /************************************************************************/
12891 : /* gdal::pow() */
12892 : /************************************************************************/
12893 :
12894 : namespace gdal
12895 : {
12896 :
12897 : #ifndef DOXYGEN_SKIP
12898 : /** Return a band whose each pixel value is the constant raised to the power of
12899 : * the corresponding pixel value in the input band.
12900 : *
12901 : * The resulting band is lazy evaluated. A reference is taken on input
12902 : * datasets.
12903 : *
12904 : * @since 3.12
12905 : */
12906 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12907 : {
12908 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12909 1 : constant, band);
12910 : }
12911 : #endif
12912 :
12913 : } // namespace gdal
12914 :
12915 : /************************************************************************/
12916 : /* gdal::pow() */
12917 : /************************************************************************/
12918 :
12919 : namespace gdal
12920 : {
12921 :
12922 : /** Return a band whose each pixel value is the the corresponding pixel value
12923 : * in the input band raised to the power of the constant.
12924 : *
12925 : * The resulting band is lazy evaluated. A reference is taken on input
12926 : * datasets.
12927 : *
12928 : * @since 3.12
12929 : */
12930 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12931 : {
12932 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12933 1 : band, constant);
12934 : }
12935 : } // namespace gdal
12936 :
12937 : /************************************************************************/
12938 : /* gdal::pow() */
12939 : /************************************************************************/
12940 :
12941 : namespace gdal
12942 : {
12943 :
12944 : #ifndef DOXYGEN_SKIP
12945 : /** Return a band whose each pixel value is the the corresponding pixel value
12946 : * in the input band1 raised to the power of the corresponding pixel value
12947 : * in the input band2
12948 : *
12949 : * The resulting band is lazy evaluated. A reference is taken on input
12950 : * datasets.
12951 : *
12952 : * @since 3.12
12953 : * @throw std::runtime_error if bands do not have the same dimensions.
12954 : */
12955 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12956 : const GDALRasterBand &band2)
12957 : {
12958 : #ifndef HAVE_MUPARSER
12959 : (void)band1;
12960 : (void)band2;
12961 : return ThrowIfNotMuparser();
12962 : #else
12963 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12964 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12965 1 : band1, band2);
12966 : #endif
12967 : }
12968 : #endif
12969 : } // namespace gdal
|