Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "cpl_float.h"
17 :
18 : #include <algorithm>
19 : #include <cassert>
20 : #include <climits>
21 : #include <cmath>
22 : #include <cstdarg>
23 : #include <cstddef>
24 : #include <cstdio>
25 : #include <cstdlib>
26 : #include <cstring>
27 : #include <limits>
28 : #include <memory>
29 : #include <new>
30 : #include <numeric> // std::lcm
31 : #include <type_traits>
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_float.h"
36 : #include "cpl_multiproc.h"
37 : #include "cpl_progress.h"
38 : #include "cpl_string.h"
39 : #include "cpl_virtualmem.h"
40 : #include "cpl_vsi.h"
41 : #include "cpl_worker_thread_pool.h"
42 : #include "gdal.h"
43 : #include "gdal_abstractbandblockcache.h"
44 : #include "gdalantirecursion.h"
45 : #include "gdal_rat.h"
46 : #include "gdal_rasterband.h"
47 : #include "gdal_priv_templates.hpp"
48 : #include "gdal_interpolateatpoint.h"
49 : #include "gdal_minmax_element.hpp"
50 : #include "gdalmultidim_priv.h"
51 : #include "gdal_thread_pool.h"
52 :
53 : #ifdef USE_NEON_OPTIMIZATIONS
54 : #include "include_sse2neon.h"
55 : #endif
56 :
57 : #if defined(__AVX2__) || defined(__FMA__)
58 : #include <immintrin.h>
59 : #endif
60 :
61 : /************************************************************************/
62 : /* GDALRasterBand() */
63 : /************************************************************************/
64 :
65 : /*! Constructor. Applications should never create GDALRasterBands directly. */
66 :
67 1578780 : GDALRasterBand::GDALRasterBand()
68 : : GDALRasterBand(
69 1578780 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
70 : {
71 1578780 : }
72 :
73 : /** Constructor. Applications should never create GDALRasterBands directly.
74 : * @param bForceCachedIOIn Whether cached IO should be forced.
75 : */
76 1870890 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
77 1870890 : : bForceCachedIO(bForceCachedIOIn)
78 :
79 : {
80 1870890 : }
81 :
82 : /************************************************************************/
83 : /* ~GDALRasterBand() */
84 : /************************************************************************/
85 :
86 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
87 : instead destroy the GDALDataset. */
88 :
89 1870890 : GDALRasterBand::~GDALRasterBand()
90 :
91 : {
92 1870890 : if (poDS && poDS->IsMarkedSuppressOnClose())
93 : {
94 593 : if (poBandBlockCache)
95 530 : poBandBlockCache->DisableDirtyBlockWriting();
96 : }
97 1870890 : GDALRasterBand::FlushCache(true);
98 :
99 1870890 : delete poBandBlockCache;
100 :
101 1870890 : if (static_cast<GIntBig>(nBlockReads) >
102 1870890 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
103 244 : nBand == 1 && poDS != nullptr)
104 : {
105 350 : CPLDebug(
106 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
107 175 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
108 175 : poDS->GetDescription());
109 : }
110 :
111 1870890 : InvalidateMaskBand();
112 1870890 : nBand = -nBand;
113 :
114 1870890 : delete m_poPointsCache;
115 1870890 : }
116 :
117 : /************************************************************************/
118 : /* RasterIO() */
119 : /************************************************************************/
120 :
121 : /**
122 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
123 : * int nXOff, int nYOff, int nXSize, int nYSize,
124 : * void * pData, int nBufXSize, int nBufYSize,
125 : * GDALDataType eBufType,
126 : * GSpacing nPixelSpace,
127 : * GSpacing nLineSpace,
128 : * GDALRasterIOExtraArg* psExtraArg )
129 : * \brief Read/write a region of image data for this band.
130 : *
131 : * This method allows reading a region of a GDALRasterBand into a buffer,
132 : * or writing data from a buffer into a region of a GDALRasterBand. It
133 : * automatically takes care of data type translation if the data type
134 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
135 : * The method also takes care of image decimation / replication if the
136 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
137 : * region being accessed (nXSize x nYSize).
138 : *
139 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
140 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
141 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
142 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
143 : * Or use nLineSpace and a possibly shifted pData value.
144 : *
145 : * The nPixelSpace and nLineSpace parameters allow reading into or
146 : * writing from unusually organized buffers. This is primarily used
147 : * for buffers containing more than one bands raster data in interleaved
148 : * format.
149 : *
150 : * Some formats may efficiently implement decimation into a buffer by
151 : * reading from lower resolution overview images. The logic of the default
152 : * implementation in the base class GDALRasterBand is the following one. It
153 : * computes a target_downscaling_factor from the window of interest and buffer
154 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
155 : * It then walks through overviews and will select the first one whose
156 : * downscaling factor is greater than target_downscaling_factor / 1.2.
157 : *
158 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
159 : * The relationship between target_downscaling_factor and the select overview
160 : * level is the following one:
161 : *
162 : * target_downscaling_factor | selected_overview
163 : * ------------------------- | -----------------
164 : * ]0, 2 / 1.2] | full resolution band
165 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
166 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
167 : * ]8 / 1.2, infinity[ | 8x downsampled band
168 : *
169 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
170 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
171 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
172 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
173 : * this oversampling threshold defaults to 1. Consequently if there are overviews
174 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
175 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
176 : *
177 : * For highest performance full resolution data access, read and write
178 : * on "block boundaries" as returned by GetBlockSize(), or use the
179 : * ReadBlock() and WriteBlock() methods.
180 : *
181 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
182 : * functions.
183 : *
184 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
185 : * write a region of data.
186 : *
187 : * @param nXOff The pixel offset to the top left corner of the region
188 : * of the band to be accessed. This would be zero to start from the left side.
189 : *
190 : * @param nYOff The line offset to the top left corner of the region
191 : * of the band to be accessed. This would be zero to start from the top.
192 : *
193 : * @param nXSize The width of the region of the band to be accessed in pixels.
194 : *
195 : * @param nYSize The height of the region of the band to be accessed in lines.
196 : *
197 : * @param pData The buffer into which the data should be read, or from which
198 : * it should be written. This buffer must contain at least nBufXSize *
199 : * nBufYSize words of type eBufType. It is organized in left to right,
200 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
201 : * and nLineSpace parameters.
202 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
203 : * temporarily modified during the execution of this method (and eventually
204 : * restored back to its original content), so it is not safe to use a buffer
205 : * stored in a read-only section of the calling program.
206 : *
207 : * @param nBufXSize the width of the buffer image into which the desired region
208 : * is to be read, or from which it is to be written.
209 : *
210 : * @param nBufYSize the height of the buffer image into which the desired region
211 : * is to be read, or from which it is to be written.
212 : *
213 : * @param eBufType the type of the pixel values in the pData data buffer. The
214 : * pixel values will automatically be translated to/from the GDALRasterBand
215 : * data type as needed. Most driver implementations will use GDALCopyWords64()
216 : * to perform data type translation.
217 : *
218 : * @param nPixelSpace The byte offset from the start of one pixel value in
219 : * pData to the start of the next pixel value within a scanline. If defaulted
220 : * (0) the size of the datatype eBufType is used.
221 : *
222 : * @param nLineSpace The byte offset from the start of one scanline in
223 : * pData to the start of the next. If defaulted (0) the size of the datatype
224 : * eBufType * nBufXSize is used.
225 : *
226 : * @param psExtraArg Pointer to a GDALRasterIOExtraArg
227 : * structure with additional arguments to specify resampling and progress
228 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
229 : * configuration option can also be defined to override the default resampling
230 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
231 : *
232 : * @return CE_Failure if the access fails, otherwise CE_None.
233 : */
234 :
235 : /**
236 : * \brief Read/write a region of image data for this band.
237 : *
238 : * This method allows reading a region of a GDALRasterBand into a buffer,
239 : * or writing data from a buffer into a region of a GDALRasterBand. It
240 : * automatically takes care of data type translation if the data type
241 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
242 : * The method also takes care of image decimation / replication if the
243 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
244 : * region being accessed (nXSize x nYSize).
245 : *
246 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
247 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
248 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
249 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
250 : * Or use nLineSpace and a possibly shifted pData value.
251 : *
252 : * The nPixelSpace and nLineSpace parameters allow reading into or
253 : * writing from unusually organized buffers. This is primarily used
254 : * for buffers containing more than one bands raster data in interleaved
255 : * format.
256 : *
257 : * Some formats may efficiently implement decimation into a buffer by
258 : * reading from lower resolution overview images. The logic of the default
259 : * implementation in the base class GDALRasterBand is the following one. It
260 : * computes a target_downscaling_factor from the window of interest and buffer
261 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
262 : * It then walks through overviews and will select the first one whose
263 : * downscaling factor is greater than target_downscaling_factor / 1.2.
264 : *
265 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
266 : * The relationship between target_downscaling_factor and the select overview
267 : * level is the following one:
268 : *
269 : * target_downscaling_factor | selected_overview
270 : * ------------------------- | -----------------
271 : * ]0, 2 / 1.2] | full resolution band
272 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
273 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
274 : * ]8 / 1.2, infinity[ | 8x downsampled band
275 : *
276 : * For highest performance full resolution data access, read and write
277 : * on "block boundaries" as returned by GetBlockSize(), or use the
278 : * ReadBlock() and WriteBlock() methods.
279 : *
280 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
281 : * functions.
282 : *
283 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
284 : * more convenient to use for most common use cases.
285 : *
286 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
287 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
288 : * instance of this dataset) concurrently from several threads.
289 : *
290 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
291 : * write a region of data.
292 : *
293 : * @param nXOff The pixel offset to the top left corner of the region
294 : * of the band to be accessed. This would be zero to start from the left side.
295 : *
296 : * @param nYOff The line offset to the top left corner of the region
297 : * of the band to be accessed. This would be zero to start from the top.
298 : *
299 : * @param nXSize The width of the region of the band to be accessed in pixels.
300 : *
301 : * @param nYSize The height of the region of the band to be accessed in lines.
302 : *
303 : * @param[in,out] pData The buffer into which the data should be read, or from
304 : * which it should be written. This buffer must contain at least nBufXSize *
305 : * nBufYSize words of type eBufType. It is organized in left to right,
306 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
307 : * and nLineSpace parameters.
308 : *
309 : * @param nBufXSize the width of the buffer image into which the desired region
310 : * is to be read, or from which it is to be written.
311 : *
312 : * @param nBufYSize the height of the buffer image into which the desired region
313 : * is to be read, or from which it is to be written.
314 : *
315 : * @param eBufType the type of the pixel values in the pData data buffer. The
316 : * pixel values will automatically be translated to/from the GDALRasterBand
317 : * data type as needed.
318 : *
319 : * @param nPixelSpace The byte offset from the start of one pixel value in
320 : * pData to the start of the next pixel value within a scanline. If defaulted
321 : * (0) the size of the datatype eBufType is used.
322 : *
323 : * @param nLineSpace The byte offset from the start of one scanline in
324 : * pData to the start of the next. If defaulted (0) the size of the datatype
325 : * eBufType * nBufXSize is used.
326 : *
327 : * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
328 : * structure with additional arguments to specify resampling and progress
329 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
330 : * configuration option can also be defined to override the default resampling
331 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
332 : *
333 : * @return CE_Failure if the access fails, otherwise CE_None.
334 : *
335 : * @see GDALRasterBand::ReadRaster()
336 : */
337 :
338 4644420 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
339 : int nXSize, int nYSize, void *pData,
340 : int nBufXSize, int nBufYSize,
341 : GDALDataType eBufType, GSpacing nPixelSpace,
342 : GSpacing nLineSpace,
343 : GDALRasterIOExtraArg *psExtraArg)
344 :
345 : {
346 : GDALRasterIOExtraArg sExtraArg;
347 4644420 : if (psExtraArg == nullptr)
348 : {
349 4038060 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
350 4038060 : psExtraArg = &sExtraArg;
351 : }
352 606355 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
353 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
354 : {
355 0 : ReportError(CE_Failure, CPLE_AppDefined,
356 : "Unhandled version of GDALRasterIOExtraArg");
357 0 : return CE_Failure;
358 : }
359 :
360 4644420 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
361 : nBufYSize);
362 :
363 4644420 : if (CPL_UNLIKELY(nullptr == pData))
364 : {
365 0 : ReportError(CE_Failure, CPLE_AppDefined,
366 : "The buffer into which the data should be read is null");
367 0 : return CE_Failure;
368 : }
369 :
370 : /* -------------------------------------------------------------------- */
371 : /* Some size values are "noop". Lets just return to avoid */
372 : /* stressing lower level functions. */
373 : /* -------------------------------------------------------------------- */
374 4644420 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
375 : nBufYSize < 1))
376 : {
377 2 : CPLDebug("GDAL",
378 : "RasterIO() skipped for odd window or buffer size.\n"
379 : " Window = (%d,%d)x%dx%d\n"
380 : " Buffer = %dx%d\n",
381 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
382 :
383 2 : return CE_None;
384 : }
385 :
386 4644420 : if (eRWFlag == GF_Write)
387 : {
388 407880 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
389 : {
390 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
391 : "An error occurred while writing a dirty block "
392 : "from GDALRasterBand::RasterIO");
393 0 : CPLErr eErr = eFlushBlockErr;
394 0 : eFlushBlockErr = CE_None;
395 0 : return eErr;
396 : }
397 407880 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
398 : {
399 7 : return CE_Failure;
400 : }
401 : }
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* If pixel and line spacing are defaulted assign reasonable */
405 : /* value assuming a packed buffer. */
406 : /* -------------------------------------------------------------------- */
407 4644410 : if (nPixelSpace == 0)
408 : {
409 4236020 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
410 : }
411 :
412 4644410 : if (nLineSpace == 0)
413 : {
414 4223640 : nLineSpace = nPixelSpace * nBufXSize;
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Do some validation of parameters. */
419 : /* -------------------------------------------------------------------- */
420 4644410 : if (CPL_UNLIKELY(nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
421 : nYSize > nRasterYSize - nYOff))
422 : {
423 15 : ReportError(CE_Failure, CPLE_IllegalArg,
424 : "Access window out of range in RasterIO(). Requested\n"
425 : "(%d,%d) of size %dx%d on raster of %dx%d.",
426 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
427 15 : return CE_Failure;
428 : }
429 :
430 4644400 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
431 : {
432 0 : ReportError(
433 : CE_Failure, CPLE_IllegalArg,
434 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
435 : eRWFlag);
436 0 : return CE_Failure;
437 : }
438 4644400 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
439 : {
440 2 : ReportError(CE_Failure, CPLE_IllegalArg,
441 : "Illegal GDT_Unknown/GDT_TypeCount argument");
442 2 : return CE_Failure;
443 : }
444 :
445 4644390 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
446 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
447 4644390 : nLineSpace, psExtraArg);
448 : }
449 :
450 : /************************************************************************/
451 : /* RasterIOInternal() */
452 : /************************************************************************/
453 :
454 4644500 : CPLErr GDALRasterBand::RasterIOInternal(
455 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
456 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
457 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
458 : {
459 : /* -------------------------------------------------------------------- */
460 : /* Call the format specific function. */
461 : /* -------------------------------------------------------------------- */
462 :
463 4644500 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
464 :
465 : CPLErr eErr;
466 4644500 : if (bForceCachedIO)
467 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
468 : pData, nBufXSize, nBufYSize, eBufType,
469 : nPixelSpace, nLineSpace, psExtraArg);
470 : else
471 : eErr =
472 4644470 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
473 4644470 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
474 :
475 4644500 : if (bCallLeaveReadWrite)
476 612647 : LeaveReadWrite();
477 :
478 4644500 : return eErr;
479 : }
480 :
481 : /************************************************************************/
482 : /* GDALRasterIO() */
483 : /************************************************************************/
484 :
485 : /**
486 : * \brief Read/write a region of image data for this band.
487 : *
488 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
489 : * resolution, progress callback, etc. are needed)
490 : *
491 : * @see GDALRasterBand::RasterIO()
492 : */
493 :
494 3589480 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
495 : int nXOff, int nYOff, int nXSize, int nYSize,
496 : void *pData, int nBufXSize, int nBufYSize,
497 : GDALDataType eBufType, int nPixelSpace,
498 : int nLineSpace)
499 :
500 : {
501 3589480 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
502 :
503 3589480 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
504 :
505 3589480 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
506 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
507 3589480 : nLineSpace, nullptr));
508 : }
509 :
510 : /************************************************************************/
511 : /* GDALRasterIOEx() */
512 : /************************************************************************/
513 :
514 : /**
515 : * \brief Read/write a region of image data for this band.
516 : *
517 : * @see GDALRasterBand::RasterIO()
518 : */
519 :
520 42501 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
521 : int nXOff, int nYOff, int nXSize, int nYSize,
522 : void *pData, int nBufXSize, int nBufYSize,
523 : GDALDataType eBufType, GSpacing nPixelSpace,
524 : GSpacing nLineSpace,
525 : GDALRasterIOExtraArg *psExtraArg)
526 :
527 : {
528 42501 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
529 :
530 42501 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
531 :
532 42501 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
533 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
534 42501 : nLineSpace, psExtraArg));
535 : }
536 :
537 : /************************************************************************/
538 : /* GetGDTFromCppType() */
539 : /************************************************************************/
540 :
541 : namespace
542 : {
543 : template <class T> struct GetGDTFromCppType;
544 :
545 : #define DEFINE_GetGDTFromCppType(T, eDT) \
546 : template <> struct GetGDTFromCppType<T> \
547 : { \
548 : static constexpr GDALDataType GDT = eDT; \
549 : }
550 :
551 : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
552 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
553 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
554 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
555 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
556 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
557 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
558 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
559 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
560 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
561 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
562 : // Not allowed by C++ standard
563 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
564 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
565 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
566 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
567 : } // namespace
568 :
569 : /************************************************************************/
570 : /* ReadRaster() */
571 : /************************************************************************/
572 :
573 : // clang-format off
574 : /** Read a region of image data for this band.
575 : *
576 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
577 : * for common use cases, like reading a whole band.
578 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
579 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
580 : * float, double, std::complex<float|double>.
581 : *
582 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
583 : * and can allocate memory automatically.
584 : *
585 : * To read a whole band (assuming it fits into memory), as an array of double:
586 : *
587 : \code{.cpp}
588 : double* myArray = static_cast<double*>(
589 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
590 : // TODO: check here that myArray != nullptr
591 : const size_t nArrayEltCount =
592 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
593 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
594 : {
595 : // do something
596 : }
597 : VSIFree(myArray)
598 : \endcode
599 : *
600 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
601 : *
602 : \code{.cpp}
603 : double* myArray = static_cast<double*>(
604 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
605 : // TODO: check here that myArray != nullptr
606 : const size_t nArrayEltCount = 128 * 128;
607 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
608 : {
609 : // do something
610 : }
611 : VSIFree(myArray)
612 : \endcode
613 : *
614 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
615 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
616 : * instance of this dataset) concurrently from several threads.
617 : *
618 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
619 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
620 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
621 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
622 : * Or use nLineSpace and a possibly shifted pData value.
623 : *
624 : * @param[out] pData The buffer into which the data should be written.
625 : * This buffer must contain at least nBufXSize *
626 : * nBufYSize words of type T. It is organized in left to right,
627 : * top to bottom pixel order, and fully packed.
628 : * The type of the buffer does not need to be the one of GetDataType(). The
629 : * method will perform data type translation (with potential rounding, clamping)
630 : * if needed.
631 : *
632 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
633 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
634 : * return in error if it is not. If set to zero, then pData is trusted to be
635 : * large enough.
636 : *
637 : * @param dfXOff The pixel offset to the top left corner of the region
638 : * of the band to be accessed. This would be zero to start from the left side.
639 : * Defaults to 0.
640 : *
641 : * @param dfYOff The line offset to the top left corner of the region
642 : * of the band to be accessed. This would be zero to start from the top.
643 : * Defaults to 0.
644 : *
645 : * @param dfXSize The width of the region of the band to be accessed in pixels.
646 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
647 : * dfXSize is set to the band width.
648 : *
649 : * @param dfYSize The height of the region of the band to be accessed in lines.
650 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
651 : * dfYSize is set to the band height.
652 : *
653 : * @param nBufXSize the width of the buffer image into which the desired region
654 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
655 : * then nBufXSize is initialized with dfXSize.
656 : *
657 : * @param nBufYSize the height of the buffer image into which the desired region
658 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
659 : * then nBufYSize is initialized with dfYSize.
660 : *
661 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
662 : *
663 : * @param pfnProgress Progress function. May be nullptr.
664 : *
665 : * @param pProgressData User data of pfnProgress. May be nullptr.
666 : *
667 : * @return CE_Failure if the access fails, otherwise CE_None.
668 : *
669 : * @see GDALRasterBand::RasterIO()
670 : * @since GDAL 3.10
671 : */
672 : // clang-format on
673 :
674 : template <class T>
675 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
676 : double dfXOff, double dfYOff, double dfXSize,
677 : double dfYSize, size_t nBufXSize,
678 : size_t nBufYSize,
679 : GDALRIOResampleAlg eResampleAlg,
680 : GDALProgressFunc pfnProgress,
681 : void *pProgressData) const
682 : {
683 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
684 : {
685 2 : return CE_Failure;
686 : }
687 :
688 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
689 : {
690 16 : dfXSize = nRasterXSize;
691 16 : dfYSize = nRasterYSize;
692 : }
693 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
694 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
695 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
696 2 : dfYOff + dfYSize > INT_MAX)
697 : {
698 0 : return CE_Failure;
699 : }
700 :
701 : GDALRasterIOExtraArg sExtraArg;
702 18 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
703 18 : CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
704 18 : CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
705 18 : CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
706 18 : CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
707 18 : sExtraArg.eResampleAlg = eResampleAlg;
708 18 : sExtraArg.pfnProgress = pfnProgress;
709 18 : sExtraArg.pProgressData = pProgressData;
710 18 : sExtraArg.bFloatingPointWindowValidity = true;
711 18 : sExtraArg.dfXOff = dfXOff;
712 18 : sExtraArg.dfYOff = dfYOff;
713 18 : sExtraArg.dfXSize = dfXSize;
714 18 : sExtraArg.dfYSize = dfYSize;
715 :
716 18 : const int nXOff = static_cast<int>(dfXOff);
717 18 : const int nYOff = static_cast<int>(dfYOff);
718 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
719 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
720 18 : if (nBufXSize == 0 && nBufYSize == 0)
721 : {
722 17 : if (static_cast<int>(dfXSize) == dfXSize &&
723 17 : static_cast<int>(dfYSize) == dfYSize)
724 : {
725 17 : nBufXSize = static_cast<int>(dfXSize);
726 17 : nBufYSize = static_cast<int>(dfYSize);
727 : }
728 : else
729 : {
730 0 : CPLError(CE_Failure, CPLE_AppDefined,
731 : "nBufXSize and nBufYSize must be provided if dfXSize or "
732 : "dfYSize is not an integer value");
733 0 : return CE_Failure;
734 : }
735 : }
736 18 : if (nBufXSize == 0 || nBufYSize == 0)
737 : {
738 0 : CPLDebug("GDAL",
739 : "RasterIO() skipped for odd window or buffer size.\n"
740 : " Window = (%d,%d)x%dx%d\n"
741 : " Buffer = %dx%d\n",
742 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
743 : static_cast<int>(nBufYSize));
744 :
745 0 : return CE_None;
746 : }
747 :
748 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
749 : {
750 1 : CPLError(CE_Failure, CPLE_AppDefined,
751 : "Provided array is not large enough");
752 1 : return CE_Failure;
753 : }
754 :
755 17 : constexpr GSpacing nPixelSpace = sizeof(T);
756 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
757 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
758 :
759 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
760 :
761 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
762 : static_cast<int>(nBufXSize),
763 : static_cast<int>(nBufYSize), eBufType,
764 17 : nPixelSpace, nLineSpace, &sExtraArg);
765 : }
766 :
767 : //! @cond Doxygen_Suppress
768 :
769 : #define INSTANTIATE_READ_RASTER(T) \
770 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
771 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
772 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
773 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
774 : void *pProgressData) const;
775 :
776 : INSTANTIATE_READ_RASTER(uint8_t)
777 : INSTANTIATE_READ_RASTER(int8_t)
778 : INSTANTIATE_READ_RASTER(uint16_t)
779 : INSTANTIATE_READ_RASTER(int16_t)
780 : INSTANTIATE_READ_RASTER(uint32_t)
781 : INSTANTIATE_READ_RASTER(int32_t)
782 : INSTANTIATE_READ_RASTER(uint64_t)
783 : INSTANTIATE_READ_RASTER(int64_t)
784 : INSTANTIATE_READ_RASTER(GFloat16)
785 : INSTANTIATE_READ_RASTER(float)
786 : INSTANTIATE_READ_RASTER(double)
787 : // Not allowed by C++ standard
788 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
789 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
790 : INSTANTIATE_READ_RASTER(std::complex<float>)
791 : INSTANTIATE_READ_RASTER(std::complex<double>)
792 :
793 : //! @endcond
794 :
795 : /************************************************************************/
796 : /* ReadRaster() */
797 : /************************************************************************/
798 :
799 : /** Read a region of image data for this band.
800 : *
801 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
802 : * for common use cases, like reading a whole band.
803 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
804 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
805 : * float, double, std::complex<float|double>.
806 : *
807 : * To read a whole band (assuming it fits into memory), as a vector of double:
808 : *
809 : \code
810 : std::vector<double> myArray;
811 : if (poBand->ReadRaster(myArray) == CE_None)
812 : {
813 : // do something
814 : }
815 : \endcode
816 : *
817 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
818 : *
819 : \code{.cpp}
820 : std::vector<double> myArray;
821 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
822 : {
823 : // do something
824 : }
825 : \endcode
826 : *
827 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
828 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
829 : * instance of this dataset) concurrently from several threads.
830 : *
831 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
832 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
833 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
834 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
835 : * Or use nLineSpace and a possibly shifted pData value.
836 : *
837 : * @param[out] vData The vector into which the data should be written.
838 : * The vector will be resized, if needed, to contain at least nBufXSize *
839 : * nBufYSize values. The values in the vector are organized in left to right,
840 : * top to bottom pixel order, and fully packed.
841 : * The type of the vector does not need to be the one of GetDataType(). The
842 : * method will perform data type translation (with potential rounding, clamping)
843 : * if needed.
844 : *
845 : * @param dfXOff The pixel offset to the top left corner of the region
846 : * of the band to be accessed. This would be zero to start from the left side.
847 : * Defaults to 0.
848 : *
849 : * @param dfYOff The line offset to the top left corner of the region
850 : * of the band to be accessed. This would be zero to start from the top.
851 : * Defaults to 0.
852 : *
853 : * @param dfXSize The width of the region of the band to be accessed in pixels.
854 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
855 : * dfXSize is set to the band width.
856 : *
857 : * @param dfYSize The height of the region of the band to be accessed in lines.
858 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
859 : * dfYSize is set to the band height.
860 : *
861 : * @param nBufXSize the width of the buffer image into which the desired region
862 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
863 : * then nBufXSize is initialized with dfXSize.
864 : *
865 : * @param nBufYSize the height of the buffer image into which the desired region
866 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
867 : * then nBufYSize is initialized with dfYSize.
868 : *
869 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
870 : *
871 : * @param pfnProgress Progress function. May be nullptr.
872 : *
873 : * @param pProgressData User data of pfnProgress. May be nullptr.
874 : *
875 : * @return CE_Failure if the access fails, otherwise CE_None.
876 : *
877 : * @see GDALRasterBand::RasterIO()
878 : * @since GDAL 3.10
879 : */
880 : template <class T>
881 90 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
882 : double dfYOff, double dfXSize, double dfYSize,
883 : size_t nBufXSize, size_t nBufYSize,
884 : GDALRIOResampleAlg eResampleAlg,
885 : GDALProgressFunc pfnProgress,
886 : void *pProgressData) const
887 : {
888 90 : if (((nBufXSize | nBufYSize) >> 31) != 0)
889 : {
890 2 : return CE_Failure;
891 : }
892 :
893 88 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
894 : {
895 81 : dfXSize = nRasterXSize;
896 81 : dfYSize = nRasterYSize;
897 : }
898 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
899 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
900 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
901 7 : dfYOff + dfYSize > INT_MAX)
902 : {
903 0 : return CE_Failure;
904 : }
905 :
906 : GDALRasterIOExtraArg sExtraArg;
907 88 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
908 88 : CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
909 88 : CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
910 88 : CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
911 88 : CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
912 88 : sExtraArg.eResampleAlg = eResampleAlg;
913 88 : sExtraArg.pfnProgress = pfnProgress;
914 88 : sExtraArg.pProgressData = pProgressData;
915 88 : sExtraArg.bFloatingPointWindowValidity = true;
916 88 : sExtraArg.dfXOff = dfXOff;
917 88 : sExtraArg.dfYOff = dfYOff;
918 88 : sExtraArg.dfXSize = dfXSize;
919 88 : sExtraArg.dfYSize = dfYSize;
920 :
921 88 : const int nXOff = static_cast<int>(dfXOff);
922 88 : const int nYOff = static_cast<int>(dfYOff);
923 88 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
924 88 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
925 88 : if (nBufXSize == 0 && nBufYSize == 0)
926 : {
927 84 : if (static_cast<int>(dfXSize) == dfXSize &&
928 83 : static_cast<int>(dfYSize) == dfYSize)
929 : {
930 83 : nBufXSize = static_cast<int>(dfXSize);
931 83 : nBufYSize = static_cast<int>(dfYSize);
932 : }
933 : else
934 : {
935 1 : CPLError(CE_Failure, CPLE_AppDefined,
936 : "nBufXSize and nBufYSize must be provided if "
937 : "dfXSize or dfYSize is not an integer value");
938 1 : return CE_Failure;
939 : }
940 : }
941 87 : if (nBufXSize == 0 || nBufYSize == 0)
942 : {
943 0 : CPLDebug("GDAL",
944 : "RasterIO() skipped for odd window or buffer size.\n"
945 : " Window = (%d,%d)x%dx%d\n"
946 : " Buffer = %dx%d\n",
947 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
948 : static_cast<int>(nBufYSize));
949 :
950 0 : return CE_None;
951 : }
952 :
953 : if constexpr (SIZEOF_VOIDP < 8)
954 : {
955 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
956 : {
957 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
958 : return CE_Failure;
959 : }
960 : }
961 :
962 87 : if (vData.size() < nBufXSize * nBufYSize)
963 : {
964 : try
965 : {
966 85 : vData.resize(nBufXSize * nBufYSize);
967 : }
968 1 : catch (const std::exception &)
969 : {
970 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
971 1 : return CE_Failure;
972 : }
973 : }
974 :
975 86 : constexpr GSpacing nPixelSpace = sizeof(T);
976 86 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
977 86 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
978 :
979 86 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
980 :
981 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
982 : vData.data(), static_cast<int>(nBufXSize),
983 : static_cast<int>(nBufYSize), eBufType,
984 86 : nPixelSpace, nLineSpace, &sExtraArg);
985 : }
986 :
987 : //! @cond Doxygen_Suppress
988 :
989 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
990 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
991 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
992 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
993 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
994 : void *pProgressData) const;
995 :
996 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
997 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
998 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
999 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
1000 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
1001 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
1002 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
1003 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
1004 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
1005 : INSTANTIATE_READ_RASTER_VECTOR(float)
1006 : INSTANTIATE_READ_RASTER_VECTOR(double)
1007 : // Not allowed by C++ standard
1008 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
1009 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
1010 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
1011 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
1012 :
1013 : //! @endcond
1014 :
1015 : /************************************************************************/
1016 : /* ReadBlock() */
1017 : /************************************************************************/
1018 :
1019 : /**
1020 : * \brief Read a block of image data efficiently.
1021 : *
1022 : * This method accesses a "natural" block from the raster band without
1023 : * resampling, or data type conversion. For a more generalized, but
1024 : * potentially less efficient access use RasterIO().
1025 : *
1026 : * This method is the same as the C GDALReadBlock() function.
1027 : *
1028 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1029 : * block oriented data without an extra copy into an application buffer.
1030 : *
1031 : * The following code would efficiently compute a histogram of eight bit
1032 : * raster data. Note that the final block may be partial ... data beyond
1033 : * the edge of the underlying raster band in these edge blocks is of an
1034 : * undetermined value.
1035 : *
1036 : \code{.cpp}
1037 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1038 :
1039 : {
1040 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1041 :
1042 : CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1043 :
1044 : int nXBlockSize, nYBlockSize;
1045 :
1046 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1047 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1048 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1049 :
1050 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1051 :
1052 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1053 : {
1054 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1055 : {
1056 : int nXValid, nYValid;
1057 :
1058 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1059 :
1060 : // Compute the portion of the block that is valid
1061 : // for partial edge blocks.
1062 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1063 :
1064 : // Collect the histogram counts.
1065 : for( int iY = 0; iY < nYValid; iY++ )
1066 : {
1067 : for( int iX = 0; iX < nXValid; iX++ )
1068 : {
1069 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1070 : }
1071 : }
1072 : }
1073 : }
1074 : }
1075 : \endcode
1076 : *
1077 : * @param nXBlockOff the horizontal block offset, with zero indicating
1078 : * the left most block, 1 the next block and so forth.
1079 : *
1080 : * @param nYBlockOff the vertical block offset, with zero indicating
1081 : * the top most block, 1 the next block and so forth.
1082 : *
1083 : * @param pImage the buffer into which the data will be read. The buffer
1084 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1085 : * of type GetRasterDataType().
1086 : *
1087 : * @return CE_None on success or CE_Failure on an error.
1088 : */
1089 :
1090 1076 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1091 :
1092 : {
1093 : /* -------------------------------------------------------------------- */
1094 : /* Validate arguments. */
1095 : /* -------------------------------------------------------------------- */
1096 1076 : CPLAssert(pImage != nullptr);
1097 :
1098 1076 : if (!InitBlockInfo())
1099 0 : return CE_Failure;
1100 :
1101 1076 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1102 : {
1103 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1104 : "Illegal nXBlockOff value (%d) in "
1105 : "GDALRasterBand::ReadBlock()\n",
1106 : nXBlockOff);
1107 :
1108 0 : return (CE_Failure);
1109 : }
1110 :
1111 1076 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1112 : {
1113 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1114 : "Illegal nYBlockOff value (%d) in "
1115 : "GDALRasterBand::ReadBlock()\n",
1116 : nYBlockOff);
1117 :
1118 0 : return (CE_Failure);
1119 : }
1120 :
1121 : /* -------------------------------------------------------------------- */
1122 : /* Invoke underlying implementation method. */
1123 : /* -------------------------------------------------------------------- */
1124 :
1125 1076 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1126 1076 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1127 1076 : if (bCallLeaveReadWrite)
1128 4 : LeaveReadWrite();
1129 1076 : return eErr;
1130 : }
1131 :
1132 : /************************************************************************/
1133 : /* GDALReadBlock() */
1134 : /************************************************************************/
1135 :
1136 : /**
1137 : * \brief Read a block of image data efficiently.
1138 : *
1139 : * @see GDALRasterBand::ReadBlock()
1140 : */
1141 :
1142 79 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1143 : void *pData)
1144 :
1145 : {
1146 79 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1147 :
1148 79 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1149 79 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1150 : }
1151 :
1152 : /************************************************************************/
1153 : /* IReadBlock() */
1154 : /************************************************************************/
1155 :
1156 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1157 : * ) \brief Read a block of data.
1158 : *
1159 : * Default internal implementation ... to be overridden by
1160 : * subclasses that support reading.
1161 : * @param nBlockXOff Block X Offset
1162 : * @param nBlockYOff Block Y Offset
1163 : * @param pData Pixel buffer into which to place read data.
1164 : * @return CE_None on success or CE_Failure on an error.
1165 : */
1166 :
1167 : /************************************************************************/
1168 : /* IWriteBlock() */
1169 : /************************************************************************/
1170 :
1171 : /**
1172 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1173 : * Write a block of data.
1174 : *
1175 : * Default internal implementation ... to be overridden by
1176 : * subclasses that support writing.
1177 : * @param nBlockXOff Block X Offset
1178 : * @param nBlockYOff Block Y Offset
1179 : * @param pData Pixel buffer to write
1180 : * @return CE_None on success or CE_Failure on an error.
1181 : */
1182 :
1183 : /**/
1184 : /**/
1185 :
1186 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1187 : void * /*pData*/)
1188 :
1189 : {
1190 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1191 0 : ReportError(CE_Failure, CPLE_NotSupported,
1192 : "WriteBlock() not supported for this dataset.");
1193 :
1194 0 : return (CE_Failure);
1195 : }
1196 :
1197 : /************************************************************************/
1198 : /* WriteBlock() */
1199 : /************************************************************************/
1200 :
1201 : /**
1202 : * \brief Write a block of image data efficiently.
1203 : *
1204 : * This method accesses a "natural" block from the raster band without
1205 : * resampling, or data type conversion. For a more generalized, but
1206 : * potentially less efficient access use RasterIO().
1207 : *
1208 : * This method is the same as the C GDALWriteBlock() function.
1209 : *
1210 : * See ReadBlock() for an example of block oriented data access.
1211 : *
1212 : * @param nXBlockOff the horizontal block offset, with zero indicating
1213 : * the left most block, 1 the next block and so forth.
1214 : *
1215 : * @param nYBlockOff the vertical block offset, with zero indicating
1216 : * the left most block, 1 the next block and so forth.
1217 : *
1218 : * @param pImage the buffer from which the data will be written. The buffer
1219 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1220 : * of type GetRasterDataType(). Note that the content of the buffer might be
1221 : * temporarily modified during the execution of this method (and eventually
1222 : * restored back to its original content), so it is not safe to use a buffer
1223 : * stored in a read-only section of the calling program.
1224 : *
1225 : * @return CE_None on success or CE_Failure on an error.
1226 : */
1227 :
1228 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1229 :
1230 : {
1231 : /* -------------------------------------------------------------------- */
1232 : /* Validate arguments. */
1233 : /* -------------------------------------------------------------------- */
1234 4883 : CPLAssert(pImage != nullptr);
1235 :
1236 4883 : if (!InitBlockInfo())
1237 0 : return CE_Failure;
1238 :
1239 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1240 : {
1241 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1242 : "Illegal nXBlockOff value (%d) in "
1243 : "GDALRasterBand::WriteBlock()\n",
1244 : nXBlockOff);
1245 :
1246 0 : return (CE_Failure);
1247 : }
1248 :
1249 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1250 : {
1251 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1252 : "Illegal nYBlockOff value (%d) in "
1253 : "GDALRasterBand::WriteBlock()\n",
1254 : nYBlockOff);
1255 :
1256 0 : return (CE_Failure);
1257 : }
1258 :
1259 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1260 : {
1261 0 : return CE_Failure;
1262 : }
1263 :
1264 4883 : if (eFlushBlockErr != CE_None)
1265 : {
1266 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1267 : "An error occurred while writing a dirty block "
1268 : "from GDALRasterBand::WriteBlock");
1269 0 : CPLErr eErr = eFlushBlockErr;
1270 0 : eFlushBlockErr = CE_None;
1271 0 : return eErr;
1272 : }
1273 :
1274 : /* -------------------------------------------------------------------- */
1275 : /* Invoke underlying implementation method. */
1276 : /* -------------------------------------------------------------------- */
1277 :
1278 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1279 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1280 4883 : if (bCallLeaveReadWrite)
1281 4883 : LeaveReadWrite();
1282 :
1283 4883 : return eErr;
1284 : }
1285 :
1286 : /************************************************************************/
1287 : /* GDALWriteBlock() */
1288 : /************************************************************************/
1289 :
1290 : /**
1291 : * \brief Write a block of image data efficiently.
1292 : *
1293 : * @see GDALRasterBand::WriteBlock()
1294 : */
1295 :
1296 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1297 : void *pData)
1298 :
1299 : {
1300 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1301 :
1302 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1303 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1304 : }
1305 :
1306 : /************************************************************************/
1307 : /* EmitErrorMessageIfWriteNotSupported() */
1308 : /************************************************************************/
1309 :
1310 : /**
1311 : * Emit an error message if a write operation to this band is not supported.
1312 : *
1313 : * The base implementation will emit an error message if the access mode is
1314 : * read-only. Derived classes may implement it to provide a custom message.
1315 : *
1316 : * @param pszCaller Calling function.
1317 : * @return true if an error message has been emitted.
1318 : */
1319 681775 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1320 : const char *pszCaller) const
1321 : {
1322 681775 : if (eAccess == GA_ReadOnly)
1323 : {
1324 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1325 : "%s: attempt to write to dataset opened in read-only mode.",
1326 : pszCaller);
1327 :
1328 4 : return true;
1329 : }
1330 681771 : return false;
1331 : }
1332 :
1333 : /************************************************************************/
1334 : /* GetActualBlockSize() */
1335 : /************************************************************************/
1336 : /**
1337 : * \brief Fetch the actual block size for a given block offset.
1338 : *
1339 : * Handles partial blocks at the edges of the raster and returns the true
1340 : * number of pixels
1341 : *
1342 : * @param nXBlockOff the horizontal block offset for which to calculate the
1343 : * number of valid pixels, with zero indicating the left most block, 1 the next
1344 : * block and so forth.
1345 : *
1346 : * @param nYBlockOff the vertical block offset, with zero indicating
1347 : * the top most block, 1 the next block and so forth.
1348 : *
1349 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1350 : * the x direction will be stored
1351 : *
1352 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1353 : * the y direction will be stored
1354 : *
1355 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1356 : *
1357 : */
1358 33951 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1359 : int *pnXValid, int *pnYValid) const
1360 : {
1361 67901 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1362 67898 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1363 67894 : nYBlockOff < 0 || nBlockYSize == 0 ||
1364 33947 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1365 : {
1366 6 : return CE_Failure;
1367 : }
1368 :
1369 33945 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1370 33945 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1371 :
1372 33945 : *pnXValid = nBlockXSize;
1373 33945 : *pnYValid = nBlockYSize;
1374 :
1375 33945 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1376 : {
1377 32608 : *pnXValid = nRasterXSize - nXPixelOff;
1378 : }
1379 :
1380 33945 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1381 : {
1382 3294 : *pnYValid = nRasterYSize - nYPixelOff;
1383 : }
1384 :
1385 33945 : return CE_None;
1386 : }
1387 :
1388 : /************************************************************************/
1389 : /* GDALGetActualBlockSize() */
1390 : /************************************************************************/
1391 :
1392 : /**
1393 : * \brief Retrieve the actual block size for a given block offset.
1394 : *
1395 : * @see GDALRasterBand::GetActualBlockSize()
1396 : */
1397 :
1398 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1399 : int nYBlockOff, int *pnXValid,
1400 : int *pnYValid)
1401 :
1402 : {
1403 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1404 :
1405 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1406 : return (
1407 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1408 : }
1409 :
1410 : /************************************************************************/
1411 : /* GetSuggestedBlockAccessPattern() */
1412 : /************************************************************************/
1413 :
1414 : /**
1415 : * \brief Return the suggested/most efficient access pattern to blocks
1416 : * (for read operations).
1417 : *
1418 : * While all GDAL drivers have to expose a block size, not all can guarantee
1419 : * efficient random access (GSBAP_RANDOM) to any block.
1420 : * Some drivers for example decompress sequentially a compressed stream from
1421 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1422 : * case best performance will be achieved while reading blocks in that order.
1423 : * (accessing blocks in random access in such rasters typically causes the
1424 : * decoding to be re-initialized from the start if accessing blocks in
1425 : * a non-sequential order)
1426 : *
1427 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1428 : * returned by drivers that expose a somewhat artificial block size, because
1429 : * they can extract any part of a raster, but in a rather inefficient way.
1430 : *
1431 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1432 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1433 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1434 : * most efficient strategy is to read as many pixels as possible in the less
1435 : * RasterIO() operations.
1436 : *
1437 : * The return of this method is for example used to determine the swath size
1438 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1439 : *
1440 : * @since GDAL 3.6
1441 : */
1442 :
1443 : GDALSuggestedBlockAccessPattern
1444 2491 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1445 : {
1446 2491 : return GSBAP_UNKNOWN;
1447 : }
1448 :
1449 : /************************************************************************/
1450 : /* GetRasterDataType() */
1451 : /************************************************************************/
1452 :
1453 : /**
1454 : * \brief Fetch the pixel data type for this band.
1455 : *
1456 : * This method is the same as the C function GDALGetRasterDataType().
1457 : *
1458 : * @return the data type of pixels for this band.
1459 : */
1460 :
1461 9054580 : GDALDataType GDALRasterBand::GetRasterDataType() const
1462 :
1463 : {
1464 9054580 : return eDataType;
1465 : }
1466 :
1467 : /************************************************************************/
1468 : /* GDALGetRasterDataType() */
1469 : /************************************************************************/
1470 :
1471 : /**
1472 : * \brief Fetch the pixel data type for this band.
1473 : *
1474 : * @see GDALRasterBand::GetRasterDataType()
1475 : */
1476 :
1477 911252 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1478 :
1479 : {
1480 911252 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1481 :
1482 911252 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1483 911252 : return poBand->GetRasterDataType();
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* GetBlockSize() */
1488 : /************************************************************************/
1489 :
1490 : /**
1491 : * \brief Fetch the "natural" block size of this band.
1492 : *
1493 : * GDAL contains a concept of the natural block size of rasters so that
1494 : * applications can organized data access efficiently for some file formats.
1495 : * The natural block size is the block size that is most efficient for
1496 : * accessing the format. For many formats this is simple a whole scanline
1497 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1498 : *
1499 : * However, for tiled images this will typically be the tile size.
1500 : *
1501 : * Note that the X and Y block sizes don't have to divide the image size
1502 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1503 : * See ReadBlock() for an example of code dealing with these issues.
1504 : *
1505 : * This method is the same as the C function GDALGetBlockSize().
1506 : *
1507 : * @param pnXSize integer to put the X block size into or NULL.
1508 : *
1509 : * @param pnYSize integer to put the Y block size into or NULL.
1510 : */
1511 :
1512 5584880 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1513 :
1514 : {
1515 5584880 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1516 : {
1517 0 : ReportError(CE_Failure, CPLE_AppDefined,
1518 0 : "Invalid block dimension : %d * %d", nBlockXSize,
1519 0 : nBlockYSize);
1520 0 : if (pnXSize != nullptr)
1521 0 : *pnXSize = 0;
1522 0 : if (pnYSize != nullptr)
1523 0 : *pnYSize = 0;
1524 : }
1525 : else
1526 : {
1527 5584880 : if (pnXSize != nullptr)
1528 5584880 : *pnXSize = nBlockXSize;
1529 5584880 : if (pnYSize != nullptr)
1530 5584880 : *pnYSize = nBlockYSize;
1531 : }
1532 5584880 : }
1533 :
1534 : /************************************************************************/
1535 : /* GDALGetBlockSize() */
1536 : /************************************************************************/
1537 :
1538 : /**
1539 : * \brief Fetch the "natural" block size of this band.
1540 : *
1541 : * @see GDALRasterBand::GetBlockSize()
1542 : */
1543 :
1544 41361 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1545 : int *pnYSize)
1546 :
1547 : {
1548 41361 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1549 :
1550 41361 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1551 41361 : poBand->GetBlockSize(pnXSize, pnYSize);
1552 : }
1553 :
1554 : /************************************************************************/
1555 : /* InitBlockInfo() */
1556 : /************************************************************************/
1557 :
1558 : //! @cond Doxygen_Suppress
1559 3677100 : int GDALRasterBand::InitBlockInfo()
1560 :
1561 : {
1562 3677100 : if (poBandBlockCache != nullptr)
1563 3436100 : return poBandBlockCache->IsInitOK();
1564 :
1565 : /* Do some validation of raster and block dimensions in case the driver */
1566 : /* would have neglected to do it itself */
1567 241004 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1568 : {
1569 0 : ReportError(CE_Failure, CPLE_AppDefined,
1570 : "Invalid block dimension : %d * %d", nBlockXSize,
1571 : nBlockYSize);
1572 0 : return FALSE;
1573 : }
1574 :
1575 241004 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1576 : {
1577 0 : ReportError(CE_Failure, CPLE_AppDefined,
1578 : "Invalid raster dimension : %d * %d", nRasterXSize,
1579 : nRasterYSize);
1580 0 : return FALSE;
1581 : }
1582 :
1583 241004 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1584 241004 : if (nDataTypeSize == 0)
1585 : {
1586 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1587 0 : return FALSE;
1588 : }
1589 :
1590 : #if SIZEOF_VOIDP == 4
1591 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1592 : {
1593 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1594 : * multiplication in other cases */
1595 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1596 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1597 : {
1598 : ReportError(CE_Failure, CPLE_NotSupported,
1599 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1600 : nBlockYSize);
1601 : return FALSE;
1602 : }
1603 : }
1604 : #endif
1605 :
1606 241004 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1607 241004 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1608 :
1609 : const char *pszBlockStrategy =
1610 241004 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1611 241004 : bool bUseArray = true;
1612 241004 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1613 : {
1614 240964 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1615 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1616 : {
1617 240945 : GUIntBig nBlockCount =
1618 240945 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1619 240945 : if (poDS != nullptr)
1620 240741 : nBlockCount *= poDS->GetRasterCount();
1621 240945 : bUseArray = (nBlockCount < 1024 * 1024);
1622 : }
1623 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1624 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1625 : {
1626 0 : bUseArray = false;
1627 240964 : }
1628 : }
1629 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1630 40 : bUseArray = false;
1631 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1632 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1633 : pszBlockStrategy);
1634 :
1635 241004 : if (bUseArray)
1636 240933 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1637 : else
1638 : {
1639 71 : if (nBand == 1)
1640 26 : CPLDebug("GDAL", "Use hashset band block cache");
1641 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1642 : }
1643 241004 : if (poBandBlockCache == nullptr)
1644 0 : return FALSE;
1645 241004 : return poBandBlockCache->Init();
1646 : }
1647 :
1648 : //! @endcond
1649 :
1650 : /************************************************************************/
1651 : /* FlushCache() */
1652 : /************************************************************************/
1653 :
1654 : /**
1655 : * \brief Flush raster data cache.
1656 : *
1657 : * This call will recover memory used to cache data blocks for this raster
1658 : * band, and ensure that new requests are referred to the underlying driver.
1659 : *
1660 : * This method is the same as the C function GDALFlushRasterCache().
1661 : *
1662 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1663 : * @return CE_None on success.
1664 : */
1665 :
1666 5833400 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1667 :
1668 : {
1669 5963560 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1670 130163 : poBandBlockCache)
1671 4330 : poBandBlockCache->DisableDirtyBlockWriting();
1672 :
1673 5833400 : CPLErr eGlobalErr = eFlushBlockErr;
1674 :
1675 5833400 : if (eFlushBlockErr != CE_None)
1676 : {
1677 0 : ReportError(
1678 : eFlushBlockErr, CPLE_AppDefined,
1679 : "An error occurred while writing a dirty block from FlushCache");
1680 0 : eFlushBlockErr = CE_None;
1681 : }
1682 :
1683 5833400 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1684 5061690 : return eGlobalErr;
1685 :
1686 771710 : return poBandBlockCache->FlushCache();
1687 : }
1688 :
1689 : /************************************************************************/
1690 : /* GDALFlushRasterCache() */
1691 : /************************************************************************/
1692 :
1693 : /**
1694 : * \brief Flush raster data cache.
1695 : *
1696 : * @see GDALRasterBand::FlushCache()
1697 : */
1698 :
1699 625 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1700 :
1701 : {
1702 625 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1703 :
1704 625 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1705 : }
1706 :
1707 : /************************************************************************/
1708 : /* DropCache() */
1709 : /************************************************************************/
1710 :
1711 : /**
1712 : * \brief Drop raster data cache : data in cache will be lost.
1713 : *
1714 : * This call will recover memory used to cache data blocks for this raster
1715 : * band, and ensure that new requests are referred to the underlying driver.
1716 : *
1717 : * This method is the same as the C function GDALDropRasterCache().
1718 : *
1719 : * @return CE_None on success.
1720 : * @since 3.9
1721 : */
1722 :
1723 1 : CPLErr GDALRasterBand::DropCache()
1724 :
1725 : {
1726 1 : CPLErr result = CE_None;
1727 :
1728 1 : if (poBandBlockCache)
1729 1 : poBandBlockCache->DisableDirtyBlockWriting();
1730 :
1731 1 : CPLErr eGlobalErr = eFlushBlockErr;
1732 :
1733 1 : if (eFlushBlockErr != CE_None)
1734 : {
1735 0 : ReportError(
1736 : eFlushBlockErr, CPLE_AppDefined,
1737 : "An error occurred while writing a dirty block from DropCache");
1738 0 : eFlushBlockErr = CE_None;
1739 : }
1740 :
1741 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1742 0 : result = eGlobalErr;
1743 : else
1744 1 : result = poBandBlockCache->FlushCache();
1745 :
1746 1 : if (poBandBlockCache)
1747 1 : poBandBlockCache->EnableDirtyBlockWriting();
1748 :
1749 1 : return result;
1750 : }
1751 :
1752 : /************************************************************************/
1753 : /* GDALDropRasterCache() */
1754 : /************************************************************************/
1755 :
1756 : /**
1757 : * \brief Drop raster data cache.
1758 : *
1759 : * @see GDALRasterBand::DropCache()
1760 : * @since 3.9
1761 : */
1762 :
1763 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1764 :
1765 : {
1766 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1767 :
1768 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1769 : }
1770 :
1771 : /************************************************************************/
1772 : /* UnreferenceBlock() */
1773 : /* */
1774 : /* Unreference the block from our array of blocks */
1775 : /* This method should only be called by */
1776 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1777 : /* the block cache mutex) */
1778 : /************************************************************************/
1779 :
1780 29635 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1781 : {
1782 : #ifdef notdef
1783 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1784 : {
1785 : if (poBandBlockCache == nullptr)
1786 : printf("poBandBlockCache == NULL\n"); /*ok*/
1787 : else
1788 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1789 : printf("caller = %s\n", pszCaller); /*ok*/
1790 : printf("GDALRasterBand: %p\n", this); /*ok*/
1791 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1792 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1793 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1794 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1795 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1796 : poBlock->DumpBlock();
1797 : if (GetDataset() != nullptr)
1798 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1799 : GDALRasterBlock::Verify();
1800 : abort();
1801 : }
1802 : #endif
1803 29635 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1804 29635 : return poBandBlockCache->UnreferenceBlock(poBlock);
1805 : }
1806 :
1807 : /************************************************************************/
1808 : /* AddBlockToFreeList() */
1809 : /* */
1810 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1811 : /* finished with a block about to be free'd, they pass it to that */
1812 : /* method. */
1813 : /************************************************************************/
1814 :
1815 : //! @cond Doxygen_Suppress
1816 29635 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1817 : {
1818 29635 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1819 29635 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1820 : }
1821 :
1822 : //! @endcond
1823 :
1824 : /************************************************************************/
1825 : /* HasDirtyBlocks() */
1826 : /************************************************************************/
1827 :
1828 : //! @cond Doxygen_Suppress
1829 17 : bool GDALRasterBand::HasDirtyBlocks() const
1830 : {
1831 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1832 : }
1833 :
1834 : //! @endcond
1835 :
1836 : /************************************************************************/
1837 : /* FlushBlock() */
1838 : /************************************************************************/
1839 :
1840 : /** Flush a block out of the block cache.
1841 : * @param nXBlockOff block x offset
1842 : * @param nYBlockOff blocky offset
1843 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1844 : * @return CE_None in case of success, an error code otherwise.
1845 : */
1846 2315 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1847 : int bWriteDirtyBlock)
1848 :
1849 : {
1850 2315 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1851 0 : return (CE_Failure);
1852 :
1853 : /* -------------------------------------------------------------------- */
1854 : /* Validate the request */
1855 : /* -------------------------------------------------------------------- */
1856 2315 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1857 : {
1858 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1859 : "Illegal nBlockXOff value (%d) in "
1860 : "GDALRasterBand::FlushBlock()\n",
1861 : nXBlockOff);
1862 :
1863 0 : return (CE_Failure);
1864 : }
1865 :
1866 2315 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1867 : {
1868 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1869 : "Illegal nBlockYOff value (%d) in "
1870 : "GDALRasterBand::FlushBlock()\n",
1871 : nYBlockOff);
1872 :
1873 0 : return (CE_Failure);
1874 : }
1875 :
1876 2315 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1877 2315 : bWriteDirtyBlock);
1878 : }
1879 :
1880 : /************************************************************************/
1881 : /* TryGetLockedBlockRef() */
1882 : /************************************************************************/
1883 :
1884 : /**
1885 : * \brief Try fetching block ref.
1886 : *
1887 : * This method will returned the requested block (locked) if it is already
1888 : * in the block cache for the layer. If not, nullptr is returned.
1889 : *
1890 : * If a non-NULL value is returned, then a lock for the block will have been
1891 : * acquired on behalf of the caller. It is absolutely imperative that the
1892 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1893 : * severe problems may result.
1894 : *
1895 : * @param nXBlockOff the horizontal block offset, with zero indicating
1896 : * the left most block, 1 the next block and so forth.
1897 : *
1898 : * @param nYBlockOff the vertical block offset, with zero indicating
1899 : * the top most block, 1 the next block and so forth.
1900 : *
1901 : * @return NULL if block not available, or locked block pointer.
1902 : */
1903 :
1904 10766300 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1905 : int nYBlockOff)
1906 :
1907 : {
1908 10766300 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1909 174048 : return nullptr;
1910 :
1911 : /* -------------------------------------------------------------------- */
1912 : /* Validate the request */
1913 : /* -------------------------------------------------------------------- */
1914 10592200 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1915 : {
1916 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1917 : "Illegal nBlockXOff value (%d) in "
1918 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1919 : nXBlockOff);
1920 :
1921 0 : return (nullptr);
1922 : }
1923 :
1924 10592200 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1925 : {
1926 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1927 : "Illegal nBlockYOff value (%d) in "
1928 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1929 : nYBlockOff);
1930 :
1931 0 : return (nullptr);
1932 : }
1933 :
1934 10592200 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1935 : }
1936 :
1937 : /************************************************************************/
1938 : /* GetLockedBlockRef() */
1939 : /************************************************************************/
1940 :
1941 : /**
1942 : * \brief Fetch a pointer to an internally cached raster block.
1943 : *
1944 : * This method will returned the requested block (locked) if it is already
1945 : * in the block cache for the layer. If not, the block will be read from
1946 : * the driver, and placed in the layer block cached, then returned. If an
1947 : * error occurs reading the block from the driver, a NULL value will be
1948 : * returned.
1949 : *
1950 : * If a non-NULL value is returned, then a lock for the block will have been
1951 : * acquired on behalf of the caller. It is absolutely imperative that the
1952 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1953 : * severe problems may result.
1954 : *
1955 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1956 : * enable caching.
1957 : *
1958 : * @param nXBlockOff the horizontal block offset, with zero indicating
1959 : * the left most block, 1 the next block and so forth.
1960 : *
1961 : * @param nYBlockOff the vertical block offset, with zero indicating
1962 : * the top most block, 1 the next block and so forth.
1963 : *
1964 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1965 : * but not actually read from the source. This is useful when it will just
1966 : * be completely set and written back.
1967 : *
1968 : * @return pointer to the block object, or NULL on failure.
1969 : */
1970 :
1971 10455800 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1972 : int nYBlockOff,
1973 : int bJustInitialize)
1974 :
1975 : {
1976 : /* -------------------------------------------------------------------- */
1977 : /* Try and fetch from cache. */
1978 : /* -------------------------------------------------------------------- */
1979 10455800 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1980 :
1981 : /* -------------------------------------------------------------------- */
1982 : /* If we didn't find it in our memory cache, instantiate a */
1983 : /* block (potentially load from disk) and "adopt" it into the */
1984 : /* cache. */
1985 : /* -------------------------------------------------------------------- */
1986 10455800 : if (poBlock == nullptr)
1987 : {
1988 3398740 : if (!InitBlockInfo())
1989 0 : return (nullptr);
1990 :
1991 : /* --------------------------------------------------------------------
1992 : */
1993 : /* Validate the request */
1994 : /* --------------------------------------------------------------------
1995 : */
1996 3398740 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1997 : {
1998 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1999 : "Illegal nBlockXOff value (%d) in "
2000 : "GDALRasterBand::GetLockedBlockRef()\n",
2001 : nXBlockOff);
2002 :
2003 0 : return (nullptr);
2004 : }
2005 :
2006 3398740 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
2007 : {
2008 0 : ReportError(CE_Failure, CPLE_IllegalArg,
2009 : "Illegal nBlockYOff value (%d) in "
2010 : "GDALRasterBand::GetLockedBlockRef()\n",
2011 : nYBlockOff);
2012 :
2013 0 : return (nullptr);
2014 : }
2015 :
2016 3398740 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2017 3398740 : if (poBlock == nullptr)
2018 0 : return nullptr;
2019 :
2020 3398740 : poBlock->AddLock();
2021 :
2022 : /* We need to temporarily drop the read-write lock in the following */
2023 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2024 : */
2025 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2026 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2027 : */
2028 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2029 : */
2030 : /* called and attempt at taking the lock on T2 (already taken).
2031 : * Similarly */
2032 : /* for T2 with D1, hence a deadlock situation (#6163) */
2033 : /* But this may open the door to other problems... */
2034 3398740 : if (poDS)
2035 3398000 : poDS->TemporarilyDropReadWriteLock();
2036 : /* allocate data space */
2037 3398740 : CPLErr eErr = poBlock->Internalize();
2038 3398740 : if (poDS)
2039 3398000 : poDS->ReacquireReadWriteLock();
2040 3398740 : if (eErr != CE_None)
2041 : {
2042 0 : poBlock->DropLock();
2043 0 : delete poBlock;
2044 0 : return nullptr;
2045 : }
2046 :
2047 3398740 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2048 : {
2049 0 : poBlock->DropLock();
2050 0 : delete poBlock;
2051 0 : return nullptr;
2052 : }
2053 :
2054 3398740 : if (!bJustInitialize)
2055 : {
2056 2900860 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2057 2900860 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2058 2900860 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2059 2900860 : if (bCallLeaveReadWrite)
2060 133890 : LeaveReadWrite();
2061 2900860 : if (eErr != CE_None)
2062 : {
2063 1165 : poBlock->DropLock();
2064 1165 : FlushBlock(nXBlockOff, nYBlockOff);
2065 1165 : ReportError(CE_Failure, CPLE_AppDefined,
2066 : "IReadBlock failed at X offset %d, Y offset %d%s",
2067 : nXBlockOff, nYBlockOff,
2068 1165 : (nErrorCounter != CPLGetErrorCounter())
2069 1163 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2070 : : "");
2071 1165 : return nullptr;
2072 : }
2073 :
2074 2899700 : nBlockReads++;
2075 2899700 : if (static_cast<GIntBig>(nBlockReads) ==
2076 2899700 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2077 244 : 1 &&
2078 244 : nBand == 1 && poDS != nullptr)
2079 : {
2080 175 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2081 175 : poDS->GetDescription());
2082 : }
2083 : }
2084 : }
2085 :
2086 10454600 : return poBlock;
2087 : }
2088 :
2089 : /************************************************************************/
2090 : /* Fill() */
2091 : /************************************************************************/
2092 :
2093 : /**
2094 : * \brief Fill this band with a constant value.
2095 : *
2096 : * GDAL makes no guarantees
2097 : * about what values pixels in newly created files are set to, so this
2098 : * method can be used to clear a band to a specified "default" value.
2099 : * The fill value is passed in as a double but this will be converted
2100 : * to the underlying type before writing to the file. An optional
2101 : * second argument allows the imaginary component of a complex
2102 : * constant value to be specified.
2103 : *
2104 : * This method is the same as the C function GDALFillRaster().
2105 : *
2106 : * @param dfRealValue Real component of fill value
2107 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2108 : *
2109 : * @return CE_Failure if the write fails, otherwise CE_None
2110 : */
2111 269827 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2112 : {
2113 :
2114 : // General approach is to construct a source block of the file's
2115 : // native type containing the appropriate value and then copy this
2116 : // to each block in the image via the RasterBlock cache. Using
2117 : // the cache means we avoid file I/O if it is not necessary, at the
2118 : // expense of some extra memcpy's (since we write to the
2119 : // RasterBlock cache, which is then at some point written to the
2120 : // underlying file, rather than simply directly to the underlying
2121 : // file.)
2122 :
2123 : // Check we can write to the file.
2124 269827 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2125 : {
2126 6 : return CE_Failure;
2127 : }
2128 :
2129 : // Make sure block parameters are set.
2130 269821 : if (!InitBlockInfo())
2131 0 : return CE_Failure;
2132 :
2133 : // Allocate the source block.
2134 269821 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2135 269821 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2136 269821 : auto blockByteSize = blockSize * elementSize;
2137 : unsigned char *srcBlock =
2138 269821 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2139 269821 : if (srcBlock == nullptr)
2140 : {
2141 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2142 : "GDALRasterBand::Fill(): Out of memory "
2143 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2144 : static_cast<GUIntBig>(blockByteSize));
2145 0 : return CE_Failure;
2146 : }
2147 :
2148 : // Initialize the source block.
2149 269821 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2150 269821 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2151 : elementSize, blockSize);
2152 :
2153 269821 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2154 :
2155 : // Write block to block cache
2156 881425 : for (int j = 0; j < nBlocksPerColumn; ++j)
2157 : {
2158 1517580 : for (int i = 0; i < nBlocksPerRow; ++i)
2159 : {
2160 905978 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2161 905978 : if (destBlock == nullptr)
2162 : {
2163 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2164 : "GDALRasterBand::Fill(): Error "
2165 : "while retrieving cache block.");
2166 0 : VSIFree(srcBlock);
2167 0 : return CE_Failure;
2168 : }
2169 905978 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2170 905978 : destBlock->MarkDirty();
2171 905978 : destBlock->DropLock();
2172 : }
2173 : }
2174 :
2175 269821 : if (bCallLeaveReadWrite)
2176 267757 : LeaveReadWrite();
2177 :
2178 : // Free up the source block
2179 269821 : VSIFree(srcBlock);
2180 :
2181 269821 : return CE_None;
2182 : }
2183 :
2184 : /************************************************************************/
2185 : /* GDALFillRaster() */
2186 : /************************************************************************/
2187 :
2188 : /**
2189 : * \brief Fill this band with a constant value.
2190 : *
2191 : * @see GDALRasterBand::Fill()
2192 : */
2193 269597 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2194 : double dfImaginaryValue)
2195 : {
2196 269597 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2197 :
2198 269597 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2199 269597 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2200 : }
2201 :
2202 : /************************************************************************/
2203 : /* GetAccess() */
2204 : /************************************************************************/
2205 :
2206 : /**
2207 : * \brief Find out if we have update permission for this band.
2208 : *
2209 : * This method is the same as the C function GDALGetRasterAccess().
2210 : *
2211 : * @return Either GA_Update or GA_ReadOnly.
2212 : */
2213 :
2214 3224 : GDALAccess GDALRasterBand::GetAccess()
2215 :
2216 : {
2217 3224 : return eAccess;
2218 : }
2219 :
2220 : /************************************************************************/
2221 : /* GDALGetRasterAccess() */
2222 : /************************************************************************/
2223 :
2224 : /**
2225 : * \brief Find out if we have update permission for this band.
2226 : *
2227 : * @see GDALRasterBand::GetAccess()
2228 : */
2229 :
2230 2564 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2231 :
2232 : {
2233 2564 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2234 :
2235 2564 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2236 2564 : return poBand->GetAccess();
2237 : }
2238 :
2239 : /************************************************************************/
2240 : /* GetCategoryNames() */
2241 : /************************************************************************/
2242 :
2243 : /**
2244 : * \brief Fetch the list of category names for this raster.
2245 : *
2246 : * The return list is a "StringList" in the sense of the CPL functions.
2247 : * That is a NULL terminated array of strings. Raster values without
2248 : * associated names will have an empty string in the returned list. The
2249 : * first entry in the list is for raster values of zero, and so on.
2250 : *
2251 : * The returned stringlist should not be altered or freed by the application.
2252 : * It may change on the next GDAL call, so please copy it if it is needed
2253 : * for any period of time.
2254 : *
2255 : * This method is the same as the C function GDALGetRasterCategoryNames().
2256 : *
2257 : * @return list of names, or NULL if none.
2258 : */
2259 :
2260 332 : char **GDALRasterBand::GetCategoryNames()
2261 :
2262 : {
2263 332 : return nullptr;
2264 : }
2265 :
2266 : /************************************************************************/
2267 : /* GDALGetRasterCategoryNames() */
2268 : /************************************************************************/
2269 :
2270 : /**
2271 : * \brief Fetch the list of category names for this raster.
2272 : *
2273 : * @see GDALRasterBand::GetCategoryNames()
2274 : */
2275 :
2276 210 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2277 :
2278 : {
2279 210 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2280 :
2281 210 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2282 210 : return poBand->GetCategoryNames();
2283 : }
2284 :
2285 : /************************************************************************/
2286 : /* SetCategoryNames() */
2287 : /************************************************************************/
2288 :
2289 : /**
2290 : * \fn GDALRasterBand::SetCategoryNames(char**)
2291 : * \brief Set the category names for this band.
2292 : *
2293 : * See the GetCategoryNames() method for more on the interpretation of
2294 : * category names.
2295 : *
2296 : * This method is the same as the C function GDALSetRasterCategoryNames().
2297 : *
2298 : * @param papszNames the NULL terminated StringList of category names. May
2299 : * be NULL to just clear the existing list.
2300 : *
2301 : * @return CE_None on success of CE_Failure on failure. If unsupported
2302 : * by the driver CE_Failure is returned, but no error message is reported.
2303 : */
2304 :
2305 : /**/
2306 : /**/
2307 :
2308 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2309 : {
2310 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2311 0 : ReportError(CE_Failure, CPLE_NotSupported,
2312 : "SetCategoryNames() not supported for this dataset.");
2313 :
2314 0 : return CE_Failure;
2315 : }
2316 :
2317 : /************************************************************************/
2318 : /* GDALSetCategoryNames() */
2319 : /************************************************************************/
2320 :
2321 : /**
2322 : * \brief Set the category names for this band.
2323 : *
2324 : * @see GDALRasterBand::SetCategoryNames()
2325 : */
2326 :
2327 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2328 : CSLConstList papszNames)
2329 :
2330 : {
2331 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2332 :
2333 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2334 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2335 : }
2336 :
2337 : /************************************************************************/
2338 : /* GetNoDataValue() */
2339 : /************************************************************************/
2340 :
2341 : /**
2342 : * \brief Fetch the no data value for this band.
2343 : *
2344 : * If there is no out of data value, an out of range value will generally
2345 : * be returned. The no data value for a band is generally a special marker
2346 : * value used to mark pixels that are not valid data. Such pixels should
2347 : * generally not be displayed, nor contribute to analysis operations.
2348 : *
2349 : * The no data value returned is 'raw', meaning that it has no offset and
2350 : * scale applied.
2351 : *
2352 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2353 : * lossy if the nodata value cannot exactly been represented by a double.
2354 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2355 : *
2356 : * This method is the same as the C function GDALGetRasterNoDataValue().
2357 : *
2358 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2359 : * is actually associated with this layer. May be NULL (default).
2360 : *
2361 : * @return the nodata value for this band.
2362 : */
2363 :
2364 31877 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2365 :
2366 : {
2367 31877 : if (pbSuccess != nullptr)
2368 31877 : *pbSuccess = FALSE;
2369 :
2370 31877 : return -1e10;
2371 : }
2372 :
2373 : /************************************************************************/
2374 : /* GDALGetRasterNoDataValue() */
2375 : /************************************************************************/
2376 :
2377 : /**
2378 : * \brief Fetch the no data value for this band.
2379 : *
2380 : * @see GDALRasterBand::GetNoDataValue()
2381 : */
2382 :
2383 415181 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2384 : int *pbSuccess)
2385 :
2386 : {
2387 415181 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2388 :
2389 415181 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2390 415181 : return poBand->GetNoDataValue(pbSuccess);
2391 : }
2392 :
2393 : /************************************************************************/
2394 : /* GetNoDataValueAsInt64() */
2395 : /************************************************************************/
2396 :
2397 : /**
2398 : * \brief Fetch the no data value for this band.
2399 : *
2400 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2401 : *
2402 : * If there is no out of data value, an out of range value will generally
2403 : * be returned. The no data value for a band is generally a special marker
2404 : * value used to mark pixels that are not valid data. Such pixels should
2405 : * generally not be displayed, nor contribute to analysis operations.
2406 : *
2407 : * The no data value returned is 'raw', meaning that it has no offset and
2408 : * scale applied.
2409 : *
2410 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2411 : *
2412 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2413 : * is actually associated with this layer. May be NULL (default).
2414 : *
2415 : * @return the nodata value for this band.
2416 : *
2417 : * @since GDAL 3.5
2418 : */
2419 :
2420 11 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2421 :
2422 : {
2423 11 : if (pbSuccess != nullptr)
2424 11 : *pbSuccess = FALSE;
2425 :
2426 11 : return std::numeric_limits<int64_t>::min();
2427 : }
2428 :
2429 : /************************************************************************/
2430 : /* GDALGetRasterNoDataValueAsInt64() */
2431 : /************************************************************************/
2432 :
2433 : /**
2434 : * \brief Fetch the no data value for this band.
2435 : *
2436 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2437 : *
2438 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2439 : *
2440 : * @since GDAL 3.5
2441 : */
2442 :
2443 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2444 : int *pbSuccess)
2445 :
2446 : {
2447 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2448 : std::numeric_limits<int64_t>::min());
2449 :
2450 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2451 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2452 : }
2453 :
2454 : /************************************************************************/
2455 : /* GetNoDataValueAsUInt64() */
2456 : /************************************************************************/
2457 :
2458 : /**
2459 : * \brief Fetch the no data value for this band.
2460 : *
2461 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2462 : *
2463 : * If there is no out of data value, an out of range value will generally
2464 : * be returned. The no data value for a band is generally a special marker
2465 : * value used to mark pixels that are not valid data. Such pixels should
2466 : * generally not be displayed, nor contribute to analysis operations.
2467 : *
2468 : * The no data value returned is 'raw', meaning that it has no offset and
2469 : * scale applied.
2470 : *
2471 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2472 : *
2473 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2474 : * is actually associated with this layer. May be NULL (default).
2475 : *
2476 : * @return the nodata value for this band.
2477 : *
2478 : * @since GDAL 3.5
2479 : */
2480 :
2481 10 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2482 :
2483 : {
2484 10 : if (pbSuccess != nullptr)
2485 10 : *pbSuccess = FALSE;
2486 :
2487 10 : return std::numeric_limits<uint64_t>::max();
2488 : }
2489 :
2490 : /************************************************************************/
2491 : /* GDALGetRasterNoDataValueAsUInt64() */
2492 : /************************************************************************/
2493 :
2494 : /**
2495 : * \brief Fetch the no data value for this band.
2496 : *
2497 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2498 : *
2499 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2500 : *
2501 : * @since GDAL 3.5
2502 : */
2503 :
2504 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2505 : int *pbSuccess)
2506 :
2507 : {
2508 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2509 : std::numeric_limits<uint64_t>::max());
2510 :
2511 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2512 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2513 : }
2514 :
2515 : /************************************************************************/
2516 : /* SetNoDataValueAsString() */
2517 : /************************************************************************/
2518 :
2519 : /**
2520 : * \brief Set the no data value for this band.
2521 : *
2522 : * Depending on drivers, changing the no data value may or may not have an
2523 : * effect on the pixel values of a raster that has just been created. It is
2524 : * thus advised to explicitly called Fill() if the intent is to initialize
2525 : * the raster to the nodata value.
2526 : * In any case, changing an existing no data value, when one already exists and
2527 : * the dataset exists or has been initialized, has no effect on the pixel whose
2528 : * value matched the previous nodata value.
2529 : *
2530 : * To clear the nodata value, use DeleteNoDataValue().
2531 : *
2532 : * @param pszNoData the value to set.
2533 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2534 : * If the value cannot be exactly represented on the output data
2535 : * type, *pbCannotBeExactlyRepresented will be set to true.
2536 : *
2537 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2538 : * by the driver, CE_Failure is returned but no error message will have
2539 : * been emitted.
2540 : *
2541 : * @since 3.11
2542 : */
2543 :
2544 : CPLErr
2545 126 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2546 : bool *pbCannotBeExactlyRepresented)
2547 : {
2548 126 : if (pbCannotBeExactlyRepresented)
2549 126 : *pbCannotBeExactlyRepresented = false;
2550 126 : if (eDataType == GDT_Int64)
2551 : {
2552 8 : if (strchr(pszNoData, '.') ||
2553 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2554 : {
2555 2 : char *endptr = nullptr;
2556 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2557 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2558 2 : GDALIsValueExactAs<int64_t>(dfVal))
2559 : {
2560 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2561 : }
2562 : }
2563 : else
2564 : {
2565 : try
2566 : {
2567 7 : const auto val = std::stoll(pszNoData);
2568 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2569 : }
2570 2 : catch (const std::exception &)
2571 : {
2572 : }
2573 : }
2574 : }
2575 121 : else if (eDataType == GDT_UInt64)
2576 : {
2577 2 : if (strchr(pszNoData, '.') ||
2578 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2579 : {
2580 0 : char *endptr = nullptr;
2581 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2582 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2583 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2584 : {
2585 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2586 : }
2587 : }
2588 : else
2589 : {
2590 : try
2591 : {
2592 1 : const auto val = std::stoull(pszNoData);
2593 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2594 : }
2595 0 : catch (const std::exception &)
2596 : {
2597 : }
2598 : }
2599 : }
2600 120 : else if (eDataType == GDT_Float32)
2601 : {
2602 10 : char *endptr = nullptr;
2603 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2604 10 : if (endptr == pszNoData + strlen(pszNoData))
2605 : {
2606 10 : return SetNoDataValue(double(fVal));
2607 : }
2608 : }
2609 : else
2610 : {
2611 110 : char *endptr = nullptr;
2612 110 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2613 220 : if (endptr == pszNoData + strlen(pszNoData) &&
2614 110 : GDALIsValueExactAs(dfVal, eDataType))
2615 : {
2616 109 : return SetNoDataValue(dfVal);
2617 : }
2618 : }
2619 5 : if (pbCannotBeExactlyRepresented)
2620 5 : *pbCannotBeExactlyRepresented = true;
2621 5 : return CE_Failure;
2622 : }
2623 :
2624 : /************************************************************************/
2625 : /* SetNoDataValue() */
2626 : /************************************************************************/
2627 :
2628 : /**
2629 : * \fn GDALRasterBand::SetNoDataValue(double)
2630 : * \brief Set the no data value for this band.
2631 : *
2632 : * Depending on drivers, changing the no data value may or may not have an
2633 : * effect on the pixel values of a raster that has just been created. It is
2634 : * thus advised to explicitly called Fill() if the intent is to initialize
2635 : * the raster to the nodata value.
2636 : * In any case, changing an existing no data value, when one already exists and
2637 : * the dataset exists or has been initialized, has no effect on the pixel whose
2638 : * value matched the previous nodata value.
2639 : *
2640 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2641 : * be represented by a double, use SetNoDataValueAsInt64() or
2642 : * SetNoDataValueAsUInt64() instead.
2643 : *
2644 : * To clear the nodata value, use DeleteNoDataValue().
2645 : *
2646 : * This method is the same as the C function GDALSetRasterNoDataValue().
2647 : *
2648 : * @param dfNoData the value to set.
2649 : *
2650 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2651 : * by the driver, CE_Failure is returned but no error message will have
2652 : * been emitted.
2653 : */
2654 :
2655 : /**/
2656 : /**/
2657 :
2658 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2659 :
2660 : {
2661 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2662 0 : ReportError(CE_Failure, CPLE_NotSupported,
2663 : "SetNoDataValue() not supported for this dataset.");
2664 :
2665 0 : return CE_Failure;
2666 : }
2667 :
2668 : /************************************************************************/
2669 : /* GDALSetRasterNoDataValue() */
2670 : /************************************************************************/
2671 :
2672 : /**
2673 : * \brief Set the no data value for this band.
2674 : *
2675 : * Depending on drivers, changing the no data value may or may not have an
2676 : * effect on the pixel values of a raster that has just been created. It is
2677 : * thus advised to explicitly called Fill() if the intent is to initialize
2678 : * the raster to the nodata value.
2679 : * In any case, changing an existing no data value, when one already exists and
2680 : * the dataset exists or has been initialized, has no effect on the pixel whose
2681 : * value matched the previous nodata value.
2682 : *
2683 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2684 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2685 : * GDALSetRasterNoDataValueAsUInt64() instead.
2686 : *
2687 : * @see GDALRasterBand::SetNoDataValue()
2688 : */
2689 :
2690 1277 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2691 : double dfValue)
2692 :
2693 : {
2694 1277 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2695 :
2696 1277 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2697 1277 : return poBand->SetNoDataValue(dfValue);
2698 : }
2699 :
2700 : /************************************************************************/
2701 : /* SetNoDataValueAsInt64() */
2702 : /************************************************************************/
2703 :
2704 : /**
2705 : * \brief Set the no data value for this band.
2706 : *
2707 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2708 : *
2709 : * Depending on drivers, changing the no data value may or may not have an
2710 : * effect on the pixel values of a raster that has just been created. It is
2711 : * thus advised to explicitly called Fill() if the intent is to initialize
2712 : * the raster to the nodata value.
2713 : * In ay case, changing an existing no data value, when one already exists and
2714 : * the dataset exists or has been initialized, has no effect on the pixel whose
2715 : * value matched the previous nodata value.
2716 : *
2717 : * To clear the nodata value, use DeleteNoDataValue().
2718 : *
2719 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2720 : *
2721 : * @param nNoDataValue the value to set.
2722 : *
2723 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2724 : * by the driver, CE_Failure is returned but no error message will have
2725 : * been emitted.
2726 : *
2727 : * @since GDAL 3.5
2728 : */
2729 :
2730 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2731 :
2732 : {
2733 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2734 0 : ReportError(CE_Failure, CPLE_NotSupported,
2735 : "SetNoDataValueAsInt64() not supported for this dataset.");
2736 :
2737 0 : return CE_Failure;
2738 : }
2739 :
2740 : /************************************************************************/
2741 : /* GDALSetRasterNoDataValueAsInt64() */
2742 : /************************************************************************/
2743 :
2744 : /**
2745 : * \brief Set the no data value for this band.
2746 : *
2747 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2748 : *
2749 : * Depending on drivers, changing the no data value may or may not have an
2750 : * effect on the pixel values of a raster that has just been created. It is
2751 : * thus advised to explicitly called Fill() if the intent is to initialize
2752 : * the raster to the nodata value.
2753 : * In ay case, changing an existing no data value, when one already exists and
2754 : * the dataset exists or has been initialized, has no effect on the pixel whose
2755 : * value matched the previous nodata value.
2756 : *
2757 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2758 : *
2759 : * @since GDAL 3.5
2760 : */
2761 :
2762 24 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2763 : int64_t nValue)
2764 :
2765 : {
2766 24 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2767 :
2768 24 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2769 24 : return poBand->SetNoDataValueAsInt64(nValue);
2770 : }
2771 :
2772 : /************************************************************************/
2773 : /* SetNoDataValueAsUInt64() */
2774 : /************************************************************************/
2775 :
2776 : /**
2777 : * \brief Set the no data value for this band.
2778 : *
2779 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2780 : *
2781 : * Depending on drivers, changing the no data value may or may not have an
2782 : * effect on the pixel values of a raster that has just been created. It is
2783 : * thus advised to explicitly called Fill() if the intent is to initialize
2784 : * the raster to the nodata value.
2785 : * In ay case, changing an existing no data value, when one already exists and
2786 : * the dataset exists or has been initialized, has no effect on the pixel whose
2787 : * value matched the previous nodata value.
2788 : *
2789 : * To clear the nodata value, use DeleteNoDataValue().
2790 : *
2791 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2792 : *
2793 : * @param nNoDataValue the value to set.
2794 : *
2795 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2796 : * by the driver, CE_Failure is returned but no error message will have
2797 : * been emitted.
2798 : *
2799 : * @since GDAL 3.5
2800 : */
2801 :
2802 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2803 :
2804 : {
2805 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2806 0 : ReportError(CE_Failure, CPLE_NotSupported,
2807 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2808 :
2809 0 : return CE_Failure;
2810 : }
2811 :
2812 : /************************************************************************/
2813 : /* GDALSetRasterNoDataValueAsUInt64() */
2814 : /************************************************************************/
2815 :
2816 : /**
2817 : * \brief Set the no data value for this band.
2818 : *
2819 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2820 : *
2821 : * Depending on drivers, changing the no data value may or may not have an
2822 : * effect on the pixel values of a raster that has just been created. It is
2823 : * thus advised to explicitly called Fill() if the intent is to initialize
2824 : * the raster to the nodata value.
2825 : * In ay case, changing an existing no data value, when one already exists and
2826 : * the dataset exists or has been initialized, has no effect on the pixel whose
2827 : * value matched the previous nodata value.
2828 : *
2829 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2830 : *
2831 : * @since GDAL 3.5
2832 : */
2833 :
2834 23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2835 : uint64_t nValue)
2836 :
2837 : {
2838 23 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2839 :
2840 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2841 23 : return poBand->SetNoDataValueAsUInt64(nValue);
2842 : }
2843 :
2844 : /************************************************************************/
2845 : /* DeleteNoDataValue() */
2846 : /************************************************************************/
2847 :
2848 : /**
2849 : * \brief Remove the no data value for this band.
2850 : *
2851 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2852 : *
2853 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2854 : * by the driver, CE_Failure is returned but no error message will have
2855 : * been emitted.
2856 : *
2857 : */
2858 :
2859 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2860 :
2861 : {
2862 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2863 0 : ReportError(CE_Failure, CPLE_NotSupported,
2864 : "DeleteNoDataValue() not supported for this dataset.");
2865 :
2866 0 : return CE_Failure;
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* GDALDeleteRasterNoDataValue() */
2871 : /************************************************************************/
2872 :
2873 : /**
2874 : * \brief Remove the no data value for this band.
2875 : *
2876 : * @see GDALRasterBand::DeleteNoDataValue()
2877 : *
2878 : */
2879 :
2880 56 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2881 :
2882 : {
2883 56 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2884 :
2885 56 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2886 56 : return poBand->DeleteNoDataValue();
2887 : }
2888 :
2889 : /************************************************************************/
2890 : /* GetMaximum() */
2891 : /************************************************************************/
2892 :
2893 : /**
2894 : * \brief Fetch the maximum value for this band.
2895 : *
2896 : * For file formats that don't know this intrinsically, the maximum supported
2897 : * value for the data type will generally be returned.
2898 : *
2899 : * This method is the same as the C function GDALGetRasterMaximum().
2900 : *
2901 : * @param pbSuccess pointer to a boolean to use to indicate if the
2902 : * returned value is a tight maximum or not. May be NULL (default).
2903 : *
2904 : * @return the maximum raster value (excluding no data pixels)
2905 : */
2906 :
2907 548 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2908 :
2909 : {
2910 548 : const char *pszValue = nullptr;
2911 :
2912 548 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2913 : {
2914 47 : if (pbSuccess != nullptr)
2915 42 : *pbSuccess = TRUE;
2916 :
2917 47 : return CPLAtofM(pszValue);
2918 : }
2919 :
2920 501 : if (pbSuccess != nullptr)
2921 497 : *pbSuccess = FALSE;
2922 :
2923 501 : switch (eDataType)
2924 : {
2925 345 : case GDT_UInt8:
2926 : {
2927 345 : EnablePixelTypeSignedByteWarning(false);
2928 : const char *pszPixelType =
2929 345 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2930 345 : EnablePixelTypeSignedByteWarning(true);
2931 345 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2932 0 : return 127;
2933 :
2934 345 : return 255;
2935 : }
2936 :
2937 1 : case GDT_Int8:
2938 1 : return 127;
2939 :
2940 21 : case GDT_UInt16:
2941 21 : return 65535;
2942 :
2943 24 : case GDT_Int16:
2944 : case GDT_CInt16:
2945 24 : return 32767;
2946 :
2947 39 : case GDT_Int32:
2948 : case GDT_CInt32:
2949 39 : return 2147483647.0;
2950 :
2951 14 : case GDT_UInt32:
2952 14 : return 4294967295.0;
2953 :
2954 1 : case GDT_Int64:
2955 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2956 :
2957 1 : case GDT_UInt64:
2958 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2959 :
2960 0 : case GDT_Float16:
2961 : case GDT_CFloat16:
2962 0 : return 65504.0;
2963 :
2964 33 : case GDT_Float32:
2965 : case GDT_CFloat32:
2966 33 : return 4294967295.0; // Not actually accurate.
2967 :
2968 22 : case GDT_Float64:
2969 : case GDT_CFloat64:
2970 22 : return 4294967295.0; // Not actually accurate.
2971 :
2972 0 : case GDT_Unknown:
2973 : case GDT_TypeCount:
2974 0 : break;
2975 : }
2976 0 : return 4294967295.0; // Not actually accurate.
2977 : }
2978 :
2979 : /************************************************************************/
2980 : /* GDALGetRasterMaximum() */
2981 : /************************************************************************/
2982 :
2983 : /**
2984 : * \brief Fetch the maximum value for this band.
2985 : *
2986 : * @see GDALRasterBand::GetMaximum()
2987 : */
2988 :
2989 350 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2990 :
2991 : {
2992 350 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2993 :
2994 350 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2995 350 : return poBand->GetMaximum(pbSuccess);
2996 : }
2997 :
2998 : /************************************************************************/
2999 : /* GetMinimum() */
3000 : /************************************************************************/
3001 :
3002 : /**
3003 : * \brief Fetch the minimum value for this band.
3004 : *
3005 : * For file formats that don't know this intrinsically, the minimum supported
3006 : * value for the data type will generally be returned.
3007 : *
3008 : * This method is the same as the C function GDALGetRasterMinimum().
3009 : *
3010 : * @param pbSuccess pointer to a boolean to use to indicate if the
3011 : * returned value is a tight minimum or not. May be NULL (default).
3012 : *
3013 : * @return the minimum raster value (excluding no data pixels)
3014 : */
3015 :
3016 556 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3017 :
3018 : {
3019 556 : const char *pszValue = nullptr;
3020 :
3021 556 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3022 : {
3023 52 : if (pbSuccess != nullptr)
3024 47 : *pbSuccess = TRUE;
3025 :
3026 52 : return CPLAtofM(pszValue);
3027 : }
3028 :
3029 504 : if (pbSuccess != nullptr)
3030 500 : *pbSuccess = FALSE;
3031 :
3032 504 : switch (eDataType)
3033 : {
3034 348 : case GDT_UInt8:
3035 : {
3036 348 : EnablePixelTypeSignedByteWarning(false);
3037 : const char *pszPixelType =
3038 348 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3039 348 : EnablePixelTypeSignedByteWarning(true);
3040 348 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3041 0 : return -128;
3042 :
3043 348 : return 0;
3044 : }
3045 :
3046 1 : case GDT_Int8:
3047 1 : return -128;
3048 :
3049 21 : case GDT_UInt16:
3050 21 : return 0;
3051 :
3052 24 : case GDT_Int16:
3053 : case GDT_CInt16:
3054 24 : return -32768;
3055 :
3056 39 : case GDT_Int32:
3057 : case GDT_CInt32:
3058 39 : return -2147483648.0;
3059 :
3060 14 : case GDT_UInt32:
3061 14 : return 0;
3062 :
3063 1 : case GDT_Int64:
3064 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3065 :
3066 1 : case GDT_UInt64:
3067 1 : return 0;
3068 :
3069 0 : case GDT_Float16:
3070 : case GDT_CFloat16:
3071 0 : return -65504.0;
3072 :
3073 33 : case GDT_Float32:
3074 : case GDT_CFloat32:
3075 33 : return -4294967295.0; // Not actually accurate.
3076 :
3077 22 : case GDT_Float64:
3078 : case GDT_CFloat64:
3079 22 : return -4294967295.0; // Not actually accurate.
3080 :
3081 0 : case GDT_Unknown:
3082 : case GDT_TypeCount:
3083 0 : break;
3084 : }
3085 0 : return -4294967295.0; // Not actually accurate.
3086 : }
3087 :
3088 : /************************************************************************/
3089 : /* GDALGetRasterMinimum() */
3090 : /************************************************************************/
3091 :
3092 : /**
3093 : * \brief Fetch the minimum value for this band.
3094 : *
3095 : * @see GDALRasterBand::GetMinimum()
3096 : */
3097 :
3098 360 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3099 :
3100 : {
3101 360 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3102 :
3103 360 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3104 360 : return poBand->GetMinimum(pbSuccess);
3105 : }
3106 :
3107 : /************************************************************************/
3108 : /* GetColorInterpretation() */
3109 : /************************************************************************/
3110 :
3111 : /**
3112 : * \brief How should this band be interpreted as color?
3113 : *
3114 : * GCI_Undefined is returned when the format doesn't know anything
3115 : * about the color interpretation.
3116 : *
3117 : * This method is the same as the C function
3118 : * GDALGetRasterColorInterpretation().
3119 : *
3120 : * @return color interpretation value for band.
3121 : */
3122 :
3123 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3124 :
3125 : {
3126 163 : return GCI_Undefined;
3127 : }
3128 :
3129 : /************************************************************************/
3130 : /* GDALGetRasterColorInterpretation() */
3131 : /************************************************************************/
3132 :
3133 : /**
3134 : * \brief How should this band be interpreted as color?
3135 : *
3136 : * @see GDALRasterBand::GetColorInterpretation()
3137 : */
3138 :
3139 : GDALColorInterp CPL_STDCALL
3140 6441 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3141 :
3142 : {
3143 6441 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3144 :
3145 6441 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3146 6441 : return poBand->GetColorInterpretation();
3147 : }
3148 :
3149 : /************************************************************************/
3150 : /* SetColorInterpretation() */
3151 : /************************************************************************/
3152 :
3153 : /**
3154 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3155 : * \brief Set color interpretation of a band.
3156 : *
3157 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3158 : *
3159 : * @param eColorInterp the new color interpretation to apply to this band.
3160 : *
3161 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3162 : */
3163 :
3164 : /**/
3165 : /**/
3166 :
3167 1 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3168 :
3169 : {
3170 1 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3171 1 : ReportError(CE_Failure, CPLE_NotSupported,
3172 : "SetColorInterpretation() not supported for this dataset.");
3173 1 : return CE_Failure;
3174 : }
3175 :
3176 : /************************************************************************/
3177 : /* GDALSetRasterColorInterpretation() */
3178 : /************************************************************************/
3179 :
3180 : /**
3181 : * \brief Set color interpretation of a band.
3182 : *
3183 : * @see GDALRasterBand::SetColorInterpretation()
3184 : */
3185 :
3186 1891 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3187 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3188 :
3189 : {
3190 1891 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3191 :
3192 1891 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3193 1891 : return poBand->SetColorInterpretation(eColorInterp);
3194 : }
3195 :
3196 : /************************************************************************/
3197 : /* GetColorTable() */
3198 : /************************************************************************/
3199 :
3200 : /**
3201 : * \brief Fetch the color table associated with band.
3202 : *
3203 : * If there is no associated color table, the return result is NULL. The
3204 : * returned color table remains owned by the GDALRasterBand, and can't
3205 : * be depended on for long, nor should it ever be modified by the caller.
3206 : *
3207 : * This method is the same as the C function GDALGetRasterColorTable().
3208 : *
3209 : * @return internal color table, or NULL.
3210 : */
3211 :
3212 203 : GDALColorTable *GDALRasterBand::GetColorTable()
3213 :
3214 : {
3215 203 : return nullptr;
3216 : }
3217 :
3218 : /************************************************************************/
3219 : /* GDALGetRasterColorTable() */
3220 : /************************************************************************/
3221 :
3222 : /**
3223 : * \brief Fetch the color table associated with band.
3224 : *
3225 : * @see GDALRasterBand::GetColorTable()
3226 : */
3227 :
3228 2202 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3229 :
3230 : {
3231 2202 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3232 :
3233 2202 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3234 2202 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3235 : }
3236 :
3237 : /************************************************************************/
3238 : /* SetColorTable() */
3239 : /************************************************************************/
3240 :
3241 : /**
3242 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3243 : * \brief Set the raster color table.
3244 : *
3245 : * The driver will make a copy of all desired data in the colortable. It
3246 : * remains owned by the caller after the call.
3247 : *
3248 : * This method is the same as the C function GDALSetRasterColorTable().
3249 : *
3250 : * @param poCT the color table to apply. This may be NULL to clear the color
3251 : * table (where supported).
3252 : *
3253 : * @return CE_None on success, or CE_Failure on failure. If the action is
3254 : * unsupported by the driver, a value of CE_Failure is returned, but no
3255 : * error is issued.
3256 : */
3257 :
3258 : /**/
3259 : /**/
3260 :
3261 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3262 :
3263 : {
3264 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3265 0 : ReportError(CE_Failure, CPLE_NotSupported,
3266 : "SetColorTable() not supported for this dataset.");
3267 0 : return CE_Failure;
3268 : }
3269 :
3270 : /************************************************************************/
3271 : /* GDALSetRasterColorTable() */
3272 : /************************************************************************/
3273 :
3274 : /**
3275 : * \brief Set the raster color table.
3276 : *
3277 : * @see GDALRasterBand::SetColorTable()
3278 : */
3279 :
3280 105 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3281 : GDALColorTableH hCT)
3282 :
3283 : {
3284 105 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3285 :
3286 105 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3287 105 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3288 : }
3289 :
3290 : /************************************************************************/
3291 : /* HasArbitraryOverviews() */
3292 : /************************************************************************/
3293 :
3294 : /**
3295 : * \brief Check for arbitrary overviews.
3296 : *
3297 : * This returns TRUE if the underlying datastore can compute arbitrary
3298 : * overviews efficiently, such as is the case with OGDI over a network.
3299 : * Datastores with arbitrary overviews don't generally have any fixed
3300 : * overviews, but the RasterIO() method can be used in downsampling mode
3301 : * to get overview data efficiently.
3302 : *
3303 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3304 : *
3305 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3306 : * FALSE.
3307 : */
3308 :
3309 279 : int GDALRasterBand::HasArbitraryOverviews()
3310 :
3311 : {
3312 279 : return FALSE;
3313 : }
3314 :
3315 : /************************************************************************/
3316 : /* GDALHasArbitraryOverviews() */
3317 : /************************************************************************/
3318 :
3319 : /**
3320 : * \brief Check for arbitrary overviews.
3321 : *
3322 : * @see GDALRasterBand::HasArbitraryOverviews()
3323 : */
3324 :
3325 200 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3326 :
3327 : {
3328 200 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3329 :
3330 200 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3331 200 : return poBand->HasArbitraryOverviews();
3332 : }
3333 :
3334 : /************************************************************************/
3335 : /* GetOverviewCount() */
3336 : /************************************************************************/
3337 :
3338 : /**
3339 : * \brief Return the number of overview layers available.
3340 : *
3341 : * This method is the same as the C function GDALGetOverviewCount().
3342 : *
3343 : * @return overview count, zero if none.
3344 : */
3345 :
3346 1077360 : int GDALRasterBand::GetOverviewCount()
3347 :
3348 : {
3349 1734440 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3350 657087 : poDS->AreOverviewsEnabled())
3351 657087 : return poDS->oOvManager.GetOverviewCount(nBand);
3352 :
3353 420268 : return 0;
3354 : }
3355 :
3356 : /************************************************************************/
3357 : /* GDALGetOverviewCount() */
3358 : /************************************************************************/
3359 :
3360 : /**
3361 : * \brief Return the number of overview layers available.
3362 : *
3363 : * @see GDALRasterBand::GetOverviewCount()
3364 : */
3365 :
3366 3329 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3367 :
3368 : {
3369 3329 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3370 :
3371 3329 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3372 3329 : return poBand->GetOverviewCount();
3373 : }
3374 :
3375 : /************************************************************************/
3376 : /* GetOverview() */
3377 : /************************************************************************/
3378 :
3379 : /**
3380 : * \brief Fetch overview raster band object.
3381 : *
3382 : * This method is the same as the C function GDALGetOverview().
3383 : *
3384 : * @param i overview index between 0 and GetOverviewCount()-1.
3385 : *
3386 : * @return overview GDALRasterBand.
3387 : */
3388 :
3389 944 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3390 :
3391 : {
3392 1735 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3393 791 : poDS->AreOverviewsEnabled())
3394 791 : return poDS->oOvManager.GetOverview(nBand, i);
3395 :
3396 153 : return nullptr;
3397 : }
3398 :
3399 : /************************************************************************/
3400 : /* GDALGetOverview() */
3401 : /************************************************************************/
3402 :
3403 : /**
3404 : * \brief Fetch overview raster band object.
3405 : *
3406 : * @see GDALRasterBand::GetOverview()
3407 : */
3408 :
3409 5672 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3410 :
3411 : {
3412 5672 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3413 :
3414 5672 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3415 5672 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3416 : }
3417 :
3418 : /************************************************************************/
3419 : /* GetRasterSampleOverview() */
3420 : /************************************************************************/
3421 :
3422 : /**
3423 : * \brief Fetch best sampling overview.
3424 : *
3425 : * Returns the most reduced overview of the given band that still satisfies
3426 : * the desired number of samples. This function can be used with zero
3427 : * as the number of desired samples to fetch the most reduced overview.
3428 : * The same band as was passed in will be returned if it has not overviews,
3429 : * or if none of the overviews have enough samples.
3430 : *
3431 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3432 : * and GDALGetRasterSampleOverviewEx().
3433 : *
3434 : * @param nDesiredSamples the returned band will have at least this many
3435 : * pixels.
3436 : *
3437 : * @return optimal overview or the band itself.
3438 : */
3439 :
3440 : GDALRasterBand *
3441 2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3442 :
3443 : {
3444 2009 : GDALRasterBand *poBestBand = this;
3445 :
3446 2009 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3447 :
3448 4029 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3449 : {
3450 2020 : GDALRasterBand *poOBand = GetOverview(iOverview);
3451 :
3452 2020 : if (poOBand == nullptr)
3453 0 : continue;
3454 :
3455 : const double dfOSamples =
3456 2020 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3457 :
3458 2020 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3459 : {
3460 2017 : dfBestSamples = dfOSamples;
3461 2017 : poBestBand = poOBand;
3462 : }
3463 : }
3464 :
3465 2009 : return poBestBand;
3466 : }
3467 :
3468 : /************************************************************************/
3469 : /* GDALGetRasterSampleOverview() */
3470 : /************************************************************************/
3471 :
3472 : /**
3473 : * \brief Fetch best sampling overview.
3474 : *
3475 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3476 : * billion samples.
3477 : *
3478 : * @see GDALRasterBand::GetRasterSampleOverview()
3479 : * @see GDALGetRasterSampleOverviewEx()
3480 : */
3481 :
3482 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3483 : int nDesiredSamples)
3484 :
3485 : {
3486 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3487 :
3488 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3489 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3490 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3491 : }
3492 :
3493 : /************************************************************************/
3494 : /* GDALGetRasterSampleOverviewEx() */
3495 : /************************************************************************/
3496 :
3497 : /**
3498 : * \brief Fetch best sampling overview.
3499 : *
3500 : * @see GDALRasterBand::GetRasterSampleOverview()
3501 : */
3502 :
3503 : GDALRasterBandH CPL_STDCALL
3504 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3505 :
3506 : {
3507 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3508 :
3509 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3510 2000 : return GDALRasterBand::ToHandle(
3511 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3512 : }
3513 :
3514 : /************************************************************************/
3515 : /* BuildOverviews() */
3516 : /************************************************************************/
3517 :
3518 : /**
3519 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3520 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3521 : *
3522 : * If the operation is unsupported for the indicated dataset, then
3523 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3524 : * CPLE_NotSupported.
3525 : *
3526 : * WARNING: Most formats don't support per-band overview computation, but
3527 : * require that overviews are computed for all bands of a dataset, using
3528 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3529 : * is the HFA driver which supports this method.
3530 : *
3531 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3532 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3533 : * applied.
3534 : * @param nOverviews number of overviews to build.
3535 : * @param panOverviewList the list of overview decimation factors to build.
3536 : * @param pfnProgress a function to call to report progress, or NULL.
3537 : * @param pProgressData application data to pass to the progress function.
3538 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3539 : * key=value pairs, or NULL
3540 : *
3541 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3542 : */
3543 :
3544 : /**/
3545 : /**/
3546 :
3547 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3548 : int /*nOverviews*/,
3549 : const int * /*panOverviewList*/,
3550 : GDALProgressFunc /*pfnProgress*/,
3551 : void * /*pProgressData*/,
3552 : CSLConstList /* papszOptions */)
3553 :
3554 : {
3555 0 : ReportError(CE_Failure, CPLE_NotSupported,
3556 : "BuildOverviews() not supported for this dataset.");
3557 :
3558 0 : return (CE_Failure);
3559 : }
3560 :
3561 : /************************************************************************/
3562 : /* GetOffset() */
3563 : /************************************************************************/
3564 :
3565 : /**
3566 : * \brief Fetch the raster value offset.
3567 : *
3568 : * This value (in combination with the GetScale() value) can be used to
3569 : * transform raw pixel values into the units returned by GetUnitType().
3570 : * For example this might be used to store elevations in GUInt16 bands
3571 : * with a precision of 0.1, and starting from -100.
3572 : *
3573 : * Units value = (raw value * scale) + offset
3574 : *
3575 : * Note that applying scale and offset is of the responsibility of the user,
3576 : * and is not done by methods such as RasterIO() or ReadBlock().
3577 : *
3578 : * For file formats that don't know this intrinsically a value of zero
3579 : * is returned.
3580 : *
3581 : * This method is the same as the C function GDALGetRasterOffset().
3582 : *
3583 : * @param pbSuccess pointer to a boolean to use to indicate if the
3584 : * returned value is meaningful or not. May be NULL (default).
3585 : *
3586 : * @return the raster offset.
3587 : */
3588 :
3589 510 : double GDALRasterBand::GetOffset(int *pbSuccess)
3590 :
3591 : {
3592 510 : if (pbSuccess != nullptr)
3593 333 : *pbSuccess = FALSE;
3594 :
3595 510 : return 0.0;
3596 : }
3597 :
3598 : /************************************************************************/
3599 : /* GDALGetRasterOffset() */
3600 : /************************************************************************/
3601 :
3602 : /**
3603 : * \brief Fetch the raster value offset.
3604 : *
3605 : * @see GDALRasterBand::GetOffset()
3606 : */
3607 :
3608 423 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3609 :
3610 : {
3611 423 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3612 :
3613 423 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3614 423 : return poBand->GetOffset(pbSuccess);
3615 : }
3616 :
3617 : /************************************************************************/
3618 : /* SetOffset() */
3619 : /************************************************************************/
3620 :
3621 : /**
3622 : * \fn GDALRasterBand::SetOffset(double)
3623 : * \brief Set scaling offset.
3624 : *
3625 : * Very few formats implement this method. When not implemented it will
3626 : * issue a CPLE_NotSupported error and return CE_Failure.
3627 : *
3628 : * This method is the same as the C function GDALSetRasterOffset().
3629 : *
3630 : * @param dfNewOffset the new offset.
3631 : *
3632 : * @return CE_None or success or CE_Failure on failure.
3633 : */
3634 :
3635 : /**/
3636 : /**/
3637 :
3638 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3639 : {
3640 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3641 0 : ReportError(CE_Failure, CPLE_NotSupported,
3642 : "SetOffset() not supported on this raster band.");
3643 :
3644 0 : return CE_Failure;
3645 : }
3646 :
3647 : /************************************************************************/
3648 : /* GDALSetRasterOffset() */
3649 : /************************************************************************/
3650 :
3651 : /**
3652 : * \brief Set scaling offset.
3653 : *
3654 : * @see GDALRasterBand::SetOffset()
3655 : */
3656 :
3657 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3658 : double dfNewOffset)
3659 :
3660 : {
3661 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3662 :
3663 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3664 86 : return poBand->SetOffset(dfNewOffset);
3665 : }
3666 :
3667 : /************************************************************************/
3668 : /* GetScale() */
3669 : /************************************************************************/
3670 :
3671 : /**
3672 : * \brief Fetch the raster value scale.
3673 : *
3674 : * This value (in combination with the GetOffset() value) can be used to
3675 : * transform raw pixel values into the units returned by GetUnitType().
3676 : * For example this might be used to store elevations in GUInt16 bands
3677 : * with a precision of 0.1, and starting from -100.
3678 : *
3679 : * Units value = (raw value * scale) + offset
3680 : *
3681 : * Note that applying scale and offset is of the responsibility of the user,
3682 : * and is not done by methods such as RasterIO() or ReadBlock().
3683 : *
3684 : * For file formats that don't know this intrinsically a value of one
3685 : * is returned.
3686 : *
3687 : * This method is the same as the C function GDALGetRasterScale().
3688 : *
3689 : * @param pbSuccess pointer to a boolean to use to indicate if the
3690 : * returned value is meaningful or not. May be NULL (default).
3691 : *
3692 : * @return the raster scale.
3693 : */
3694 :
3695 510 : double GDALRasterBand::GetScale(int *pbSuccess)
3696 :
3697 : {
3698 510 : if (pbSuccess != nullptr)
3699 333 : *pbSuccess = FALSE;
3700 :
3701 510 : return 1.0;
3702 : }
3703 :
3704 : /************************************************************************/
3705 : /* GDALGetRasterScale() */
3706 : /************************************************************************/
3707 :
3708 : /**
3709 : * \brief Fetch the raster value scale.
3710 : *
3711 : * @see GDALRasterBand::GetScale()
3712 : */
3713 :
3714 421 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3715 :
3716 : {
3717 421 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3718 :
3719 421 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3720 421 : return poBand->GetScale(pbSuccess);
3721 : }
3722 :
3723 : /************************************************************************/
3724 : /* SetScale() */
3725 : /************************************************************************/
3726 :
3727 : /**
3728 : * \fn GDALRasterBand::SetScale(double)
3729 : * \brief Set scaling ratio.
3730 : *
3731 : * Very few formats implement this method. When not implemented it will
3732 : * issue a CPLE_NotSupported error and return CE_Failure.
3733 : *
3734 : * This method is the same as the C function GDALSetRasterScale().
3735 : *
3736 : * @param dfNewScale the new scale.
3737 : *
3738 : * @return CE_None or success or CE_Failure on failure.
3739 : */
3740 :
3741 : /**/
3742 : /**/
3743 :
3744 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3745 :
3746 : {
3747 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3748 0 : ReportError(CE_Failure, CPLE_NotSupported,
3749 : "SetScale() not supported on this raster band.");
3750 :
3751 0 : return CE_Failure;
3752 : }
3753 :
3754 : /************************************************************************/
3755 : /* GDALSetRasterScale() */
3756 : /************************************************************************/
3757 :
3758 : /**
3759 : * \brief Set scaling ratio.
3760 : *
3761 : * @see GDALRasterBand::SetScale()
3762 : */
3763 :
3764 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3765 :
3766 : {
3767 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3768 :
3769 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3770 87 : return poBand->SetScale(dfNewOffset);
3771 : }
3772 :
3773 : /************************************************************************/
3774 : /* GetUnitType() */
3775 : /************************************************************************/
3776 :
3777 : /**
3778 : * \brief Return raster unit type.
3779 : *
3780 : * Return a name for the units of this raster's values. For instance, it
3781 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3782 : * units are available, a value of "" will be returned. The returned string
3783 : * should not be modified, nor freed by the calling application.
3784 : *
3785 : * This method is the same as the C function GDALGetRasterUnitType().
3786 : *
3787 : * @return unit name string.
3788 : */
3789 :
3790 181 : const char *GDALRasterBand::GetUnitType()
3791 :
3792 : {
3793 181 : return "";
3794 : }
3795 :
3796 : /************************************************************************/
3797 : /* GDALGetRasterUnitType() */
3798 : /************************************************************************/
3799 :
3800 : /**
3801 : * \brief Return raster unit type.
3802 : *
3803 : * @see GDALRasterBand::GetUnitType()
3804 : */
3805 :
3806 1748 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3807 :
3808 : {
3809 1748 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3810 :
3811 1748 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3812 1748 : return poBand->GetUnitType();
3813 : }
3814 :
3815 : /************************************************************************/
3816 : /* SetUnitType() */
3817 : /************************************************************************/
3818 :
3819 : /**
3820 : * \fn GDALRasterBand::SetUnitType(const char*)
3821 : * \brief Set unit type.
3822 : *
3823 : * Set the unit type for a raster band. Values should be one of
3824 : * "" (the default indicating it is unknown), "m" indicating meters,
3825 : * or "ft" indicating feet, though other nonstandard values are allowed.
3826 : *
3827 : * This method is the same as the C function GDALSetRasterUnitType().
3828 : *
3829 : * @param pszNewValue the new unit type value.
3830 : *
3831 : * @return CE_None on success or CE_Failure if not successful, or
3832 : * unsupported.
3833 : */
3834 :
3835 : /**/
3836 : /**/
3837 :
3838 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3839 :
3840 : {
3841 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3842 0 : ReportError(CE_Failure, CPLE_NotSupported,
3843 : "SetUnitType() not supported on this raster band.");
3844 0 : return CE_Failure;
3845 : }
3846 :
3847 : /************************************************************************/
3848 : /* GDALSetRasterUnitType() */
3849 : /************************************************************************/
3850 :
3851 : /**
3852 : * \brief Set unit type.
3853 : *
3854 : * @see GDALRasterBand::SetUnitType()
3855 : *
3856 : */
3857 :
3858 124 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3859 : const char *pszNewValue)
3860 :
3861 : {
3862 124 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3863 :
3864 124 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3865 124 : return poBand->SetUnitType(pszNewValue);
3866 : }
3867 :
3868 : /************************************************************************/
3869 : /* GetXSize() */
3870 : /************************************************************************/
3871 :
3872 : /**
3873 : * \brief Fetch XSize of raster.
3874 : *
3875 : * This method is the same as the C function GDALGetRasterBandXSize().
3876 : *
3877 : * @return the width in pixels of this band.
3878 : */
3879 :
3880 8577500 : int GDALRasterBand::GetXSize() const
3881 :
3882 : {
3883 8577500 : return nRasterXSize;
3884 : }
3885 :
3886 : /************************************************************************/
3887 : /* GDALGetRasterBandXSize() */
3888 : /************************************************************************/
3889 :
3890 : /**
3891 : * \brief Fetch XSize of raster.
3892 : *
3893 : * @see GDALRasterBand::GetXSize()
3894 : */
3895 :
3896 58338 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3897 :
3898 : {
3899 58338 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3900 :
3901 58338 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3902 58338 : return poBand->GetXSize();
3903 : }
3904 :
3905 : /************************************************************************/
3906 : /* GetYSize() */
3907 : /************************************************************************/
3908 :
3909 : /**
3910 : * \brief Fetch YSize of raster.
3911 : *
3912 : * This method is the same as the C function GDALGetRasterBandYSize().
3913 : *
3914 : * @return the height in pixels of this band.
3915 : */
3916 :
3917 4767290 : int GDALRasterBand::GetYSize() const
3918 :
3919 : {
3920 4767290 : return nRasterYSize;
3921 : }
3922 :
3923 : /************************************************************************/
3924 : /* GDALGetRasterBandYSize() */
3925 : /************************************************************************/
3926 :
3927 : /**
3928 : * \brief Fetch YSize of raster.
3929 : *
3930 : * @see GDALRasterBand::GetYSize()
3931 : */
3932 :
3933 57201 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3934 :
3935 : {
3936 57201 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3937 :
3938 57201 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3939 57201 : return poBand->GetYSize();
3940 : }
3941 :
3942 : /************************************************************************/
3943 : /* GetBand() */
3944 : /************************************************************************/
3945 :
3946 : /**
3947 : * \brief Fetch the band number.
3948 : *
3949 : * This method returns the band that this GDALRasterBand objects represents
3950 : * within its dataset. This method may return a value of 0 to indicate
3951 : * GDALRasterBand objects without an apparently relationship to a dataset,
3952 : * such as GDALRasterBands serving as overviews.
3953 : *
3954 : * This method is the same as the C function GDALGetBandNumber().
3955 : *
3956 : * @return band number (1+) or 0 if the band number isn't known.
3957 : */
3958 :
3959 151661 : int GDALRasterBand::GetBand() const
3960 :
3961 : {
3962 151661 : return nBand;
3963 : }
3964 :
3965 : /************************************************************************/
3966 : /* GDALGetBandNumber() */
3967 : /************************************************************************/
3968 :
3969 : /**
3970 : * \brief Fetch the band number.
3971 : *
3972 : * @see GDALRasterBand::GetBand()
3973 : */
3974 :
3975 159 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3976 :
3977 : {
3978 159 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3979 :
3980 159 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3981 159 : return poBand->GetBand();
3982 : }
3983 :
3984 : /************************************************************************/
3985 : /* GetDataset() */
3986 : /************************************************************************/
3987 :
3988 : /**
3989 : * \brief Fetch the owning dataset handle.
3990 : *
3991 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3992 : * such as overviews or other "freestanding" bands.
3993 : *
3994 : * This method is the same as the C function GDALGetBandDataset().
3995 : *
3996 : * @return the pointer to the GDALDataset to which this band belongs, or
3997 : * NULL if this cannot be determined.
3998 : */
3999 :
4000 4991710 : GDALDataset *GDALRasterBand::GetDataset() const
4001 :
4002 : {
4003 4991710 : return poDS;
4004 : }
4005 :
4006 : /************************************************************************/
4007 : /* GDALGetBandDataset() */
4008 : /************************************************************************/
4009 :
4010 : /**
4011 : * \brief Fetch the owning dataset handle.
4012 : *
4013 : * @see GDALRasterBand::GetDataset()
4014 : */
4015 :
4016 360 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4017 :
4018 : {
4019 360 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4020 :
4021 360 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4022 360 : return GDALDataset::ToHandle(poBand->GetDataset());
4023 : }
4024 :
4025 : /************************************************************************/
4026 : /* ComputeFloat16NoDataValue() */
4027 : /************************************************************************/
4028 :
4029 3284 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4030 : double dfNoDataValue,
4031 : int &bGotNoDataValue,
4032 : GFloat16 &hfNoDataValue,
4033 : bool &bGotFloat16NoDataValue)
4034 : {
4035 3284 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4036 : {
4037 7 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4038 7 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4039 : {
4040 7 : hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4041 7 : bGotFloat16NoDataValue = true;
4042 7 : bGotNoDataValue = false;
4043 : }
4044 : }
4045 3284 : }
4046 :
4047 : /************************************************************************/
4048 : /* ComputeFloatNoDataValue() */
4049 : /************************************************************************/
4050 :
4051 3284 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4052 : double dfNoDataValue,
4053 : int &bGotNoDataValue,
4054 : float &fNoDataValue,
4055 : bool &bGotFloatNoDataValue)
4056 : {
4057 3284 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4058 : {
4059 117 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4060 117 : if (GDALIsValueInRange<float>(dfNoDataValue))
4061 : {
4062 117 : fNoDataValue = static_cast<float>(dfNoDataValue);
4063 117 : bGotFloatNoDataValue = true;
4064 117 : bGotNoDataValue = false;
4065 : }
4066 : }
4067 3280 : else if (eDataType == GDT_Int16 && bGotNoDataValue &&
4068 113 : GDALIsValueExactAs<int16_t>(dfNoDataValue))
4069 : {
4070 113 : fNoDataValue = static_cast<float>(dfNoDataValue);
4071 113 : bGotFloatNoDataValue = true;
4072 : }
4073 3087 : else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
4074 33 : GDALIsValueExactAs<uint16_t>(dfNoDataValue))
4075 : {
4076 33 : fNoDataValue = static_cast<float>(dfNoDataValue);
4077 33 : bGotFloatNoDataValue = true;
4078 : }
4079 3028 : else if (eDataType == GDT_Float16 && bGotNoDataValue &&
4080 7 : GDALIsValueExactAs<GFloat16>(dfNoDataValue))
4081 : {
4082 7 : fNoDataValue = static_cast<float>(dfNoDataValue);
4083 7 : bGotFloatNoDataValue = true;
4084 : }
4085 3284 : }
4086 :
4087 : /************************************************************************/
4088 : /* struct GDALNoDataValues */
4089 : /************************************************************************/
4090 :
4091 : /**
4092 : * \brief No-data-values for all types
4093 : *
4094 : * The functions below pass various no-data-values around. To avoid
4095 : * long argument lists, this struct collects the no-data-values for
4096 : * all types into a single, convenient place.
4097 : **/
4098 :
4099 : struct GDALNoDataValues
4100 : {
4101 : int bGotNoDataValue;
4102 : double dfNoDataValue;
4103 :
4104 : bool bGotInt64NoDataValue;
4105 : int64_t nInt64NoDataValue;
4106 :
4107 : bool bGotUInt64NoDataValue;
4108 : uint64_t nUInt64NoDataValue;
4109 :
4110 : bool bGotFloatNoDataValue;
4111 : float fNoDataValue;
4112 :
4113 : bool bGotFloat16NoDataValue;
4114 : GFloat16 hfNoDataValue;
4115 :
4116 3384 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4117 3384 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4118 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4119 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4120 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4121 3384 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4122 : {
4123 3384 : if (eDataType == GDT_Int64)
4124 : {
4125 62 : int nGot = false;
4126 62 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4127 62 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4128 62 : if (bGotInt64NoDataValue)
4129 : {
4130 10 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4131 10 : bGotNoDataValue =
4132 10 : nInt64NoDataValue <=
4133 20 : std::numeric_limits<int64_t>::max() - 1024 &&
4134 10 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4135 : }
4136 : else
4137 52 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4138 : }
4139 3322 : else if (eDataType == GDT_UInt64)
4140 : {
4141 38 : int nGot = false;
4142 38 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4143 38 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4144 38 : if (bGotUInt64NoDataValue)
4145 : {
4146 10 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4147 10 : bGotNoDataValue =
4148 10 : nUInt64NoDataValue <=
4149 20 : std::numeric_limits<uint64_t>::max() - 2048 &&
4150 10 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4151 : }
4152 : else
4153 28 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4154 : }
4155 : else
4156 : {
4157 3284 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4158 3284 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4159 :
4160 3284 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4161 3284 : fNoDataValue, bGotFloatNoDataValue);
4162 :
4163 3284 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4164 3284 : hfNoDataValue, bGotFloat16NoDataValue);
4165 : }
4166 3384 : }
4167 : };
4168 :
4169 : /************************************************************************/
4170 : /* ARE_REAL_EQUAL() */
4171 : /************************************************************************/
4172 :
4173 28 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4174 : {
4175 : using std::abs;
4176 56 : return dfVal1 == dfVal2 || /* Should cover infinity */
4177 28 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4178 28 : abs(dfVal1 + dfVal2) * ulp;
4179 : }
4180 :
4181 : /************************************************************************/
4182 : /* GetHistogram() */
4183 : /************************************************************************/
4184 :
4185 : /**
4186 : * \brief Compute raster histogram.
4187 : *
4188 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4189 : *
4190 : * For example to compute a simple 256 entry histogram of eight bit data,
4191 : * the following would be suitable. The unusual bounds are to ensure that
4192 : * bucket boundaries don't fall right on integer values causing possible errors
4193 : * due to rounding after scaling.
4194 : \code{.cpp}
4195 : GUIntBig anHistogram[256];
4196 :
4197 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4198 : GDALDummyProgress, nullptr );
4199 : \endcode
4200 : *
4201 : * Note that setting bApproxOK will generally result in a subsampling of the
4202 : * file, and will utilize overviews if available. It should generally
4203 : * produce a representative histogram for the data that is suitable for use
4204 : * in generating histogram based luts for instance. Generally bApproxOK is
4205 : * much faster than an exactly computed histogram.
4206 : *
4207 : * This method is the same as the C functions GDALGetRasterHistogram() and
4208 : * GDALGetRasterHistogramEx().
4209 : *
4210 : * @param dfMin the lower bound of the histogram.
4211 : * @param dfMax the upper bound of the histogram.
4212 : * @param nBuckets the number of buckets in panHistogram.
4213 : * @param panHistogram array into which the histogram totals are placed.
4214 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4215 : * mapped into panHistogram[0], and values above will be mapped into
4216 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4217 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4218 : * @param pfnProgress function to report progress to completion.
4219 : * @param pProgressData application data to pass to pfnProgress.
4220 : *
4221 : * @return CE_None on success, or CE_Failure if something goes wrong.
4222 : */
4223 :
4224 45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4225 : GUIntBig *panHistogram,
4226 : int bIncludeOutOfRange, int bApproxOK,
4227 : GDALProgressFunc pfnProgress,
4228 : void *pProgressData)
4229 :
4230 : {
4231 45 : CPLAssert(nullptr != panHistogram);
4232 :
4233 45 : if (pfnProgress == nullptr)
4234 29 : pfnProgress = GDALDummyProgress;
4235 :
4236 : /* -------------------------------------------------------------------- */
4237 : /* If we have overviews, use them for the histogram. */
4238 : /* -------------------------------------------------------------------- */
4239 45 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4240 : {
4241 : // FIXME: should we use the most reduced overview here or use some
4242 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4243 : // does?
4244 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4245 :
4246 0 : if (poBestOverview != this)
4247 : {
4248 0 : return poBestOverview->GetHistogram(
4249 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4250 0 : bApproxOK, pfnProgress, pProgressData);
4251 : }
4252 : }
4253 :
4254 : /* -------------------------------------------------------------------- */
4255 : /* Read actual data and build histogram. */
4256 : /* -------------------------------------------------------------------- */
4257 45 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4258 : {
4259 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4260 0 : return CE_Failure;
4261 : }
4262 :
4263 : // Written this way to deal with NaN
4264 45 : if (!(dfMax > dfMin))
4265 : {
4266 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4267 : "dfMax should be strictly greater than dfMin");
4268 5 : return CE_Failure;
4269 : }
4270 :
4271 : GDALRasterIOExtraArg sExtraArg;
4272 40 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4273 :
4274 40 : const double dfScale = nBuckets / (dfMax - dfMin);
4275 40 : if (dfScale == 0 || !std::isfinite(dfScale))
4276 : {
4277 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4278 : "dfMin and dfMax should be finite values such that "
4279 : "nBuckets / (dfMax - dfMin) is non-zero");
4280 5 : return CE_Failure;
4281 : }
4282 35 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4283 :
4284 35 : GDALNoDataValues sNoDataValues(this, eDataType);
4285 35 : GDALRasterBand *poMaskBand = nullptr;
4286 35 : if (!sNoDataValues.bGotNoDataValue)
4287 : {
4288 34 : const int l_nMaskFlags = GetMaskFlags();
4289 36 : if (l_nMaskFlags != GMF_ALL_VALID &&
4290 2 : GetColorInterpretation() != GCI_AlphaBand)
4291 : {
4292 2 : poMaskBand = GetMaskBand();
4293 : }
4294 : }
4295 :
4296 35 : bool bSignedByte = false;
4297 35 : if (eDataType == GDT_UInt8)
4298 : {
4299 26 : EnablePixelTypeSignedByteWarning(false);
4300 : const char *pszPixelType =
4301 26 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4302 26 : EnablePixelTypeSignedByteWarning(true);
4303 26 : bSignedByte =
4304 26 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4305 : }
4306 :
4307 35 : if (bApproxOK && HasArbitraryOverviews())
4308 : {
4309 : /* --------------------------------------------------------------------
4310 : */
4311 : /* Figure out how much the image should be reduced to get an */
4312 : /* approximate value. */
4313 : /* --------------------------------------------------------------------
4314 : */
4315 : const double dfReduction =
4316 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4317 : GDALSTAT_APPROX_NUMSAMPLES);
4318 :
4319 0 : int nXReduced = nRasterXSize;
4320 0 : int nYReduced = nRasterYSize;
4321 0 : if (dfReduction > 1.0)
4322 : {
4323 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4324 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4325 :
4326 : // Catch the case of huge resizing ratios here
4327 0 : if (nXReduced == 0)
4328 0 : nXReduced = 1;
4329 0 : if (nYReduced == 0)
4330 0 : nYReduced = 1;
4331 : }
4332 :
4333 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4334 : nXReduced, nYReduced);
4335 0 : if (!pData)
4336 0 : return CE_Failure;
4337 :
4338 : const CPLErr eErr =
4339 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4340 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4341 0 : if (eErr != CE_None)
4342 : {
4343 0 : CPLFree(pData);
4344 0 : return eErr;
4345 : }
4346 :
4347 0 : GByte *pabyMaskData = nullptr;
4348 0 : if (poMaskBand)
4349 : {
4350 : pabyMaskData =
4351 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4352 0 : if (!pabyMaskData)
4353 : {
4354 0 : CPLFree(pData);
4355 0 : return CE_Failure;
4356 : }
4357 :
4358 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4359 : pabyMaskData, nXReduced, nYReduced,
4360 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
4361 : {
4362 0 : CPLFree(pData);
4363 0 : CPLFree(pabyMaskData);
4364 0 : return CE_Failure;
4365 : }
4366 : }
4367 :
4368 : // This isn't the fastest way to do this, but is easier for now.
4369 0 : for (int iY = 0; iY < nYReduced; iY++)
4370 : {
4371 0 : for (int iX = 0; iX < nXReduced; iX++)
4372 : {
4373 0 : const int iOffset = iX + iY * nXReduced;
4374 0 : double dfValue = 0.0;
4375 :
4376 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4377 0 : continue;
4378 :
4379 0 : switch (eDataType)
4380 : {
4381 0 : case GDT_UInt8:
4382 : {
4383 0 : if (bSignedByte)
4384 0 : dfValue =
4385 0 : static_cast<signed char *>(pData)[iOffset];
4386 : else
4387 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4388 0 : break;
4389 : }
4390 0 : case GDT_Int8:
4391 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4392 0 : break;
4393 0 : case GDT_UInt16:
4394 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4395 0 : break;
4396 0 : case GDT_Int16:
4397 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4398 0 : break;
4399 0 : case GDT_UInt32:
4400 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4401 0 : break;
4402 0 : case GDT_Int32:
4403 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4404 0 : break;
4405 0 : case GDT_UInt64:
4406 0 : dfValue = static_cast<double>(
4407 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4408 0 : break;
4409 0 : case GDT_Int64:
4410 0 : dfValue = static_cast<double>(
4411 0 : static_cast<GInt64 *>(pData)[iOffset]);
4412 0 : break;
4413 0 : case GDT_Float16:
4414 : {
4415 : using namespace std;
4416 0 : const GFloat16 hfValue =
4417 0 : static_cast<GFloat16 *>(pData)[iOffset];
4418 0 : if (isnan(hfValue) ||
4419 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4420 0 : ARE_REAL_EQUAL(hfValue,
4421 : sNoDataValues.hfNoDataValue)))
4422 0 : continue;
4423 0 : dfValue = hfValue;
4424 0 : break;
4425 : }
4426 0 : case GDT_Float32:
4427 : {
4428 0 : const float fValue =
4429 0 : static_cast<float *>(pData)[iOffset];
4430 0 : if (std::isnan(fValue) ||
4431 0 : (sNoDataValues.bGotFloatNoDataValue &&
4432 0 : ARE_REAL_EQUAL(fValue,
4433 : sNoDataValues.fNoDataValue)))
4434 0 : continue;
4435 0 : dfValue = double(fValue);
4436 0 : break;
4437 : }
4438 0 : case GDT_Float64:
4439 0 : dfValue = static_cast<double *>(pData)[iOffset];
4440 0 : if (std::isnan(dfValue))
4441 0 : continue;
4442 0 : break;
4443 0 : case GDT_CInt16:
4444 : {
4445 0 : const double dfReal =
4446 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4447 0 : const double dfImag =
4448 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4449 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4450 0 : continue;
4451 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4452 : }
4453 0 : break;
4454 0 : case GDT_CInt32:
4455 : {
4456 0 : const double dfReal =
4457 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4458 0 : const double dfImag =
4459 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4460 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4461 0 : continue;
4462 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4463 : }
4464 0 : break;
4465 0 : case GDT_CFloat16:
4466 : {
4467 : const double dfReal =
4468 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4469 : const double dfImag =
4470 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4471 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4472 0 : continue;
4473 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4474 0 : break;
4475 : }
4476 0 : case GDT_CFloat32:
4477 : {
4478 0 : const double dfReal =
4479 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4480 0 : const double dfImag = double(
4481 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4482 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4483 0 : continue;
4484 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4485 0 : break;
4486 : }
4487 0 : case GDT_CFloat64:
4488 : {
4489 0 : const double dfReal =
4490 0 : static_cast<double *>(pData)[iOffset * 2];
4491 0 : const double dfImag =
4492 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4493 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4494 0 : continue;
4495 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4496 0 : break;
4497 : }
4498 0 : case GDT_Unknown:
4499 : case GDT_TypeCount:
4500 0 : CPLAssert(false);
4501 : }
4502 :
4503 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4504 0 : sNoDataValues.bGotNoDataValue &&
4505 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4506 0 : continue;
4507 :
4508 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4509 : // finite, the result of the multiplication cannot be NaN
4510 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4511 :
4512 0 : if (dfIndex < 0)
4513 : {
4514 0 : if (bIncludeOutOfRange)
4515 0 : panHistogram[0]++;
4516 : }
4517 0 : else if (dfIndex >= nBuckets)
4518 : {
4519 0 : if (bIncludeOutOfRange)
4520 0 : ++panHistogram[nBuckets - 1];
4521 : }
4522 : else
4523 : {
4524 0 : ++panHistogram[static_cast<int>(dfIndex)];
4525 : }
4526 : }
4527 : }
4528 :
4529 0 : CPLFree(pData);
4530 0 : CPLFree(pabyMaskData);
4531 : }
4532 : else // No arbitrary overviews.
4533 : {
4534 35 : if (!InitBlockInfo())
4535 0 : return CE_Failure;
4536 :
4537 : /* --------------------------------------------------------------------
4538 : */
4539 : /* Figure out the ratio of blocks we will read to get an */
4540 : /* approximate value. */
4541 : /* --------------------------------------------------------------------
4542 : */
4543 :
4544 35 : int nSampleRate = 1;
4545 35 : if (bApproxOK)
4546 : {
4547 8 : nSampleRate = static_cast<int>(std::max(
4548 16 : 1.0,
4549 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4550 : // We want to avoid probing only the first column of blocks for
4551 : // a square shaped raster, because it is not unlikely that it may
4552 : // be padding only (#6378).
4553 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4554 1 : nSampleRate += 1;
4555 : }
4556 :
4557 35 : GByte *pabyMaskData = nullptr;
4558 35 : if (poMaskBand)
4559 : {
4560 : pabyMaskData = static_cast<GByte *>(
4561 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4562 2 : if (!pabyMaskData)
4563 : {
4564 0 : return CE_Failure;
4565 : }
4566 : }
4567 :
4568 : /* --------------------------------------------------------------------
4569 : */
4570 : /* Read the blocks, and add to histogram. */
4571 : /* --------------------------------------------------------------------
4572 : */
4573 35 : for (GIntBig iSampleBlock = 0;
4574 160 : iSampleBlock <
4575 160 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4576 125 : iSampleBlock += nSampleRate)
4577 : {
4578 125 : if (!pfnProgress(
4579 125 : static_cast<double>(iSampleBlock) /
4580 125 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4581 : "Compute Histogram", pProgressData))
4582 : {
4583 0 : CPLFree(pabyMaskData);
4584 0 : return CE_Failure;
4585 : }
4586 :
4587 125 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4588 125 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4589 :
4590 125 : int nXCheck = 0, nYCheck = 0;
4591 125 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4592 :
4593 127 : if (poMaskBand &&
4594 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4595 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4596 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4597 2 : 0, nBlockXSize, nullptr) != CE_None)
4598 : {
4599 0 : CPLFree(pabyMaskData);
4600 0 : return CE_Failure;
4601 : }
4602 :
4603 125 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4604 125 : if (poBlock == nullptr)
4605 : {
4606 0 : CPLFree(pabyMaskData);
4607 0 : return CE_Failure;
4608 : }
4609 :
4610 125 : void *pData = poBlock->GetDataRef();
4611 :
4612 : // this is a special case for a common situation.
4613 125 : if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4614 89 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4615 86 : nXCheck == nBlockXSize && nBuckets == 256)
4616 : {
4617 86 : const GPtrDiff_t nPixels =
4618 86 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4619 86 : GByte *pabyData = static_cast<GByte *>(pData);
4620 :
4621 79640 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4622 : {
4623 79554 : if (pabyMaskData && pabyMaskData[i] == 0)
4624 0 : continue;
4625 79554 : if (!(sNoDataValues.bGotNoDataValue &&
4626 512 : (pabyData[i] ==
4627 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4628 : {
4629 79298 : panHistogram[pabyData[i]]++;
4630 : }
4631 : }
4632 :
4633 86 : poBlock->DropLock();
4634 86 : continue; // To next sample block.
4635 : }
4636 :
4637 : // This isn't the fastest way to do this, but is easier for now.
4638 257 : for (int iY = 0; iY < nYCheck; iY++)
4639 : {
4640 36389 : for (int iX = 0; iX < nXCheck; iX++)
4641 : {
4642 36171 : const GPtrDiff_t iOffset =
4643 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4644 :
4645 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4646 2 : continue;
4647 :
4648 36169 : double dfValue = 0.0;
4649 :
4650 36169 : switch (eDataType)
4651 : {
4652 19716 : case GDT_UInt8:
4653 : {
4654 19716 : if (bSignedByte)
4655 0 : dfValue =
4656 0 : static_cast<signed char *>(pData)[iOffset];
4657 : else
4658 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4659 19716 : break;
4660 : }
4661 1 : case GDT_Int8:
4662 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4663 1 : break;
4664 16384 : case GDT_UInt16:
4665 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4666 16384 : break;
4667 3 : case GDT_Int16:
4668 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4669 3 : break;
4670 0 : case GDT_UInt32:
4671 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4672 0 : break;
4673 60 : case GDT_Int32:
4674 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4675 60 : break;
4676 0 : case GDT_UInt64:
4677 0 : dfValue = static_cast<double>(
4678 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4679 0 : break;
4680 0 : case GDT_Int64:
4681 0 : dfValue = static_cast<double>(
4682 0 : static_cast<GInt64 *>(pData)[iOffset]);
4683 0 : break;
4684 0 : case GDT_Float16:
4685 : {
4686 : using namespace std;
4687 0 : const GFloat16 hfValue =
4688 0 : static_cast<GFloat16 *>(pData)[iOffset];
4689 0 : if (isnan(hfValue) ||
4690 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4691 0 : ARE_REAL_EQUAL(hfValue,
4692 : sNoDataValues.hfNoDataValue)))
4693 0 : continue;
4694 0 : dfValue = hfValue;
4695 0 : break;
4696 : }
4697 3 : case GDT_Float32:
4698 : {
4699 3 : const float fValue =
4700 3 : static_cast<float *>(pData)[iOffset];
4701 6 : if (std::isnan(fValue) ||
4702 6 : (sNoDataValues.bGotFloatNoDataValue &&
4703 3 : ARE_REAL_EQUAL(fValue,
4704 : sNoDataValues.fNoDataValue)))
4705 0 : continue;
4706 3 : dfValue = double(fValue);
4707 3 : break;
4708 : }
4709 2 : case GDT_Float64:
4710 2 : dfValue = static_cast<double *>(pData)[iOffset];
4711 2 : if (std::isnan(dfValue))
4712 0 : continue;
4713 2 : break;
4714 0 : case GDT_CInt16:
4715 : {
4716 0 : double dfReal =
4717 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4718 0 : double dfImag =
4719 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4720 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4721 0 : break;
4722 : }
4723 0 : case GDT_CInt32:
4724 : {
4725 0 : double dfReal =
4726 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4727 0 : double dfImag =
4728 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4729 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4730 0 : break;
4731 : }
4732 0 : case GDT_CFloat16:
4733 : {
4734 : double dfReal =
4735 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4736 : double dfImag =
4737 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4738 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4739 0 : continue;
4740 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4741 0 : break;
4742 : }
4743 0 : case GDT_CFloat32:
4744 : {
4745 0 : double dfReal = double(
4746 0 : static_cast<float *>(pData)[iOffset * 2]);
4747 0 : double dfImag = double(
4748 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4749 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4750 0 : continue;
4751 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4752 0 : break;
4753 : }
4754 0 : case GDT_CFloat64:
4755 : {
4756 0 : double dfReal =
4757 0 : static_cast<double *>(pData)[iOffset * 2];
4758 0 : double dfImag =
4759 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4760 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4761 0 : continue;
4762 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4763 0 : break;
4764 : }
4765 0 : case GDT_Unknown:
4766 : case GDT_TypeCount:
4767 0 : CPLAssert(false);
4768 : CPLFree(pabyMaskData);
4769 : return CE_Failure;
4770 : }
4771 :
4772 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4773 72338 : sNoDataValues.bGotNoDataValue &&
4774 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4775 0 : continue;
4776 :
4777 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4778 : // and finite, the result of the multiplication cannot be
4779 : // NaN
4780 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4781 :
4782 36169 : if (dfIndex < 0)
4783 : {
4784 1 : if (bIncludeOutOfRange)
4785 1 : panHistogram[0]++;
4786 : }
4787 36168 : else if (dfIndex >= nBuckets)
4788 : {
4789 7 : if (bIncludeOutOfRange)
4790 4 : ++panHistogram[nBuckets - 1];
4791 : }
4792 : else
4793 : {
4794 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4795 : }
4796 : }
4797 : }
4798 :
4799 39 : poBlock->DropLock();
4800 : }
4801 :
4802 35 : CPLFree(pabyMaskData);
4803 : }
4804 :
4805 35 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4806 :
4807 35 : return CE_None;
4808 : }
4809 :
4810 : /************************************************************************/
4811 : /* GDALGetRasterHistogram() */
4812 : /************************************************************************/
4813 :
4814 : /**
4815 : * \brief Compute raster histogram.
4816 : *
4817 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4818 : * exceeding 2 billion.
4819 : *
4820 : * @see GDALRasterBand::GetHistogram()
4821 : * @see GDALGetRasterHistogramEx()
4822 : */
4823 :
4824 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4825 : double dfMax, int nBuckets,
4826 : int *panHistogram,
4827 : int bIncludeOutOfRange, int bApproxOK,
4828 : GDALProgressFunc pfnProgress,
4829 : void *pProgressData)
4830 :
4831 : {
4832 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4833 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4834 :
4835 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4836 :
4837 : GUIntBig *panHistogramTemp =
4838 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4839 0 : if (panHistogramTemp == nullptr)
4840 : {
4841 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4842 : "Out of memory in GDALGetRasterHistogram().");
4843 0 : return CE_Failure;
4844 : }
4845 :
4846 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4847 : bIncludeOutOfRange, bApproxOK,
4848 0 : pfnProgress, pProgressData);
4849 :
4850 0 : if (eErr == CE_None)
4851 : {
4852 0 : for (int i = 0; i < nBuckets; i++)
4853 : {
4854 0 : if (panHistogramTemp[i] > INT_MAX)
4855 : {
4856 0 : CPLError(CE_Warning, CPLE_AppDefined,
4857 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4858 : " exceeds maximum 32 bit value",
4859 0 : i, panHistogramTemp[i]);
4860 0 : panHistogram[i] = INT_MAX;
4861 : }
4862 : else
4863 : {
4864 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4865 : }
4866 : }
4867 : }
4868 :
4869 0 : CPLFree(panHistogramTemp);
4870 :
4871 0 : return eErr;
4872 : }
4873 :
4874 : /************************************************************************/
4875 : /* GDALGetRasterHistogramEx() */
4876 : /************************************************************************/
4877 :
4878 : /**
4879 : * \brief Compute raster histogram.
4880 : *
4881 : * @see GDALRasterBand::GetHistogram()
4882 : *
4883 : */
4884 :
4885 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4886 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4887 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4888 : GDALProgressFunc pfnProgress, void *pProgressData)
4889 :
4890 : {
4891 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4892 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4893 :
4894 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4895 :
4896 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4897 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4898 26 : pProgressData);
4899 : }
4900 :
4901 : /************************************************************************/
4902 : /* GetDefaultHistogram() */
4903 : /************************************************************************/
4904 :
4905 : /**
4906 : * \brief Fetch default raster histogram.
4907 : *
4908 : * The default method in GDALRasterBand will compute a default histogram. This
4909 : * method is overridden by derived classes (such as GDALPamRasterBand,
4910 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4911 : * stored histogram.
4912 : *
4913 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4914 : * GDALGetDefaultHistogramEx().
4915 : *
4916 : * @param pdfMin pointer to double value that will contain the lower bound of
4917 : * the histogram.
4918 : * @param pdfMax pointer to double value that will contain the upper bound of
4919 : * the histogram.
4920 : * @param pnBuckets pointer to int value that will contain the number of buckets
4921 : * in *ppanHistogram.
4922 : * @param ppanHistogram pointer to array into which the histogram totals are
4923 : * placed. To be freed with VSIFree
4924 : * @param bForce TRUE to force the computation. If FALSE and no default
4925 : * histogram is available, the method will return CE_Warning
4926 : * @param pfnProgress function to report progress to completion.
4927 : * @param pProgressData application data to pass to pfnProgress.
4928 : *
4929 : * @return CE_None on success, CE_Failure if something goes wrong, or
4930 : * CE_Warning if no default histogram is available.
4931 : */
4932 :
4933 27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4934 : int *pnBuckets,
4935 : GUIntBig **ppanHistogram, int bForce,
4936 : GDALProgressFunc pfnProgress,
4937 : void *pProgressData)
4938 :
4939 : {
4940 27 : CPLAssert(nullptr != pnBuckets);
4941 27 : CPLAssert(nullptr != ppanHistogram);
4942 27 : CPLAssert(nullptr != pdfMin);
4943 27 : CPLAssert(nullptr != pdfMax);
4944 :
4945 27 : *pnBuckets = 0;
4946 27 : *ppanHistogram = nullptr;
4947 :
4948 27 : if (!bForce)
4949 5 : return CE_Warning;
4950 :
4951 22 : int nBuckets = 256;
4952 :
4953 22 : bool bSignedByte = false;
4954 22 : if (eDataType == GDT_UInt8)
4955 : {
4956 20 : EnablePixelTypeSignedByteWarning(false);
4957 : const char *pszPixelType =
4958 20 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4959 20 : EnablePixelTypeSignedByteWarning(true);
4960 20 : bSignedByte =
4961 20 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4962 : }
4963 :
4964 22 : if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4965 : {
4966 20 : *pdfMin = -0.5;
4967 20 : *pdfMax = 255.5;
4968 : }
4969 2 : else if (GetRasterDataType() == GDT_Int8)
4970 : {
4971 1 : *pdfMin = -128 - 0.5;
4972 1 : *pdfMax = 127 + 0.5;
4973 : }
4974 : else
4975 : {
4976 :
4977 : const CPLErr eErr =
4978 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4979 1 : if (eErr != CE_None)
4980 0 : return eErr;
4981 1 : if (*pdfMin == *pdfMax)
4982 : {
4983 1 : nBuckets = 1;
4984 1 : *pdfMin -= 0.5;
4985 1 : *pdfMax += 0.5;
4986 : }
4987 : else
4988 : {
4989 0 : const double dfHalfBucket =
4990 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4991 0 : *pdfMin -= dfHalfBucket;
4992 0 : *pdfMax += dfHalfBucket;
4993 : }
4994 : }
4995 :
4996 22 : *ppanHistogram =
4997 22 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4998 22 : if (*ppanHistogram == nullptr)
4999 : {
5000 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
5001 : "Out of memory in GetDefaultHistogram().");
5002 0 : return CE_Failure;
5003 : }
5004 :
5005 22 : *pnBuckets = nBuckets;
5006 44 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
5007 22 : TRUE, FALSE, pfnProgress, pProgressData);
5008 22 : if (eErr != CE_None)
5009 : {
5010 0 : *pnBuckets = 0;
5011 : }
5012 22 : return eErr;
5013 : }
5014 :
5015 : /************************************************************************/
5016 : /* GDALGetDefaultHistogram() */
5017 : /************************************************************************/
5018 :
5019 : /**
5020 : * \brief Fetch default raster histogram.
5021 : *
5022 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
5023 : * exceeding 2 billion.
5024 : *
5025 : * @see GDALRasterBand::GDALGetDefaultHistogram()
5026 : * @see GDALGetRasterHistogramEx()
5027 : */
5028 :
5029 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
5030 : double *pdfMin, double *pdfMax,
5031 : int *pnBuckets, int **ppanHistogram,
5032 : int bForce,
5033 : GDALProgressFunc pfnProgress,
5034 : void *pProgressData)
5035 :
5036 : {
5037 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5038 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5039 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5040 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5041 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5042 :
5043 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5044 0 : GUIntBig *panHistogramTemp = nullptr;
5045 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5046 : &panHistogramTemp, bForce,
5047 0 : pfnProgress, pProgressData);
5048 0 : if (eErr == CE_None)
5049 : {
5050 0 : const int nBuckets = *pnBuckets;
5051 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5052 0 : if (*ppanHistogram == nullptr)
5053 : {
5054 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5055 : "Out of memory in GDALGetDefaultHistogram().");
5056 0 : VSIFree(panHistogramTemp);
5057 0 : return CE_Failure;
5058 : }
5059 :
5060 0 : for (int i = 0; i < nBuckets; ++i)
5061 : {
5062 0 : if (panHistogramTemp[i] > INT_MAX)
5063 : {
5064 0 : CPLError(CE_Warning, CPLE_AppDefined,
5065 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5066 : " exceeds maximum 32 bit value",
5067 0 : i, panHistogramTemp[i]);
5068 0 : (*ppanHistogram)[i] = INT_MAX;
5069 : }
5070 : else
5071 : {
5072 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5073 : }
5074 : }
5075 :
5076 0 : CPLFree(panHistogramTemp);
5077 : }
5078 : else
5079 : {
5080 0 : *ppanHistogram = nullptr;
5081 : }
5082 :
5083 0 : return eErr;
5084 : }
5085 :
5086 : /************************************************************************/
5087 : /* GDALGetDefaultHistogramEx() */
5088 : /************************************************************************/
5089 :
5090 : /**
5091 : * \brief Fetch default raster histogram.
5092 : *
5093 : * @see GDALRasterBand::GetDefaultHistogram()
5094 : *
5095 : */
5096 :
5097 : CPLErr CPL_STDCALL
5098 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5099 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5100 : GDALProgressFunc pfnProgress, void *pProgressData)
5101 :
5102 : {
5103 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5104 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5105 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5106 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5107 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5108 :
5109 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5110 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5111 30 : bForce, pfnProgress, pProgressData);
5112 : }
5113 :
5114 : /************************************************************************/
5115 : /* AdviseRead() */
5116 : /************************************************************************/
5117 :
5118 : /**
5119 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5120 : * \brief Advise driver of upcoming read requests.
5121 : *
5122 : * Some GDAL drivers operate more efficiently if they know in advance what
5123 : * set of upcoming read requests will be made. The AdviseRead() method allows
5124 : * an application to notify the driver of the region of interest,
5125 : * and at what resolution the region will be read.
5126 : *
5127 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5128 : * accelerate access via some drivers.
5129 : *
5130 : * Depending on call paths, drivers might receive several calls to
5131 : * AdviseRead() with the same parameters.
5132 : *
5133 : * @param nXOff The pixel offset to the top left corner of the region
5134 : * of the band to be accessed. This would be zero to start from the left side.
5135 : *
5136 : * @param nYOff The line offset to the top left corner of the region
5137 : * of the band to be accessed. This would be zero to start from the top.
5138 : *
5139 : * @param nXSize The width of the region of the band to be accessed in pixels.
5140 : *
5141 : * @param nYSize The height of the region of the band to be accessed in lines.
5142 : *
5143 : * @param nBufXSize the width of the buffer image into which the desired region
5144 : * is to be read, or from which it is to be written.
5145 : *
5146 : * @param nBufYSize the height of the buffer image into which the desired
5147 : * region is to be read, or from which it is to be written.
5148 : *
5149 : * @param eBufType the type of the pixel values in the pData data buffer. The
5150 : * pixel values will automatically be translated to/from the GDALRasterBand
5151 : * data type as needed.
5152 : *
5153 : * @param papszOptions a list of name=value strings with special control
5154 : * options. Normally this is NULL.
5155 : *
5156 : * @return CE_Failure if the request is invalid and CE_None if it works or
5157 : * is ignored.
5158 : */
5159 :
5160 : /**/
5161 : /**/
5162 :
5163 114595 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5164 : int /*nYSize*/, int /*nBufXSize*/,
5165 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5166 : CSLConstList /*papszOptions*/)
5167 : {
5168 114595 : return CE_None;
5169 : }
5170 :
5171 : /************************************************************************/
5172 : /* GDALRasterAdviseRead() */
5173 : /************************************************************************/
5174 :
5175 : /**
5176 : * \brief Advise driver of upcoming read requests.
5177 : *
5178 : * @see GDALRasterBand::AdviseRead()
5179 : */
5180 :
5181 4 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5182 : int nYOff, int nXSize, int nYSize,
5183 : int nBufXSize, int nBufYSize,
5184 : GDALDataType eDT,
5185 : CSLConstList papszOptions)
5186 :
5187 : {
5188 4 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5189 :
5190 4 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5191 4 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5192 : nBufYSize, eDT,
5193 4 : const_cast<char **>(papszOptions));
5194 : }
5195 :
5196 : /************************************************************************/
5197 : /* GetStatistics() */
5198 : /************************************************************************/
5199 :
5200 : /**
5201 : * \brief Fetch image statistics.
5202 : *
5203 : * Returns the minimum, maximum, mean and standard deviation of all
5204 : * pixel values in this band. If approximate statistics are sufficient,
5205 : * the bApproxOK flag can be set to true in which case overviews, or a
5206 : * subset of image tiles may be used in computing the statistics.
5207 : *
5208 : * If bForce is FALSE results will only be returned if it can be done
5209 : * quickly (i.e. without scanning the image, typically by using pre-existing
5210 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5211 : * returned efficiently, the method will return CE_Warning but no warning will
5212 : * be issued. This is a non-standard use of the CE_Warning return value
5213 : * to indicate "nothing done".
5214 : *
5215 : * If bForce is TRUE, and results are quickly available without scanning the
5216 : * image, they will be used. If bForce is TRUE and results are not quickly
5217 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5218 : * which will scan the image.
5219 : *
5220 : * To always force recomputation of statistics, use ComputeStatistics() instead
5221 : * of this method.
5222 : *
5223 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5224 : * will generally cache statistics in the .pam file allowing fast fetch
5225 : * after the first request.
5226 : *
5227 : * This method is the same as the C function GDALGetRasterStatistics().
5228 : *
5229 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5230 : * or a subset of all tiles.
5231 : *
5232 : * @param bForce If FALSE statistics will only be returned if it can
5233 : * be done without rescanning the image. If TRUE, statistics computation will
5234 : * be forced if pre-existing values are not quickly available.
5235 : *
5236 : * @param pdfMin Location into which to load image minimum (may be NULL).
5237 : *
5238 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5239 : *
5240 : * @param pdfMean Location into which to load image mean (may be NULL).
5241 : *
5242 : * @param pdfStdDev Location into which to load image standard deviation
5243 : * (may be NULL).
5244 : *
5245 : * @return CE_None on success, CE_Warning if no values returned,
5246 : * CE_Failure if an error occurs.
5247 : */
5248 :
5249 676 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5250 : double *pdfMax, double *pdfMean,
5251 : double *pdfStdDev)
5252 :
5253 : {
5254 : /* -------------------------------------------------------------------- */
5255 : /* Do we already have metadata items for the requested values? */
5256 : /* -------------------------------------------------------------------- */
5257 1352 : if ((pdfMin == nullptr ||
5258 676 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5259 206 : (pdfMax == nullptr ||
5260 206 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5261 1558 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5262 206 : (pdfStdDev == nullptr ||
5263 206 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5264 : {
5265 206 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5266 : {
5267 199 : if (pdfMin != nullptr)
5268 199 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5269 199 : if (pdfMax != nullptr)
5270 199 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5271 199 : if (pdfMean != nullptr)
5272 199 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5273 199 : if (pdfStdDev != nullptr)
5274 199 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5275 :
5276 199 : return CE_None;
5277 : }
5278 : }
5279 :
5280 : /* -------------------------------------------------------------------- */
5281 : /* Does the driver already know the min/max? */
5282 : /* -------------------------------------------------------------------- */
5283 477 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5284 : {
5285 1 : int bSuccessMin = FALSE;
5286 1 : int bSuccessMax = FALSE;
5287 :
5288 1 : const double dfMin = GetMinimum(&bSuccessMin);
5289 1 : const double dfMax = GetMaximum(&bSuccessMax);
5290 :
5291 1 : if (bSuccessMin && bSuccessMax)
5292 : {
5293 0 : if (pdfMin != nullptr)
5294 0 : *pdfMin = dfMin;
5295 0 : if (pdfMax != nullptr)
5296 0 : *pdfMax = dfMax;
5297 0 : return CE_None;
5298 : }
5299 : }
5300 :
5301 : /* -------------------------------------------------------------------- */
5302 : /* Either return without results, or force computation. */
5303 : /* -------------------------------------------------------------------- */
5304 477 : if (!bForce)
5305 194 : return CE_Warning;
5306 : else
5307 283 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5308 283 : GDALDummyProgress, nullptr);
5309 : }
5310 :
5311 : /************************************************************************/
5312 : /* GDALGetRasterStatistics() */
5313 : /************************************************************************/
5314 :
5315 : /**
5316 : * \brief Fetch image statistics.
5317 : *
5318 : * @see GDALRasterBand::GetStatistics()
5319 : */
5320 :
5321 324 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5322 : int bForce, double *pdfMin,
5323 : double *pdfMax, double *pdfMean,
5324 : double *pdfStdDev)
5325 :
5326 : {
5327 324 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5328 :
5329 324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5330 324 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5331 324 : pdfStdDev);
5332 : }
5333 :
5334 : /************************************************************************/
5335 : /* GDALUInt128 */
5336 : /************************************************************************/
5337 :
5338 : #ifdef HAVE_UINT128_T
5339 : class GDALUInt128
5340 : {
5341 : __uint128_t val;
5342 :
5343 1200 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5344 : {
5345 1200 : }
5346 :
5347 : public:
5348 800 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5349 : {
5350 : // Evaluates to just a single mul on x86_64
5351 800 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5352 : }
5353 :
5354 400 : GDALUInt128 operator-(const GDALUInt128 &other) const
5355 : {
5356 400 : return GDALUInt128(val - other.val);
5357 : }
5358 :
5359 391 : operator double() const
5360 : {
5361 391 : return static_cast<double>(val);
5362 : }
5363 : };
5364 : #else
5365 :
5366 : #if defined(_MSC_VER) && defined(_M_X64)
5367 : #include <intrin.h>
5368 : #endif
5369 :
5370 : class GDALUInt128
5371 : {
5372 : GUIntBig low, high;
5373 :
5374 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5375 : {
5376 : }
5377 :
5378 : public:
5379 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5380 : {
5381 : #if defined(_MSC_VER) && defined(_M_X64)
5382 : GUIntBig highRes;
5383 : GUIntBig lowRes = _umul128(first, second, &highRes);
5384 : return GDALUInt128(lowRes, highRes);
5385 : #else
5386 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5387 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5388 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5389 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5390 : GUIntBig highRes = 0;
5391 : const GUIntBig firstLowSecondHigh =
5392 : static_cast<GUIntBig>(firstLow) * secondHigh;
5393 : const GUIntBig firstHighSecondLow =
5394 : static_cast<GUIntBig>(firstHigh) * secondLow;
5395 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5396 : if (middleTerm < firstLowSecondHigh) // check for overflow
5397 : highRes += static_cast<GUIntBig>(1) << 32;
5398 : const GUIntBig firstLowSecondLow =
5399 : static_cast<GUIntBig>(firstLow) * secondLow;
5400 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5401 : if (lowRes < firstLowSecondLow) // check for overflow
5402 : highRes++;
5403 : highRes +=
5404 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5405 : return GDALUInt128(lowRes, highRes);
5406 : #endif
5407 : }
5408 :
5409 : GDALUInt128 operator-(const GDALUInt128 &other) const
5410 : {
5411 : GUIntBig highRes = high - other.high;
5412 : GUIntBig lowRes = low - other.low;
5413 : if (lowRes > low) // check for underflow
5414 : --highRes;
5415 : return GDALUInt128(lowRes, highRes);
5416 : }
5417 :
5418 : operator double() const
5419 : {
5420 : const double twoPow64 = 18446744073709551616.0;
5421 : return high * twoPow64 + low;
5422 : }
5423 : };
5424 : #endif
5425 :
5426 : /************************************************************************/
5427 : /* ComputeStatisticsInternal() */
5428 : /************************************************************************/
5429 :
5430 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5431 : // not needed.
5432 : #define static_cast_for_coverity_scan static_cast
5433 :
5434 : // The rationale for below optimizations is detailed in statistics.txt
5435 :
5436 : // Use with T = GByte or GUInt16 only !
5437 : template <class T, bool COMPUTE_OTHER_STATS>
5438 : struct ComputeStatisticsInternalGeneric
5439 : {
5440 301 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5441 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5442 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5443 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5444 : {
5445 : static_assert(std::is_same<T, GByte>::value ||
5446 : std::is_same<T, GUInt16>::value,
5447 : "bad type for T");
5448 301 : if (bHasNoData)
5449 : {
5450 : // General case
5451 700 : for (int iY = 0; iY < nYCheck; iY++)
5452 : {
5453 161945 : for (int iX = 0; iX < nXCheck; iX++)
5454 : {
5455 161413 : const GPtrDiff_t iOffset =
5456 161413 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5457 161413 : const GUInt32 nValue = pData[iOffset];
5458 161413 : if (nValue == nNoDataValue)
5459 339 : continue;
5460 161074 : if (nValue < nMin)
5461 64 : nMin = nValue;
5462 161074 : if (nValue > nMax)
5463 179 : nMax = nValue;
5464 : if constexpr (COMPUTE_OTHER_STATS)
5465 : {
5466 159334 : nValidCount++;
5467 159334 : nSum += nValue;
5468 159334 : nSumSquare +=
5469 159334 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5470 159334 : nValue;
5471 : }
5472 : }
5473 : }
5474 : if constexpr (COMPUTE_OTHER_STATS)
5475 : {
5476 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5477 : }
5478 : }
5479 153 : else if (nMin == std::numeric_limits<T>::lowest() &&
5480 20 : nMax == std::numeric_limits<T>::max())
5481 : {
5482 : if constexpr (COMPUTE_OTHER_STATS)
5483 : {
5484 : // Optimization when there is no nodata and we know we have already
5485 : // reached the min and max
5486 416 : for (int iY = 0; iY < nYCheck; iY++)
5487 : {
5488 : int iX;
5489 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5490 : {
5491 1600 : const GPtrDiff_t iOffset =
5492 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493 1600 : const GUIntBig nValue = pData[iOffset];
5494 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5495 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5496 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5497 1600 : nSum += nValue;
5498 1600 : nSumSquare += nValue * nValue;
5499 1600 : nSum += nValue2;
5500 1600 : nSumSquare += nValue2 * nValue2;
5501 1600 : nSum += nValue3;
5502 1600 : nSumSquare += nValue3 * nValue3;
5503 1600 : nSum += nValue4;
5504 1600 : nSumSquare += nValue4 * nValue4;
5505 : }
5506 414 : for (; iX < nXCheck; ++iX)
5507 : {
5508 10 : const GPtrDiff_t iOffset =
5509 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5510 10 : const GUIntBig nValue = pData[iOffset];
5511 10 : nSum += nValue;
5512 10 : nSumSquare += nValue * nValue;
5513 : }
5514 : }
5515 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5516 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5517 : }
5518 : }
5519 : else
5520 : {
5521 6531 : for (int iY = 0; iY < nYCheck; iY++)
5522 : {
5523 : int iX;
5524 1329024 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5525 : {
5526 1322620 : const GPtrDiff_t iOffset =
5527 1322620 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5528 1322620 : const GUInt32 nValue = pData[iOffset];
5529 1322620 : const GUInt32 nValue2 = pData[iOffset + 1];
5530 1322620 : if (nValue < nValue2)
5531 : {
5532 2329 : if (nValue < nMin)
5533 53 : nMin = nValue;
5534 2329 : if (nValue2 > nMax)
5535 123 : nMax = nValue2;
5536 : }
5537 : else
5538 : {
5539 1320289 : if (nValue2 < nMin)
5540 67 : nMin = nValue2;
5541 1320289 : if (nValue > nMax)
5542 219 : nMax = nValue;
5543 : }
5544 : if constexpr (COMPUTE_OTHER_STATS)
5545 : {
5546 1315560 : nSum += nValue;
5547 1315560 : nSumSquare +=
5548 1315560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5549 1315560 : nValue;
5550 1315560 : nSum += nValue2;
5551 1315560 : nSumSquare +=
5552 1315560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5553 1315560 : nValue2;
5554 : }
5555 : }
5556 6410 : if (iX < nXCheck)
5557 : {
5558 31 : const GPtrDiff_t iOffset =
5559 31 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5560 31 : const GUInt32 nValue = pData[iOffset];
5561 31 : if (nValue < nMin)
5562 19 : nMin = nValue;
5563 31 : if (nValue > nMax)
5564 22 : nMax = nValue;
5565 : if (COMPUTE_OTHER_STATS)
5566 : {
5567 19 : nSum += nValue;
5568 19 : nSumSquare +=
5569 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5570 19 : nValue;
5571 : }
5572 : }
5573 : }
5574 : if constexpr (COMPUTE_OTHER_STATS)
5575 : {
5576 62 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5577 62 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5578 : }
5579 : }
5580 301 : }
5581 : };
5582 :
5583 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5584 : // using 64bit accumulators in internal loops. This also slightly helps in
5585 : // 64bit mode.
5586 : template <bool COMPUTE_OTHER_STATS>
5587 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5588 : {
5589 13828 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5590 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5591 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5592 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5593 : {
5594 13828 : int nOuterLoops = nXCheck / 65536;
5595 13828 : if (nXCheck % 65536)
5596 13828 : nOuterLoops++;
5597 :
5598 13828 : if (bHasNoData)
5599 : {
5600 : // General case
5601 23881 : for (int iY = 0; iY < nYCheck; iY++)
5602 : {
5603 13245 : int iX = 0;
5604 26490 : for (int k = 0; k < nOuterLoops; k++)
5605 : {
5606 13245 : int iMax = iX + 65536;
5607 13245 : if (iMax > nXCheck)
5608 13245 : iMax = nXCheck;
5609 13245 : GUInt32 nSum32bit = 0;
5610 13245 : GUInt32 nSumSquare32bit = 0;
5611 13245 : GUInt32 nValidCount32bit = 0;
5612 13245 : GUInt32 nSampleCount32bit = 0;
5613 20723132 : for (; iX < iMax; iX++)
5614 : {
5615 20709887 : const GPtrDiff_t iOffset =
5616 20709887 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5617 20709887 : const GUInt32 nValue = pData[iOffset];
5618 :
5619 20709887 : nSampleCount32bit++;
5620 20709887 : if (nValue == nNoDataValue)
5621 20353620 : continue;
5622 356216 : if (nValue < nMin)
5623 401 : nMin = nValue;
5624 356216 : if (nValue > nMax)
5625 942 : nMax = nValue;
5626 : if constexpr (COMPUTE_OTHER_STATS)
5627 : {
5628 32367 : nValidCount32bit++;
5629 32367 : nSum32bit += nValue;
5630 32367 : nSumSquare32bit += nValue * nValue;
5631 : }
5632 : }
5633 : if constexpr (COMPUTE_OTHER_STATS)
5634 : {
5635 945 : nSampleCount += nSampleCount32bit;
5636 945 : nValidCount += nValidCount32bit;
5637 945 : nSum += nSum32bit;
5638 945 : nSumSquare += nSumSquare32bit;
5639 : }
5640 : }
5641 : }
5642 : }
5643 3192 : else if (nMin == 0 && nMax == 255)
5644 : {
5645 : if constexpr (COMPUTE_OTHER_STATS)
5646 : {
5647 : // Optimization when there is no nodata and we know we have already
5648 : // reached the min and max
5649 2850 : for (int iY = 0; iY < nYCheck; iY++)
5650 : {
5651 2818 : int iX = 0;
5652 5636 : for (int k = 0; k < nOuterLoops; k++)
5653 : {
5654 2818 : int iMax = iX + 65536;
5655 2818 : if (iMax > nXCheck)
5656 2818 : iMax = nXCheck;
5657 2818 : GUInt32 nSum32bit = 0;
5658 2818 : GUInt32 nSumSquare32bit = 0;
5659 177298 : for (; iX + 3 < iMax; iX += 4)
5660 : {
5661 174480 : const GPtrDiff_t iOffset =
5662 174480 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5663 174480 : const GUInt32 nValue = pData[iOffset];
5664 174480 : const GUInt32 nValue2 = pData[iOffset + 1];
5665 174480 : const GUInt32 nValue3 = pData[iOffset + 2];
5666 174480 : const GUInt32 nValue4 = pData[iOffset + 3];
5667 174480 : nSum32bit += nValue;
5668 174480 : nSumSquare32bit += nValue * nValue;
5669 174480 : nSum32bit += nValue2;
5670 174480 : nSumSquare32bit += nValue2 * nValue2;
5671 174480 : nSum32bit += nValue3;
5672 174480 : nSumSquare32bit += nValue3 * nValue3;
5673 174480 : nSum32bit += nValue4;
5674 174480 : nSumSquare32bit += nValue4 * nValue4;
5675 : }
5676 2818 : nSum += nSum32bit;
5677 2818 : nSumSquare += nSumSquare32bit;
5678 : }
5679 2824 : for (; iX < nXCheck; ++iX)
5680 : {
5681 6 : const GPtrDiff_t iOffset =
5682 6 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5683 6 : const GUIntBig nValue = pData[iOffset];
5684 6 : nSum += nValue;
5685 6 : nSumSquare += nValue * nValue;
5686 : }
5687 : }
5688 32 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5689 32 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5690 32 : }
5691 : }
5692 : else
5693 : {
5694 9026 : for (int iY = 0; iY < nYCheck; iY++)
5695 : {
5696 5866 : int iX = 0;
5697 11732 : for (int k = 0; k < nOuterLoops; k++)
5698 : {
5699 5866 : int iMax = iX + 65536;
5700 5866 : if (iMax > nXCheck)
5701 5866 : iMax = nXCheck;
5702 5866 : GUInt32 nSum32bit = 0;
5703 5866 : GUInt32 nSumSquare32bit = 0;
5704 343848 : for (; iX + 1 < iMax; iX += 2)
5705 : {
5706 337982 : const GPtrDiff_t iOffset =
5707 337982 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5708 337982 : const GUInt32 nValue = pData[iOffset];
5709 337982 : const GUInt32 nValue2 = pData[iOffset + 1];
5710 337982 : if (nValue < nValue2)
5711 : {
5712 8155 : if (nValue < nMin)
5713 237 : nMin = nValue;
5714 8155 : if (nValue2 > nMax)
5715 230 : nMax = nValue2;
5716 : }
5717 : else
5718 : {
5719 329827 : if (nValue2 < nMin)
5720 364 : nMin = nValue2;
5721 329827 : if (nValue > nMax)
5722 841 : nMax = nValue;
5723 : }
5724 : if constexpr (COMPUTE_OTHER_STATS)
5725 : {
5726 315626 : nSum32bit += nValue;
5727 315626 : nSumSquare32bit += nValue * nValue;
5728 315626 : nSum32bit += nValue2;
5729 315626 : nSumSquare32bit += nValue2 * nValue2;
5730 : }
5731 : }
5732 : if constexpr (COMPUTE_OTHER_STATS)
5733 : {
5734 2650 : nSum += nSum32bit;
5735 2650 : nSumSquare += nSumSquare32bit;
5736 : }
5737 : }
5738 5866 : if (iX < nXCheck)
5739 : {
5740 1541 : const GPtrDiff_t iOffset =
5741 1541 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5742 1541 : const GUInt32 nValue = pData[iOffset];
5743 1541 : if (nValue < nMin)
5744 117 : nMin = nValue;
5745 1541 : if (nValue > nMax)
5746 103 : nMax = nValue;
5747 : if constexpr (COMPUTE_OTHER_STATS)
5748 : {
5749 321 : nSum += nValue;
5750 321 : nSumSquare +=
5751 321 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5752 321 : nValue;
5753 : }
5754 : }
5755 : }
5756 : if constexpr (COMPUTE_OTHER_STATS)
5757 : {
5758 938 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5759 938 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5760 : }
5761 : }
5762 13828 : }
5763 : };
5764 :
5765 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5766 : {
5767 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5768 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5769 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5770 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5771 : {
5772 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5773 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5774 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5775 : }
5776 : };
5777 :
5778 : constexpr int ALIGNMENT_AVX2_OPTIM = 32;
5779 :
5780 : #if (defined(__x86_64__) || defined(_M_X64) || \
5781 : defined(USE_NEON_OPTIMIZATIONS)) && \
5782 : (defined(__GNUC__) || defined(_MSC_VER))
5783 :
5784 : #include "gdal_avx2_emulation.hpp"
5785 :
5786 : #define ZERO256 GDALmm256_setzero_si256()
5787 :
5788 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5789 : static void
5790 21355 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5791 : // assumed to be aligned on 256 bits
5792 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5793 : GUIntBig &nSum, GUIntBig &nSumSquare,
5794 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5795 : {
5796 : // 32-byte alignment may not be enforced by linker, so do it at hand
5797 : GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
5798 : ALIGNMENT_AVX2_OPTIM +
5799 : (COMPUTE_OTHER_STATS
5800 : ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
5801 : : 0)];
5802 21355 : GByte *paby32ByteAligned =
5803 : aby32ByteUnaligned +
5804 21355 : (ALIGNMENT_AVX2_OPTIM -
5805 21355 : (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
5806 : ALIGNMENT_AVX2_OPTIM));
5807 21355 : GByte *pabyMin = paby32ByteAligned;
5808 21355 : GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
5809 21355 : GUInt32 *panSum = COMPUTE_OTHER_STATS
5810 : ? reinterpret_cast<GUInt32 *>(
5811 : paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
5812 : : nullptr;
5813 21355 : GUInt32 *panSumSquare =
5814 : COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
5815 : paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
5816 : : nullptr;
5817 :
5818 21355 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
5819 :
5820 21355 : GPtrDiff_t i = 0;
5821 : // Make sure that sumSquare can fit on uint32
5822 : // * 8 since we can hold 8 sums per vector register
5823 21355 : const int nMaxIterationsPerInnerLoop =
5824 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5825 21355 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5826 21355 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5827 21355 : nOuterLoops++;
5828 :
5829 : GDALm256i ymm_min =
5830 21355 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5831 21355 : GDALm256i ymm_max = ymm_min;
5832 21355 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5833 :
5834 42710 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5835 : {
5836 21355 : const auto iMax =
5837 21355 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5838 :
5839 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5840 21355 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5841 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5842 21355 : ZERO256; // holds 8 uint32 sums
5843 752431 : for (; i + 31 < iMax; i += 32)
5844 : {
5845 731076 : const GDALm256i ymm = GDALmm256_load_si256(
5846 731076 : reinterpret_cast<const GDALm256i *>(pData + i));
5847 : if (COMPUTE_MIN)
5848 : {
5849 271015 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5850 : }
5851 : if (COMPUTE_MAX)
5852 : {
5853 636401 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5854 : }
5855 :
5856 : if constexpr (COMPUTE_OTHER_STATS)
5857 : {
5858 : // Extract even-8bit values
5859 : const GDALm256i ymm_even =
5860 531792 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5861 : // Compute square of those 16 values as 32 bit result
5862 : // and add adjacent pairs
5863 : const GDALm256i ymm_even_square =
5864 531792 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5865 : // Add to the sumsquare accumulator
5866 : ymm_sumsquare =
5867 531792 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5868 :
5869 : // Extract odd-8bit values
5870 531792 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5871 : const GDALm256i ymm_odd_square =
5872 531792 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5873 : ymm_sumsquare =
5874 531792 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5875 :
5876 : // Now compute the sums
5877 531792 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5878 : GDALmm256_sad_epu8(ymm, ZERO256));
5879 : }
5880 : }
5881 :
5882 : if constexpr (COMPUTE_OTHER_STATS)
5883 : {
5884 10685 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5885 : ymm_sum);
5886 10685 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5887 : ymm_sumsquare);
5888 :
5889 10685 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5890 10685 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5891 10685 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5892 10685 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5893 : panSumSquare[7];
5894 : }
5895 : }
5896 :
5897 : if constexpr (COMPUTE_MIN)
5898 : {
5899 8464 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5900 : }
5901 : if constexpr (COMPUTE_MAX)
5902 : {
5903 17407 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5904 : }
5905 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5906 : {
5907 591459 : for (int j = 0; j < 32; j++)
5908 : {
5909 : if constexpr (COMPUTE_MIN)
5910 : {
5911 270848 : if (pabyMin[j] < nMin)
5912 1247 : nMin = pabyMin[j];
5913 : }
5914 : if constexpr (COMPUTE_MAX)
5915 : {
5916 557024 : if (pabyMax[j] > nMax)
5917 1794 : nMax = pabyMax[j];
5918 : }
5919 : }
5920 : }
5921 :
5922 234373 : for (; i < nBlockPixels; i++)
5923 : {
5924 213018 : const GUInt32 nValue = pData[i];
5925 : if constexpr (COMPUTE_MIN)
5926 : {
5927 88342 : if (nValue < nMin)
5928 2 : nMin = nValue;
5929 : }
5930 : if constexpr (COMPUTE_MAX)
5931 : {
5932 210243 : if (nValue > nMax)
5933 1150 : nMax = nValue;
5934 : }
5935 : if constexpr (COMPUTE_OTHER_STATS)
5936 : {
5937 77203 : nSum += nValue;
5938 77203 : nSumSquare +=
5939 77203 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5940 : }
5941 : }
5942 :
5943 : if constexpr (COMPUTE_OTHER_STATS)
5944 : {
5945 10685 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5946 10685 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5947 : }
5948 21355 : }
5949 :
5950 : // SSE2/AVX2 optimization for GByte case
5951 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5952 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5953 : // there are strictly equivalent to 2 parallel SSE2 streams.
5954 : template <bool COMPUTE_OTHER_STATS>
5955 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5956 : {
5957 30352 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5958 : // assumed to be aligned on 256 bits
5959 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5960 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5961 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5962 : GUIntBig &nValidCount)
5963 : {
5964 30352 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5965 30352 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5966 11610 : nMin <= nMax)
5967 : {
5968 : // 32-byte alignment may not be enforced by linker, so do it at hand
5969 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5970 1492 : GByte *paby32ByteAligned =
5971 : aby32ByteUnaligned +
5972 1492 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5973 1492 : GByte *pabyMin = paby32ByteAligned;
5974 1492 : GByte *pabyMax = paby32ByteAligned + 32;
5975 1492 : GUInt32 *panSum =
5976 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5977 1492 : GUInt32 *panSumSquare =
5978 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5979 :
5980 1492 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5981 :
5982 1492 : GPtrDiff_t i = 0;
5983 : // Make sure that sumSquare can fit on uint32
5984 : // * 8 since we can hold 8 sums per vector register
5985 1492 : const int nMaxIterationsPerInnerLoop =
5986 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5987 1492 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5988 1492 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5989 1492 : nOuterLoops++;
5990 :
5991 : const GDALm256i ymm_nodata =
5992 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5993 : // any non noData value in [min,max] would do.
5994 : const GDALm256i ymm_neutral =
5995 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5996 1492 : GDALm256i ymm_min = ymm_neutral;
5997 1492 : GDALm256i ymm_max = ymm_neutral;
5998 : [[maybe_unused]] const auto ymm_mask_8bits =
5999 1492 : GDALmm256_set1_epi16(0xFF);
6000 :
6001 1492 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
6002 1492 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
6003 1492 : const bool bComputeMinMax =
6004 1492 : nMin > nMinThreshold || nMax < nMaxThreshold;
6005 :
6006 2984 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
6007 : {
6008 1492 : const auto iMax =
6009 1492 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6010 :
6011 : // holds 4 uint32 sums in [0], [2], [4] and [6]
6012 1492 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
6013 : // holds 8 uint32 sums
6014 1492 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
6015 : // holds 4 uint32 sums in [0], [2], [4] and [6]
6016 1492 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
6017 1492 : const auto iInit = i;
6018 18982 : for (; i + 31 < iMax; i += 32)
6019 : {
6020 17490 : const GDALm256i ymm = GDALmm256_load_si256(
6021 17490 : reinterpret_cast<const GDALm256i *>(pData + i));
6022 :
6023 : // Check which values are nodata
6024 : const GDALm256i ymm_eq_nodata =
6025 17490 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
6026 : if constexpr (COMPUTE_OTHER_STATS)
6027 : {
6028 : // Count how many values are nodata (due to cmpeq
6029 : // putting 255 when condition is met, this will actually
6030 : // be 255 times the number of nodata value, spread in 4
6031 : // 64 bits words). We can use add_epi32 as the counter
6032 : // will not overflow uint32
6033 9148 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
6034 : ymm_count_nodata_mul_255,
6035 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
6036 : }
6037 : // Replace all nodata values by zero for the purpose of sum
6038 : // and sumquare.
6039 : const GDALm256i ymm_nodata_by_zero =
6040 17490 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
6041 17490 : if (bComputeMinMax)
6042 : {
6043 : // Replace all nodata values by a neutral value for the
6044 : // purpose of min and max.
6045 : const GDALm256i ymm_nodata_by_neutral =
6046 8720 : GDALmm256_or_si256(
6047 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6048 : ymm_nodata_by_zero);
6049 :
6050 : ymm_min =
6051 8720 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6052 : ymm_max =
6053 8720 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6054 : }
6055 :
6056 : if constexpr (COMPUTE_OTHER_STATS)
6057 : {
6058 : // Extract even-8bit values
6059 9148 : const GDALm256i ymm_even = GDALmm256_and_si256(
6060 : ymm_nodata_by_zero, ymm_mask_8bits);
6061 : // Compute square of those 16 values as 32 bit result
6062 : // and add adjacent pairs
6063 : const GDALm256i ymm_even_square =
6064 9148 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6065 : // Add to the sumsquare accumulator
6066 : ymm_sumsquare =
6067 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6068 :
6069 : // Extract odd-8bit values
6070 : const GDALm256i ymm_odd =
6071 9148 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6072 : const GDALm256i ymm_odd_square =
6073 9148 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6074 : ymm_sumsquare =
6075 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6076 :
6077 : // Now compute the sums
6078 9148 : ymm_sum = GDALmm256_add_epi32(
6079 : ymm_sum,
6080 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6081 : }
6082 : }
6083 :
6084 : if constexpr (COMPUTE_OTHER_STATS)
6085 : {
6086 186 : GUInt32 *panCoutNoDataMul255 = panSum;
6087 186 : GDALmm256_store_si256(
6088 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6089 : ymm_count_nodata_mul_255);
6090 :
6091 186 : nSampleCount += (i - iInit);
6092 :
6093 186 : nValidCount +=
6094 186 : (i - iInit) -
6095 186 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6096 186 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6097 : 255;
6098 :
6099 186 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6100 : ymm_sum);
6101 186 : GDALmm256_store_si256(
6102 : reinterpret_cast<GDALm256i *>(panSumSquare),
6103 : ymm_sumsquare);
6104 186 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6105 186 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6106 186 : panSumSquare[1] + panSumSquare[2] +
6107 186 : panSumSquare[3] + panSumSquare[4] +
6108 186 : panSumSquare[5] + panSumSquare[6] +
6109 : panSumSquare[7];
6110 : }
6111 : }
6112 :
6113 1492 : if (bComputeMinMax)
6114 : {
6115 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6116 : ymm_min);
6117 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6118 : ymm_max);
6119 47190 : for (int j = 0; j < 32; j++)
6120 : {
6121 45760 : if (pabyMin[j] < nMin)
6122 40 : nMin = pabyMin[j];
6123 45760 : if (pabyMax[j] > nMax)
6124 161 : nMax = pabyMax[j];
6125 : }
6126 : }
6127 :
6128 : if constexpr (COMPUTE_OTHER_STATS)
6129 : {
6130 186 : nSampleCount += nBlockPixels - i;
6131 : }
6132 34048 : for (; i < nBlockPixels; i++)
6133 : {
6134 32556 : const GUInt32 nValue = pData[i];
6135 32556 : if (nValue == nNoDataValue)
6136 24923 : continue;
6137 7633 : if (nValue < nMin)
6138 2 : nMin = nValue;
6139 7633 : if (nValue > nMax)
6140 14 : nMax = nValue;
6141 : if constexpr (COMPUTE_OTHER_STATS)
6142 : {
6143 3700 : nValidCount++;
6144 3700 : nSum += nValue;
6145 3700 : nSumSquare +=
6146 3700 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6147 3700 : nValue;
6148 : }
6149 1492 : }
6150 : }
6151 28860 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6152 : {
6153 14999 : if (nMin > 0)
6154 : {
6155 2108 : if (nMax < 255)
6156 : {
6157 : ComputeStatisticsByteNoNodata<true, true,
6158 1592 : COMPUTE_OTHER_STATS>(
6159 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6160 : nSampleCount, nValidCount);
6161 : }
6162 : else
6163 : {
6164 : ComputeStatisticsByteNoNodata<true, false,
6165 516 : COMPUTE_OTHER_STATS>(
6166 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6167 : nSampleCount, nValidCount);
6168 : }
6169 : }
6170 : else
6171 : {
6172 12891 : if (nMax < 255)
6173 : {
6174 : ComputeStatisticsByteNoNodata<false, true,
6175 9459 : COMPUTE_OTHER_STATS>(
6176 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6177 : nSampleCount, nValidCount);
6178 : }
6179 : else
6180 : {
6181 : ComputeStatisticsByteNoNodata<false, false,
6182 3432 : COMPUTE_OTHER_STATS>(
6183 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6184 : nSampleCount, nValidCount);
6185 : }
6186 : }
6187 : }
6188 12561 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6189 33 : (nBlockXSize % 32) == 0)
6190 : {
6191 6389 : for (int iY = 0; iY < nYCheck; iY++)
6192 : {
6193 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6194 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6195 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6196 33 : }
6197 : }
6198 : else
6199 : {
6200 13828 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6201 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6202 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6203 : }
6204 30352 : }
6205 : };
6206 :
6207 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6208 578 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6209 : GUIntBig i)
6210 : {
6211 578 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6212 578 : }
6213 :
6214 : // AVX2/SSE2 optimization for GUInt16 case
6215 : template <bool COMPUTE_OTHER_STATS>
6216 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6217 : {
6218 2153 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6219 : // assumed to be aligned on 128 bits
6220 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6221 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6222 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6223 : GUIntBig &nValidCount)
6224 : {
6225 2153 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6226 2153 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6227 : {
6228 1852 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6229 :
6230 1852 : GPtrDiff_t i = 0;
6231 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6232 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6233 : // Furthermore the shift is also needed to use madd_epi16
6234 1852 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6235 1852 : GDALm256i ymm_min = GDALmm256_load_si256(
6236 1852 : reinterpret_cast<const GDALm256i *>(pData + i));
6237 1852 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6238 1852 : GDALm256i ymm_max = ymm_min;
6239 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6240 1852 : ZERO256; // holds 4 uint64 sums
6241 :
6242 : // Make sure that sum can fit on uint32
6243 : // * 8 since we can hold 8 sums per vector register
6244 1852 : const int nMaxIterationsPerInnerLoop =
6245 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6246 1852 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6247 1852 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6248 1852 : nOuterLoops++;
6249 :
6250 1852 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6251 : [[maybe_unused]] const auto ymm_mask_16bits =
6252 1852 : GDALmm256_set1_epi32(0xFFFF);
6253 : [[maybe_unused]] const auto ymm_mask_32bits =
6254 1852 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6255 :
6256 1852 : GUIntBig nSumThis = 0;
6257 3728 : for (int k = 0; k < nOuterLoops; k++)
6258 : {
6259 1876 : const auto iMax =
6260 1876 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6261 :
6262 : [[maybe_unused]] GDALm256i ymm_sum =
6263 1876 : ZERO256; // holds 8 uint32 sums
6264 1112456 : for (; i + 15 < iMax; i += 16)
6265 : {
6266 1110580 : const GDALm256i ymm = GDALmm256_load_si256(
6267 1110580 : reinterpret_cast<const GDALm256i *>(pData + i));
6268 : const GDALm256i ymm_shifted =
6269 1110580 : GDALmm256_add_epi16(ymm, ymm_m32768);
6270 1110580 : if (bComputeMinMax)
6271 : {
6272 1092542 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6273 1092542 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6274 : }
6275 :
6276 : if constexpr (COMPUTE_OTHER_STATS)
6277 : {
6278 : // Note: the int32 range can overflow for (0-32768)^2 +
6279 : // (0-32768)^2 = 0x80000000, but as we know the result
6280 : // is positive, this is OK as we interpret is a uint32.
6281 : const GDALm256i ymm_square =
6282 243562 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6283 243562 : ymm_sumsquare = GDALmm256_add_epi64(
6284 : ymm_sumsquare,
6285 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6286 243562 : ymm_sumsquare = GDALmm256_add_epi64(
6287 : ymm_sumsquare,
6288 : GDALmm256_srli_epi64(ymm_square, 32));
6289 :
6290 : // Now compute the sums
6291 243562 : ymm_sum = GDALmm256_add_epi32(
6292 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6293 243562 : ymm_sum = GDALmm256_add_epi32(
6294 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6295 : }
6296 : }
6297 :
6298 : if constexpr (COMPUTE_OTHER_STATS)
6299 : {
6300 : GUInt32 anSum[8];
6301 578 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6302 : ymm_sum);
6303 578 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6304 578 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6305 578 : anSum[6] + anSum[7];
6306 : }
6307 : }
6308 :
6309 1852 : if (bComputeMinMax)
6310 : {
6311 : GUInt16 anMin[16];
6312 : GUInt16 anMax[16];
6313 :
6314 : // Unshift the result
6315 1770 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6316 1770 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6317 1770 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6318 : ymm_min);
6319 1770 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6320 : ymm_max);
6321 30090 : for (int j = 0; j < 16; j++)
6322 : {
6323 28320 : if (anMin[j] < nMin)
6324 394 : nMin = anMin[j];
6325 28320 : if (anMax[j] > nMax)
6326 571 : nMax = anMax[j];
6327 : }
6328 : }
6329 :
6330 : if constexpr (COMPUTE_OTHER_STATS)
6331 : {
6332 : GUIntBig anSumSquare[4];
6333 578 : GDALmm256_storeu_si256(
6334 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6335 578 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6336 : anSumSquare[3];
6337 :
6338 : // Unshift the sum of squares
6339 578 : UnshiftSumSquare(nSumSquare, nSumThis,
6340 : static_cast<GUIntBig>(i));
6341 :
6342 578 : nSum += nSumThis;
6343 :
6344 1022 : for (; i < nBlockPixels; i++)
6345 : {
6346 444 : const GUInt32 nValue = pData[i];
6347 444 : if (nValue < nMin)
6348 2 : nMin = nValue;
6349 444 : if (nValue > nMax)
6350 2 : nMax = nValue;
6351 444 : nSum += nValue;
6352 444 : nSumSquare +=
6353 444 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6354 444 : nValue;
6355 : }
6356 :
6357 578 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6358 578 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6359 1852 : }
6360 : }
6361 : else
6362 : {
6363 301 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6364 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6365 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6366 : }
6367 2153 : }
6368 : };
6369 :
6370 : #endif
6371 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6372 : // defined(_MSC_VER))
6373 :
6374 : /************************************************************************/
6375 : /* GetPixelValue() */
6376 : /************************************************************************/
6377 :
6378 15872500 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6379 : const void *pData, GPtrDiff_t iOffset,
6380 : const GDALNoDataValues &sNoDataValues,
6381 : bool &bValid)
6382 : {
6383 15872500 : bValid = true;
6384 15872500 : double dfValue = 0;
6385 15872500 : switch (eDataType)
6386 : {
6387 1400770 : case GDT_UInt8:
6388 : {
6389 1400770 : if (bSignedByte)
6390 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6391 : else
6392 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6393 1400770 : break;
6394 : }
6395 641 : case GDT_Int8:
6396 641 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6397 641 : break;
6398 200608 : case GDT_UInt16:
6399 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6400 200608 : break;
6401 54336 : case GDT_Int16:
6402 54336 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6403 54336 : break;
6404 10478 : case GDT_UInt32:
6405 10478 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6406 10478 : break;
6407 140220 : case GDT_Int32:
6408 140220 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6409 140220 : break;
6410 60 : case GDT_UInt64:
6411 60 : dfValue = static_cast<double>(
6412 60 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6413 60 : break;
6414 3268 : case GDT_Int64:
6415 3268 : dfValue = static_cast<double>(
6416 3268 : static_cast<const std::int64_t *>(pData)[iOffset]);
6417 3268 : break;
6418 40 : case GDT_Float16:
6419 : {
6420 : using namespace std;
6421 40 : const GFloat16 hfValue =
6422 40 : static_cast<const GFloat16 *>(pData)[iOffset];
6423 74 : if (isnan(hfValue) ||
6424 34 : (sNoDataValues.bGotFloat16NoDataValue &&
6425 28 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6426 : {
6427 6 : bValid = false;
6428 6 : return 0.0;
6429 : }
6430 34 : dfValue = hfValue;
6431 34 : return dfValue;
6432 : }
6433 13644000 : case GDT_Float32:
6434 : {
6435 13644000 : const float fValue = static_cast<const float *>(pData)[iOffset];
6436 27261100 : if (std::isnan(fValue) ||
6437 26886000 : (sNoDataValues.bGotFloatNoDataValue &&
6438 13268900 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6439 : {
6440 26883 : bValid = false;
6441 26883 : return 0.0;
6442 : }
6443 13617100 : dfValue = double(fValue);
6444 13617100 : return dfValue;
6445 : }
6446 400956 : case GDT_Float64:
6447 400956 : dfValue = static_cast<const double *>(pData)[iOffset];
6448 400956 : if (std::isnan(dfValue))
6449 : {
6450 6 : bValid = false;
6451 6 : return 0.0;
6452 : }
6453 400950 : break;
6454 2692 : case GDT_CInt16:
6455 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6456 2692 : break;
6457 2692 : case GDT_CInt32:
6458 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6459 2692 : break;
6460 0 : case GDT_CFloat16:
6461 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6462 0 : if (std::isnan(dfValue))
6463 : {
6464 0 : bValid = false;
6465 0 : return 0.0;
6466 : }
6467 0 : break;
6468 5812 : case GDT_CFloat32:
6469 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6470 5812 : if (std::isnan(dfValue))
6471 : {
6472 0 : bValid = false;
6473 0 : return 0.0;
6474 : }
6475 5812 : break;
6476 5892 : case GDT_CFloat64:
6477 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6478 5892 : if (std::isnan(dfValue))
6479 : {
6480 0 : bValid = false;
6481 0 : return 0.0;
6482 : }
6483 5892 : break;
6484 0 : case GDT_Unknown:
6485 : case GDT_TypeCount:
6486 0 : CPLAssert(false);
6487 : break;
6488 : }
6489 :
6490 2483820 : if (sNoDataValues.bGotNoDataValue &&
6491 255405 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6492 : {
6493 4222 : bValid = false;
6494 4222 : return 0.0;
6495 : }
6496 2224190 : return dfValue;
6497 : }
6498 :
6499 : /************************************************************************/
6500 : /* SetValidPercent() */
6501 : /************************************************************************/
6502 :
6503 : //! @cond Doxygen_Suppress
6504 : /**
6505 : * \brief Set percentage of valid (not nodata) pixels.
6506 : *
6507 : * Stores the percentage of valid pixels in the metadata item
6508 : * STATISTICS_VALID_PERCENT
6509 : *
6510 : * @param nSampleCount Number of sampled pixels.
6511 : *
6512 : * @param nValidCount Number of valid pixels.
6513 : */
6514 :
6515 599 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6516 : GUIntBig nValidCount)
6517 : {
6518 599 : if (nValidCount == 0)
6519 : {
6520 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6521 : }
6522 587 : else if (nValidCount == nSampleCount)
6523 : {
6524 494 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6525 : }
6526 : else /* nValidCount < nSampleCount */
6527 : {
6528 93 : char szValue[128] = {0};
6529 :
6530 : /* percentage is only an indicator: limit precision */
6531 93 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6532 93 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6533 :
6534 93 : if (EQUAL(szValue, "100"))
6535 : {
6536 : /* don't set 100 percent valid
6537 : * because some of the sampled pixels were nodata */
6538 4 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6539 : }
6540 : else
6541 : {
6542 89 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6543 : }
6544 : }
6545 599 : }
6546 :
6547 : //! @endcond
6548 :
6549 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6550 :
6551 : #ifdef __AVX2__
6552 :
6553 : #define set1_ps _mm256_set1_ps
6554 : #define loadu_ps _mm256_loadu_ps
6555 : #define or_ps _mm256_or_ps
6556 : #define min_ps _mm256_min_ps
6557 : #define max_ps _mm256_max_ps
6558 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6559 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6560 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6561 : #define movemask_ps _mm256_movemask_ps
6562 : #define storeu_ps _mm256_storeu_ps
6563 : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6564 : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6565 :
6566 : #define unpacklo_ps _mm256_unpacklo_ps
6567 : #define castps_pd _mm256_castps_pd
6568 :
6569 : inline __m256 dup_hi_ps(__m256 x)
6570 : {
6571 : const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6572 : return _mm256_permutevar8x32_ps(x, idx);
6573 : }
6574 :
6575 : #define setzero_pd _mm256_setzero_pd
6576 : #define set1_pd _mm256_set1_pd
6577 : #define loadu_pd _mm256_loadu_pd
6578 : #define or_pd _mm256_or_pd
6579 : #define min_pd _mm256_min_pd
6580 : #define max_pd _mm256_max_pd
6581 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6582 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6583 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6584 : #define movemask_pd _mm256_movemask_pd
6585 : #define add_pd _mm256_add_pd
6586 : #define sub_pd _mm256_sub_pd
6587 : #define mul_pd _mm256_mul_pd
6588 : #define div_pd _mm256_div_pd
6589 : #define storeu_pd _mm256_storeu_pd
6590 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6591 : #define blendv_pd _mm256_blendv_pd
6592 : #ifdef __FMA__
6593 : #define fmadd_pd _mm256_fmadd_pd
6594 : #else
6595 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6596 : #endif
6597 :
6598 : #else
6599 :
6600 : #define set1_ps _mm_set1_ps
6601 : #define loadu_ps _mm_loadu_ps
6602 : #define or_ps _mm_or_ps
6603 : #define min_ps _mm_min_ps
6604 : #define max_ps _mm_max_ps
6605 : #define cmpeq_ps _mm_cmpeq_ps
6606 : #define cmpneq_ps _mm_cmpneq_ps
6607 : #define cmpunord_ps _mm_cmpunord_ps
6608 : #define movemask_ps _mm_movemask_ps
6609 : #define storeu_ps _mm_storeu_ps
6610 : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6611 : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6612 : #define unpacklo_ps _mm_unpacklo_ps
6613 : #define castps_pd _mm_castps_pd
6614 : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6615 :
6616 : #define setzero_pd _mm_setzero_pd
6617 : #define set1_pd _mm_set1_pd
6618 : #define loadu_pd _mm_loadu_pd
6619 : #define or_pd _mm_or_pd
6620 : #define min_pd _mm_min_pd
6621 : #define max_pd _mm_max_pd
6622 : #define cmpeq_pd _mm_cmpeq_pd
6623 : #define cmpneq_pd _mm_cmpneq_pd
6624 : #define cmpunord_pd _mm_cmpunord_pd
6625 : #define movemask_pd _mm_movemask_pd
6626 : #define add_pd _mm_add_pd
6627 : #define sub_pd _mm_sub_pd
6628 : #define mul_pd _mm_mul_pd
6629 : #define div_pd _mm_div_pd
6630 : #define storeu_pd _mm_storeu_pd
6631 : #define cvtsd_f64 _mm_cvtsd_f64
6632 : #ifdef __FMA__
6633 : #define fmadd_pd _mm_fmadd_pd
6634 : #else
6635 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6636 : #endif
6637 :
6638 4299340 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6639 : {
6640 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6641 : return _mm_blendv_pd(a, b, mask);
6642 : #else
6643 12898000 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6644 : #endif
6645 : }
6646 : #endif
6647 :
6648 : #define dup_lo_ps(x) unpacklo_ps((x), (x))
6649 :
6650 : /************************************************************************/
6651 : /* ComputeStatisticsFloat32_SSE2() */
6652 : /************************************************************************/
6653 :
6654 : template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6655 : #if defined(__GNUC__)
6656 : __attribute__((noinline))
6657 : #endif
6658 8326 : static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
6659 : [[maybe_unused]] float fNoDataValue,
6660 : int iX, int nCount, float &fMin,
6661 : float &fMax, double &dfBlockMean,
6662 : double &dfBlockM2,
6663 : double &dfBlockValidCount)
6664 : {
6665 8326 : auto vValidCount = setzero_pd();
6666 8326 : const auto vOne = set1_pd(1);
6667 8326 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6668 :
6669 8326 : auto vMin = set1_ps(fMin);
6670 16652 : auto vMax = set1_ps(fMax);
6671 :
6672 8326 : auto vMean_lo = setzero_pd();
6673 8326 : auto vM2_lo = setzero_pd();
6674 :
6675 8326 : auto vMean_hi = setzero_pd();
6676 8326 : auto vM2_hi = setzero_pd();
6677 :
6678 8326 : constexpr int VALS_PER_LOOP =
6679 : static_cast<int>(sizeof(vOne) / sizeof(float));
6680 1258075 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6681 : {
6682 2499510 : const auto vValues = loadu_ps(pafData + iX);
6683 :
6684 : if constexpr (HAS_NAN)
6685 : {
6686 1236117 : auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6687 : if constexpr (HAS_NODATA)
6688 : {
6689 : isNaNOrNoData =
6690 0 : or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6691 : }
6692 1236117 : if (movemask_ps(isNaNOrNoData))
6693 : {
6694 1 : break;
6695 : }
6696 : }
6697 : else if constexpr (HAS_NODATA)
6698 : {
6699 0 : if (movemask_ps(cmpeq_ps(vValues, vNoData)))
6700 : {
6701 0 : break;
6702 : }
6703 : }
6704 :
6705 1249754 : vMin = min_ps(vMin, vValues);
6706 1249754 : vMax = max_ps(vMax, vValues);
6707 :
6708 1249754 : const auto vValues_lo = cvtps_lo_pd(vValues);
6709 2499508 : const auto vValues_hi = cvtps_hi_pd(vValues);
6710 1249754 : [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6711 :
6712 1249754 : vValidCount = add_pd(vValidCount, vOne);
6713 1249754 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6714 :
6715 1249754 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6716 2298362 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6717 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6718 : {
6719 : const auto vMinNotSameAsMax_lo =
6720 1048608 : castps_pd(dup_lo_ps(vMinNotSameAsMax));
6721 1048608 : vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6722 : const auto vNewM2_lo =
6723 2097216 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6724 1048608 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6725 : }
6726 : else
6727 : {
6728 201146 : vMean_lo = vNewMean_lo;
6729 603438 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6730 : }
6731 :
6732 1249754 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6733 2298362 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6734 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6735 : {
6736 : const auto vMinNotSameAsMax_hi =
6737 1048608 : castps_pd(dup_hi_ps(vMinNotSameAsMax));
6738 1048608 : vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6739 : const auto vNewM2_hi =
6740 2097216 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6741 1048608 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6742 : }
6743 : else
6744 : {
6745 201146 : vMean_hi = vNewMean_hi;
6746 603438 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6747 : }
6748 : }
6749 8326 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6750 8326 : if (dfValidVectorCount > 0)
6751 : {
6752 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6753 : storeu_ps(afMin, vMin);
6754 : storeu_ps(afMax, vMax);
6755 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6756 : {
6757 31964 : fMin = std::min(fMin, afMin[i]);
6758 31964 : fMax = std::max(fMax, afMax[i]);
6759 : }
6760 :
6761 : double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6762 : storeu_pd(adfMean, vMean_lo);
6763 : storeu_pd(adfM2, vM2_lo);
6764 7991 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6765 7991 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6766 39955 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6767 : {
6768 31964 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6769 31964 : dfBlockM2 += adfM2[i];
6770 31964 : if (adfMean[i] != dfBlockMean)
6771 : {
6772 13172 : const double dfDelta = adfMean[i] - dfBlockMean;
6773 13172 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6774 13172 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6775 13172 : dfValidVectorCount / dfNewValidCount;
6776 : }
6777 31964 : dfBlockValidCount = dfNewValidCount;
6778 : }
6779 : }
6780 :
6781 8326 : return iX;
6782 : }
6783 :
6784 : /************************************************************************/
6785 : /* ComputeStatisticsFloat64_SSE2() */
6786 : /************************************************************************/
6787 :
6788 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6789 : #if defined(__GNUC__)
6790 : __attribute__((noinline))
6791 : #endif
6792 2367 : static int ComputeStatisticsFloat64_SSE2(const double *padfData,
6793 : [[maybe_unused]] double dfNoDataValue,
6794 : int iX, int nCount, double &dfMin,
6795 : double &dfMax, double &dfBlockMean,
6796 : double &dfBlockM2,
6797 : double &dfBlockValidCount)
6798 : {
6799 2367 : auto vValidCount = setzero_pd();
6800 2367 : const auto vOne = set1_pd(1);
6801 2367 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6802 :
6803 2367 : auto vMin_lo = set1_pd(dfMin);
6804 4734 : auto vMax_lo = set1_pd(dfMax);
6805 2367 : auto vMean_lo = setzero_pd();
6806 2367 : auto vM2_lo = setzero_pd();
6807 :
6808 2367 : auto vMin_hi = vMin_lo;
6809 2367 : auto vMax_hi = vMax_lo;
6810 2367 : auto vMean_hi = setzero_pd();
6811 2367 : auto vM2_hi = setzero_pd();
6812 :
6813 2367 : constexpr int VALS_PER_LOOP =
6814 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6815 107199 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6816 : {
6817 104875 : const auto vValues_lo = loadu_pd(padfData + iX);
6818 209750 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6819 : // Check if there's at least one NaN in both vectors
6820 104875 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6821 : if constexpr (HAS_NODATA)
6822 : {
6823 : isNaNOrNoData =
6824 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6825 : cmpeq_pd(vValues_hi, vNoData)));
6826 : }
6827 104875 : if (movemask_pd(isNaNOrNoData))
6828 : {
6829 43 : break;
6830 : }
6831 :
6832 104832 : vValidCount = add_pd(vValidCount, vOne);
6833 104832 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6834 :
6835 104832 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6836 104832 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6837 104832 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6838 131060 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6839 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6840 : {
6841 26228 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6842 26228 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6843 : const auto vNewM2_lo =
6844 52456 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6845 26228 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6846 : }
6847 : else
6848 : {
6849 78604 : vMean_lo = vNewMean_lo;
6850 235812 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6851 : }
6852 :
6853 104832 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6854 104832 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6855 104832 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6856 131060 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6857 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6858 : {
6859 26228 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6860 26228 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6861 : const auto vNewM2_hi =
6862 52456 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6863 26228 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6864 : }
6865 : else
6866 : {
6867 78604 : vMean_hi = vNewMean_hi;
6868 235812 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6869 : }
6870 : }
6871 2367 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6872 2367 : if (dfValidVectorCount > 0)
6873 : {
6874 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6875 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6876 : storeu_pd(adfMin, vMin_lo);
6877 : storeu_pd(adfMax, vMax_lo);
6878 : storeu_pd(adfMean, vMean_lo);
6879 : storeu_pd(adfM2, vM2_lo);
6880 1801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6881 1801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6882 1801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6883 1801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6884 :
6885 9005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6886 : {
6887 7204 : dfMin = std::min(dfMin, adfMin[i]);
6888 7204 : dfMax = std::max(dfMax, adfMax[i]);
6889 7204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6890 7204 : dfBlockM2 += adfM2[i];
6891 7204 : if (adfMean[i] != dfBlockMean)
6892 : {
6893 5871 : const double dfDelta = adfMean[i] - dfBlockMean;
6894 5871 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6895 5871 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6896 5871 : dfValidVectorCount / dfNewValidCount;
6897 : }
6898 7204 : dfBlockValidCount = dfNewValidCount;
6899 : }
6900 : }
6901 :
6902 2367 : return iX;
6903 : }
6904 :
6905 : #endif
6906 :
6907 : /************************************************************************/
6908 : /* ComputeBlockStatisticsFloat32() */
6909 : /************************************************************************/
6910 :
6911 : template <bool HAS_NAN, bool HAS_NODATA>
6912 4729 : static void ComputeBlockStatisticsFloat32(
6913 : const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
6914 : const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
6915 : float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
6916 : double &dfBlockValidCountInOut)
6917 : {
6918 4729 : float fMin = fMinInOut;
6919 4729 : float fMax = fMaxInOut;
6920 4729 : double dfBlockMean = dfBlockMeanInOut;
6921 4729 : double dfBlockM2 = dfBlockM2InOut;
6922 4729 : double dfBlockValidCount = dfBlockValidCountInOut;
6923 :
6924 13055 : for (int iY = 0; iY < nYCheck; iY++)
6925 : {
6926 8326 : const int iOffset = iY * nBlockXSize;
6927 8326 : if (dfBlockValidCount > 0 && fMin != fMax)
6928 : {
6929 3470 : int iX = 0;
6930 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6931 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6932 : /* bCheckMinEqMax = */ false,
6933 3470 : HAS_NODATA>(
6934 3470 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6935 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6936 : #endif
6937 4011 : for (; iX < nXCheck; iX++)
6938 : {
6939 541 : const float fValue = pafSrcData[iOffset + iX];
6940 : if constexpr (HAS_NAN)
6941 : {
6942 535 : if (std::isnan(fValue))
6943 13 : continue;
6944 : }
6945 : if constexpr (HAS_NODATA)
6946 : {
6947 6 : if (fValue == sNoDataValues.fNoDataValue)
6948 1 : continue;
6949 : }
6950 527 : fMin = std::min(fMin, fValue);
6951 527 : fMax = std::max(fMax, fValue);
6952 527 : dfBlockValidCount += 1.0;
6953 527 : const double dfValue = static_cast<double>(fValue);
6954 527 : const double dfDelta = dfValue - dfBlockMean;
6955 527 : dfBlockMean += dfDelta / dfBlockValidCount;
6956 527 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
6957 3470 : }
6958 : }
6959 : else
6960 : {
6961 4856 : int iX = 0;
6962 4856 : if (dfBlockValidCount == 0)
6963 : {
6964 4730 : while (iX < nXCheck)
6965 : {
6966 4730 : const float fValue = pafSrcData[iOffset + iX];
6967 4730 : ++iX;
6968 : if constexpr (HAS_NAN)
6969 : {
6970 2338 : if (std::isnan(fValue))
6971 0 : continue;
6972 : }
6973 : if constexpr (HAS_NODATA)
6974 : {
6975 7 : if (fValue == sNoDataValues.fNoDataValue)
6976 1 : continue;
6977 : }
6978 4729 : fMin = std::min(fMin, fValue);
6979 4729 : fMax = std::max(fMax, fValue);
6980 4729 : dfBlockValidCount = 1;
6981 4729 : dfBlockMean = static_cast<double>(fValue);
6982 4729 : break;
6983 : }
6984 : }
6985 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
6986 : iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
6987 : /* bCheckMinEqMax = */ true,
6988 4856 : HAS_NODATA>(
6989 4856 : pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
6990 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
6991 : #endif
6992 14986 : for (; iX < nXCheck; iX++)
6993 : {
6994 10130 : const float fValue = pafSrcData[iOffset + iX];
6995 : if constexpr (HAS_NAN)
6996 : {
6997 6873 : if (std::isnan(fValue))
6998 5 : continue;
6999 : }
7000 : if constexpr (HAS_NODATA)
7001 : {
7002 9 : if (fValue == sNoDataValues.fNoDataValue)
7003 2 : continue;
7004 : }
7005 10123 : fMin = std::min(fMin, fValue);
7006 10123 : fMax = std::max(fMax, fValue);
7007 10123 : dfBlockValidCount += 1.0;
7008 10123 : if (fMin != fMax)
7009 : {
7010 3258 : const double dfValue = static_cast<double>(fValue);
7011 3258 : const double dfDelta = dfValue - dfBlockMean;
7012 3258 : dfBlockMean += dfDelta / dfBlockValidCount;
7013 3258 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7014 : }
7015 : }
7016 : }
7017 : }
7018 :
7019 4729 : fMinInOut = fMin;
7020 4729 : fMaxInOut = fMax;
7021 4729 : dfBlockMeanInOut = dfBlockMean;
7022 4729 : dfBlockM2InOut = dfBlockM2;
7023 4729 : dfBlockValidCountInOut = dfBlockValidCount;
7024 4729 : }
7025 :
7026 : /************************************************************************/
7027 : /* StatisticsTaskFloat32 */
7028 : /************************************************************************/
7029 :
7030 : namespace
7031 : {
7032 : struct StatisticsTaskFloat32
7033 : {
7034 : double dfBlockMean = 0;
7035 : double dfBlockM2 = 0;
7036 : double dfBlockValidCount = 0;
7037 : GDALDataType eDataType = GDT_Unknown;
7038 : bool bHasNoData = false;
7039 : GDALNoDataValues *psNoDataValues = nullptr;
7040 : const float *pafSrcData = nullptr;
7041 : float fMin = std::numeric_limits<float>::infinity();
7042 : float fMax = -std::numeric_limits<float>::infinity();
7043 : int nChunkXSize = 0;
7044 : int nXCheck = 0;
7045 : int nYCheck = 0;
7046 :
7047 4729 : void Perform()
7048 : {
7049 4729 : if (GDALDataTypeIsInteger(eDataType))
7050 : {
7051 2391 : if (bHasNoData)
7052 : {
7053 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7054 6 : /* HAS_NODATA = */ true>(
7055 6 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7056 6 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7057 : }
7058 : else
7059 : {
7060 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
7061 2385 : /* HAS_NODATA = */ false>(
7062 2385 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7063 2385 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7064 : }
7065 : }
7066 : else
7067 : {
7068 2338 : if (bHasNoData)
7069 : {
7070 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7071 0 : /* HAS_NODATA = */ true>(
7072 0 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7073 0 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7074 : }
7075 : else
7076 : {
7077 : ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
7078 2338 : /* HAS_NODATA = */ false>(
7079 2338 : pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
7080 2338 : fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
7081 : }
7082 : }
7083 4729 : }
7084 : };
7085 : } // namespace
7086 :
7087 : /************************************************************************/
7088 : /* ComputeStatistics() */
7089 : /************************************************************************/
7090 :
7091 : /**
7092 : * \brief Compute image statistics.
7093 : *
7094 : * Returns the minimum, maximum, mean and standard deviation of all
7095 : * pixel values in this band. If approximate statistics are sufficient,
7096 : * the bApproxOK flag can be set to true in which case overviews, or a
7097 : * subset of image tiles may be used in computing the statistics.
7098 : *
7099 : * Once computed, the statistics will generally be "set" back on the
7100 : * raster band using SetStatistics().
7101 : *
7102 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
7103 : *
7104 : * This method is the same as the C function GDALComputeRasterStatistics().
7105 : *
7106 : * @param bApproxOK If TRUE statistics may be computed based on overviews
7107 : * or a subset of all tiles.
7108 : *
7109 : * @param pdfMin Location into which to load image minimum (may be NULL).
7110 : *
7111 : * @param pdfMax Location into which to load image maximum (may be NULL).-
7112 : *
7113 : * @param pdfMean Location into which to load image mean (may be NULL).
7114 : *
7115 : * @param pdfStdDev Location into which to load image standard deviation
7116 : * (may be NULL).
7117 : *
7118 : * @param pfnProgress a function to call to report progress, or NULL.
7119 : *
7120 : * @param pProgressData application data to pass to the progress function.
7121 : *
7122 : * @return CE_None on success, or CE_Failure if an error occurs or processing
7123 : * is terminated by the user.
7124 : */
7125 :
7126 581 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
7127 : double *pdfMax, double *pdfMean,
7128 : double *pdfStdDev,
7129 : GDALProgressFunc pfnProgress,
7130 : void *pProgressData)
7131 :
7132 : {
7133 581 : if (pfnProgress == nullptr)
7134 252 : pfnProgress = GDALDummyProgress;
7135 :
7136 : /* -------------------------------------------------------------------- */
7137 : /* If we have overview bands, use them for statistics. */
7138 : /* -------------------------------------------------------------------- */
7139 581 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7140 : {
7141 : GDALRasterBand *poBand =
7142 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7143 :
7144 3 : if (poBand != this)
7145 : {
7146 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
7147 : pdfMean, pdfStdDev,
7148 3 : pfnProgress, pProgressData);
7149 3 : if (eErr == CE_None)
7150 : {
7151 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
7152 : {
7153 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7154 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
7155 : }
7156 :
7157 : /* transfer metadata from overview band to this */
7158 : const char *pszPercentValid =
7159 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
7160 :
7161 3 : if (pszPercentValid != nullptr)
7162 : {
7163 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
7164 3 : pszPercentValid);
7165 : }
7166 : }
7167 3 : return eErr;
7168 : }
7169 : }
7170 :
7171 578 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
7172 : {
7173 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7174 0 : return CE_Failure;
7175 : }
7176 :
7177 : /* -------------------------------------------------------------------- */
7178 : /* Read actual data and compute statistics. */
7179 : /* -------------------------------------------------------------------- */
7180 : // Using Welford algorithm:
7181 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
7182 : // to compute standard deviation in a more numerically robust way than
7183 : // the difference of the sum of square values with the square of the sum.
7184 : // dfMean and dfM2 are updated at each sample.
7185 : // dfM2 is the sum of square of differences to the current mean.
7186 578 : double dfMin = std::numeric_limits<double>::infinity();
7187 578 : double dfMax = -std::numeric_limits<double>::infinity();
7188 578 : double dfMean = 0.0;
7189 578 : double dfM2 = 0.0;
7190 :
7191 : GDALRasterIOExtraArg sExtraArg;
7192 578 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7193 :
7194 578 : GDALNoDataValues sNoDataValues(this, eDataType);
7195 578 : GDALRasterBand *poMaskBand = nullptr;
7196 578 : if (!sNoDataValues.bGotNoDataValue)
7197 : {
7198 507 : const int l_nMaskFlags = GetMaskFlags();
7199 565 : if (l_nMaskFlags != GMF_ALL_VALID &&
7200 58 : GetColorInterpretation() != GCI_AlphaBand)
7201 : {
7202 58 : poMaskBand = GetMaskBand();
7203 : }
7204 : }
7205 :
7206 578 : bool bSignedByte = false;
7207 578 : if (eDataType == GDT_UInt8)
7208 : {
7209 221 : EnablePixelTypeSignedByteWarning(false);
7210 : const char *pszPixelType =
7211 221 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7212 221 : EnablePixelTypeSignedByteWarning(true);
7213 221 : bSignedByte =
7214 221 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7215 : }
7216 :
7217 578 : GUIntBig nSampleCount = 0;
7218 578 : GUIntBig nValidCount = 0;
7219 :
7220 578 : if (bApproxOK && HasArbitraryOverviews())
7221 : {
7222 : /* --------------------------------------------------------------------
7223 : */
7224 : /* Figure out how much the image should be reduced to get an */
7225 : /* approximate value. */
7226 : /* --------------------------------------------------------------------
7227 : */
7228 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7229 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7230 :
7231 0 : int nXReduced = nRasterXSize;
7232 0 : int nYReduced = nRasterYSize;
7233 0 : if (dfReduction > 1.0)
7234 : {
7235 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7236 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7237 :
7238 : // Catch the case of huge resizing ratios here
7239 0 : if (nXReduced == 0)
7240 0 : nXReduced = 1;
7241 0 : if (nYReduced == 0)
7242 0 : nYReduced = 1;
7243 : }
7244 :
7245 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7246 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7247 :
7248 : const CPLErr eErr =
7249 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7250 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7251 0 : if (eErr != CE_None)
7252 : {
7253 0 : CPLFree(pData);
7254 0 : return eErr;
7255 : }
7256 :
7257 0 : GByte *pabyMaskData = nullptr;
7258 0 : if (poMaskBand)
7259 : {
7260 : pabyMaskData =
7261 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7262 0 : if (!pabyMaskData)
7263 : {
7264 0 : CPLFree(pData);
7265 0 : return CE_Failure;
7266 : }
7267 :
7268 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7269 : pabyMaskData, nXReduced, nYReduced,
7270 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
7271 : {
7272 0 : CPLFree(pData);
7273 0 : CPLFree(pabyMaskData);
7274 0 : return CE_Failure;
7275 : }
7276 : }
7277 :
7278 : /* this isn't the fastest way to do this, but is easier for now */
7279 0 : for (int iY = 0; iY < nYReduced; iY++)
7280 : {
7281 0 : for (int iX = 0; iX < nXReduced; iX++)
7282 : {
7283 0 : const int iOffset = iX + iY * nXReduced;
7284 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7285 0 : continue;
7286 :
7287 0 : bool bValid = true;
7288 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7289 0 : iOffset, sNoDataValues, bValid);
7290 0 : if (!bValid)
7291 0 : continue;
7292 :
7293 0 : dfMin = std::min(dfMin, dfValue);
7294 0 : dfMax = std::max(dfMax, dfValue);
7295 :
7296 0 : nValidCount++;
7297 0 : if (dfMin == dfMax)
7298 : {
7299 0 : if (nValidCount == 1)
7300 0 : dfMean = dfMin;
7301 : }
7302 : else
7303 : {
7304 0 : const double dfDelta = dfValue - dfMean;
7305 0 : dfMean += dfDelta / nValidCount;
7306 0 : dfM2 += dfDelta * (dfValue - dfMean);
7307 : }
7308 : }
7309 : }
7310 :
7311 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7312 :
7313 0 : CPLFree(pData);
7314 0 : CPLFree(pabyMaskData);
7315 : }
7316 :
7317 : else // No arbitrary overviews.
7318 : {
7319 578 : if (!InitBlockInfo())
7320 259 : return CE_Failure;
7321 :
7322 : /* --------------------------------------------------------------------
7323 : */
7324 : /* Figure out the ratio of blocks we will read to get an */
7325 : /* approximate value. */
7326 : /* --------------------------------------------------------------------
7327 : */
7328 578 : int nSampleRate = 1;
7329 578 : if (bApproxOK)
7330 : {
7331 43 : nSampleRate = static_cast<int>(std::max(
7332 86 : 1.0,
7333 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7334 : // We want to avoid probing only the first column of blocks for
7335 : // a square shaped raster, because it is not unlikely that it may
7336 : // be padding only (#6378)
7337 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7338 1 : nSampleRate += 1;
7339 : }
7340 578 : if (nSampleRate == 1)
7341 544 : bApproxOK = false;
7342 :
7343 : // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7344 : // for each block, and possibly for the whole raster.
7345 578 : if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7346 316 : eDataType == GDT_UInt16))
7347 : {
7348 : // We can do integer computation on the whole raster in the Byte case
7349 : // only if the number of pixels explored is lower than
7350 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7351 : // Should be 99.99999% of cases.
7352 : // For GUInt16, this limits to raster of 4 giga pixels
7353 :
7354 : const bool bIntegerStats =
7355 463 : ((eDataType == GDT_UInt8 &&
7356 204 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7357 204 : nSampleRate <
7358 204 : GUINTBIG_MAX / (255U * 255U) /
7359 204 : (static_cast<GUInt64>(nBlockXSize) *
7360 204 : static_cast<GUInt64>(nBlockYSize))) ||
7361 55 : (eDataType == GDT_UInt16 &&
7362 55 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7363 55 : nSampleRate <
7364 55 : GUINTBIG_MAX / (65535U * 65535U) /
7365 55 : (static_cast<GUInt64>(nBlockXSize) *
7366 573 : static_cast<GUInt64>(nBlockYSize)))) &&
7367 : // Can be set to NO for easier debugging of the !bIntegerStats
7368 : // case which requires huge rasters to trigger
7369 259 : CPLTestBool(
7370 259 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7371 :
7372 259 : const GUInt32 nMaxValueType =
7373 259 : (eDataType == GDT_UInt8) ? 255 : 65535;
7374 259 : GUInt32 nMin = nMaxValueType;
7375 259 : GUInt32 nMax = 0;
7376 259 : GUIntBig nSum = 0;
7377 259 : GUIntBig nSumSquare = 0;
7378 : // If no valid nodata, map to invalid value (256 for Byte)
7379 259 : const GUInt32 nNoDataValue =
7380 294 : (sNoDataValues.bGotNoDataValue &&
7381 35 : sNoDataValues.dfNoDataValue >= 0 &&
7382 35 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7383 35 : fabs(sNoDataValues.dfNoDataValue -
7384 35 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7385 : 1e-10)) < 1e-10)
7386 294 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7387 : : nMaxValueType + 1;
7388 :
7389 259 : int nChunkXSize = nBlockXSize;
7390 259 : int nChunkYSize = nBlockYSize;
7391 259 : int nChunksPerRow = nBlocksPerRow;
7392 259 : int nChunksPerCol = nBlocksPerColumn;
7393 :
7394 259 : int nThreads = 1;
7395 259 : if (nChunkYSize > 1)
7396 : {
7397 115 : nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7398 : /* bDefaultToAllCPUs = */ false);
7399 : }
7400 :
7401 259 : int nNewChunkXSize = nChunkXSize;
7402 259 : const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
7403 267 : if (!bApproxOK && nThreads > 1 &&
7404 8 : MayMultiBlockReadingBeMultiThreaded())
7405 : {
7406 4 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7407 4 : const size_t nChunkPixels =
7408 4 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7409 8 : if (nRAMAmount > 0 &&
7410 : nChunkPixels <=
7411 4 : std::numeric_limits<size_t>::max() / nDTSize)
7412 : {
7413 4 : const size_t nBlockSize = nDTSize * nChunkPixels;
7414 4 : const int64_t nBlockCount = nRAMAmount / nBlockSize;
7415 4 : if (nBlockCount >= 2)
7416 : {
7417 4 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7418 12 : nChunkXSize * std::min<int64_t>(
7419 : nBlockCount,
7420 8 : (std::numeric_limits<int>::max() -
7421 8 : ALIGNMENT_AVX2_OPTIM) /
7422 4 : nChunkPixels),
7423 8 : nRasterXSize));
7424 :
7425 4 : CPLAssert(nChunkXSize <
7426 : std::numeric_limits<int>::max() /
7427 : nChunkYSize);
7428 : }
7429 : }
7430 : }
7431 :
7432 259 : std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
7433 259 : GByte *pabyTemp = nullptr;
7434 259 : if (nNewChunkXSize != nBlockXSize)
7435 : {
7436 4 : pabyTempUnaligned.reset(static_cast<GByte *>(
7437 4 : VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
7438 : ALIGNMENT_AVX2_OPTIM)));
7439 4 : if (pabyTempUnaligned)
7440 : {
7441 4 : pabyTemp = reinterpret_cast<GByte *>(
7442 4 : reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
7443 : (ALIGNMENT_AVX2_OPTIM -
7444 4 : (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
7445 : ALIGNMENT_AVX2_OPTIM)));
7446 4 : nChunkXSize = nNewChunkXSize;
7447 : nChunksPerRow =
7448 4 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7449 : }
7450 : }
7451 :
7452 259 : for (GIntBig iSampleBlock = 0;
7453 13126 : iSampleBlock <
7454 13126 : static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7455 12867 : iSampleBlock += nSampleRate)
7456 : {
7457 12871 : const int iYBlock =
7458 12871 : static_cast<int>(iSampleBlock / nChunksPerRow);
7459 12871 : const int iXBlock =
7460 12871 : static_cast<int>(iSampleBlock % nChunksPerRow);
7461 :
7462 : const int nXCheck =
7463 12871 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7464 : const int nYCheck =
7465 12871 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7466 :
7467 12871 : GDALRasterBlock *poBlock = nullptr;
7468 12871 : if (pabyTemp)
7469 : {
7470 12 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7471 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7472 : pabyTemp, nXCheck, nYCheck, eDataType, 0,
7473 6 : static_cast<GSpacing>(nChunkXSize) * nDTSize,
7474 6 : nullptr) != CE_None)
7475 : {
7476 4 : return CE_Failure;
7477 : }
7478 : }
7479 : else
7480 : {
7481 12865 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7482 12865 : if (poBlock == nullptr)
7483 : {
7484 2 : return CE_Failure;
7485 : }
7486 : }
7487 :
7488 : const void *const pData =
7489 12867 : poBlock ? poBlock->GetDataRef() : pabyTemp;
7490 :
7491 12867 : GUIntBig nBlockSum = 0;
7492 12867 : GUIntBig nBlockSumSquare = 0;
7493 12867 : GUIntBig nBlockSampleCount = 0;
7494 12867 : GUIntBig nBlockValidCount = 0;
7495 12867 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7496 12867 : GUIntBig &nBlockSumSquareRef =
7497 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7498 12867 : GUIntBig &nBlockSampleCountRef =
7499 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7500 12867 : GUIntBig &nBlockValidCountRef =
7501 : bIntegerStats ? nValidCount : nBlockValidCount;
7502 :
7503 12867 : if (eDataType == GDT_UInt8)
7504 : {
7505 : ComputeStatisticsInternal<
7506 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7507 12171 : f(nXCheck, nChunkXSize, nYCheck,
7508 : static_cast<const GByte *>(pData),
7509 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7510 : nMax, nBlockSumRef, nBlockSumSquareRef,
7511 : nBlockSampleCountRef, nBlockValidCountRef);
7512 : }
7513 : else
7514 : {
7515 : ComputeStatisticsInternal<
7516 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7517 696 : f(nXCheck, nChunkXSize, nYCheck,
7518 : static_cast<const GUInt16 *>(pData),
7519 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7520 : nMax, nBlockSumRef, nBlockSumSquareRef,
7521 : nBlockSampleCountRef, nBlockValidCountRef);
7522 : }
7523 :
7524 12867 : if (poBlock)
7525 12863 : poBlock->DropLock();
7526 :
7527 12867 : if (!bIntegerStats)
7528 : {
7529 169 : nSampleCount += nBlockSampleCount;
7530 169 : if (nBlockValidCount)
7531 : {
7532 : // Update the global mean and M2 (the difference of the
7533 : // square to the mean) from the values of the block
7534 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7535 169 : const double dfBlockValidCount =
7536 169 : static_cast<double>(nBlockValidCount);
7537 169 : const double dfBlockMean =
7538 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7539 : const double dfBlockM2 =
7540 169 : static_cast<double>(
7541 169 : GDALUInt128::Mul(nBlockSumSquare,
7542 169 : nBlockValidCount) -
7543 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7544 169 : dfBlockValidCount;
7545 169 : const double dfDelta = dfBlockMean - dfMean;
7546 169 : const auto nNewValidCount =
7547 169 : nValidCount + nBlockValidCount;
7548 169 : const double dfNewValidCount =
7549 : static_cast<double>(nNewValidCount);
7550 169 : dfMean +=
7551 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7552 169 : dfM2 +=
7553 169 : dfBlockM2 + dfDelta * dfDelta *
7554 169 : static_cast<double>(nValidCount) *
7555 169 : dfBlockValidCount / dfNewValidCount;
7556 169 : nValidCount = nNewValidCount;
7557 : }
7558 : }
7559 :
7560 12867 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7561 12867 : (static_cast<double>(nChunksPerRow) *
7562 : nChunksPerCol),
7563 : "Compute Statistics", pProgressData))
7564 : {
7565 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7566 : "User terminated");
7567 0 : return CE_Failure;
7568 : }
7569 : }
7570 :
7571 255 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7572 : {
7573 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7574 0 : return CE_Failure;
7575 : }
7576 :
7577 255 : double dfStdDev = 0;
7578 255 : if (bIntegerStats)
7579 : {
7580 231 : if (nValidCount)
7581 222 : dfMean = static_cast<double>(nSum) / nValidCount;
7582 :
7583 : // To avoid potential precision issues when doing the difference,
7584 : // we need to do that computation on 128 bit rather than casting
7585 : // to double
7586 : const GDALUInt128 nTmpForStdDev(
7587 231 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7588 462 : GDALUInt128::Mul(nSum, nSum));
7589 231 : dfStdDev =
7590 231 : nValidCount > 0
7591 231 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7592 : : 0.0;
7593 : }
7594 24 : else if (nValidCount > 0)
7595 : {
7596 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7597 : }
7598 :
7599 : /// Save computed information
7600 255 : if (nValidCount > 0)
7601 : {
7602 246 : if (bApproxOK)
7603 : {
7604 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7605 : }
7606 222 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7607 : {
7608 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7609 : }
7610 246 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7611 : }
7612 :
7613 255 : SetValidPercent(nSampleCount, nValidCount);
7614 :
7615 : /* --------------------------------------------------------------------
7616 : */
7617 : /* Record results. */
7618 : /* --------------------------------------------------------------------
7619 : */
7620 255 : if (pdfMin != nullptr)
7621 252 : *pdfMin = nValidCount ? nMin : 0;
7622 255 : if (pdfMax != nullptr)
7623 252 : *pdfMax = nValidCount ? nMax : 0;
7624 :
7625 255 : if (pdfMean != nullptr)
7626 248 : *pdfMean = dfMean;
7627 :
7628 255 : if (pdfStdDev != nullptr)
7629 248 : *pdfStdDev = dfStdDev;
7630 :
7631 255 : if (nValidCount > 0)
7632 246 : return CE_None;
7633 :
7634 9 : ReportError(CE_Failure, CPLE_AppDefined,
7635 : "Failed to compute statistics, no valid pixels found "
7636 : "in sampling.");
7637 9 : return CE_Failure;
7638 : }
7639 :
7640 319 : GByte *pabyMaskData = nullptr;
7641 319 : if (poMaskBand)
7642 : {
7643 : pabyMaskData = static_cast<GByte *>(
7644 58 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7645 58 : if (!pabyMaskData)
7646 : {
7647 0 : return CE_Failure;
7648 : }
7649 : }
7650 :
7651 319 : float fMin = std::numeric_limits<float>::infinity();
7652 319 : float fMax = -std::numeric_limits<float>::infinity();
7653 : bool bFloat32Optim =
7654 133 : (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
7655 319 : eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
7656 209 : !pabyMaskData &&
7657 847 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7658 209 : CPLTestBool(
7659 319 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7660 0 : std::unique_ptr<float, VSIFreeReleaser> pafTemp;
7661 :
7662 319 : int nChunkXSize = nBlockXSize;
7663 319 : int nChunkYSize = nBlockYSize;
7664 319 : int nChunksPerRow = nBlocksPerRow;
7665 319 : int nChunksPerCol = nBlocksPerColumn;
7666 :
7667 : #define nBlockXSize use_nChunkXSize_instead
7668 : #define nBlockYSize use_nChunkYSize_instead
7669 : #define nBlocksPerRow use_nChunksPerRow_instead
7670 : #define nBlocksPerColumn use_nChunksPerCol_instead
7671 :
7672 319 : int nThreads = 1;
7673 319 : CPLWorkerThreadPool *psThreadPool = nullptr;
7674 319 : if (bFloat32Optim)
7675 : {
7676 207 : if (nChunkYSize > 1)
7677 : {
7678 15 : nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
7679 : /* bDefaultToAllCPUs = */ false);
7680 : }
7681 :
7682 207 : int nNewChunkXSize = nChunkXSize;
7683 211 : if (!bApproxOK && nThreads > 1 &&
7684 4 : MayMultiBlockReadingBeMultiThreaded())
7685 : {
7686 0 : const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
7687 0 : const size_t nChunkPixels =
7688 0 : static_cast<size_t>(nChunkXSize) * nChunkYSize;
7689 0 : if (nRAMAmount > 0 &&
7690 : nChunkPixels <=
7691 0 : std::numeric_limits<size_t>::max() / sizeof(float))
7692 : {
7693 0 : const size_t nBlockSizeAsFloat32 =
7694 : sizeof(float) * nChunkPixels;
7695 0 : const int64_t nBlockCount =
7696 0 : nRAMAmount / nBlockSizeAsFloat32;
7697 0 : if (nBlockCount >= 2)
7698 : {
7699 0 : nNewChunkXSize = static_cast<int>(std::min<int64_t>(
7700 0 : nChunkXSize * std::min<int64_t>(
7701 : nBlockCount,
7702 0 : std::numeric_limits<int>::max() /
7703 0 : nChunkPixels),
7704 0 : nRasterXSize));
7705 :
7706 0 : CPLAssert(nChunkXSize <
7707 : std::numeric_limits<int>::max() /
7708 : nChunkYSize);
7709 : }
7710 : }
7711 : }
7712 207 : if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
7713 : {
7714 187 : pafTemp.reset(static_cast<float *>(
7715 187 : VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
7716 187 : bFloat32Optim = pafTemp != nullptr;
7717 187 : if (bFloat32Optim)
7718 : {
7719 187 : nChunkXSize = nNewChunkXSize;
7720 : nChunksPerRow =
7721 187 : cpl::div_round_up(nRasterXSize, nChunkXSize);
7722 : }
7723 : }
7724 207 : CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
7725 : nChunkXSize, nChunkYSize);
7726 : }
7727 :
7728 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7729 : const bool bFloat64Optim =
7730 23 : eDataType == GDT_Float64 && !pabyMaskData &&
7731 365 : nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
7732 23 : CPLTestBool(
7733 319 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7734 : #endif
7735 :
7736 319 : std::vector<StatisticsTaskFloat32> tasksFloat32;
7737 :
7738 319 : for (GIntBig iSampleBlock = 0;
7739 6034 : iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
7740 5715 : iSampleBlock += nSampleRate)
7741 : {
7742 5715 : const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
7743 5715 : const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
7744 :
7745 : const int nXCheck =
7746 5715 : std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
7747 : const int nYCheck =
7748 5715 : std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
7749 :
7750 6300 : if (poMaskBand &&
7751 585 : poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
7752 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7753 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7754 : 0, nChunkXSize, nullptr) != CE_None)
7755 : {
7756 0 : CPLFree(pabyMaskData);
7757 0 : return CE_Failure;
7758 : }
7759 :
7760 5715 : GDALRasterBlock *poBlock = nullptr;
7761 5715 : if (pafTemp)
7762 : {
7763 2393 : if (RasterIO(GF_Read, iXBlock * nChunkXSize,
7764 : iYBlock * nChunkYSize, nXCheck, nYCheck,
7765 2393 : pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
7766 2393 : static_cast<GSpacing>(nChunkXSize * sizeof(float)),
7767 2393 : nullptr) != CE_None)
7768 : {
7769 0 : CPLFree(pabyMaskData);
7770 0 : return CE_Failure;
7771 : }
7772 : }
7773 : else
7774 : {
7775 3322 : poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7776 3322 : if (poBlock == nullptr)
7777 : {
7778 0 : CPLFree(pabyMaskData);
7779 0 : return CE_Failure;
7780 : }
7781 : }
7782 :
7783 : const void *const pData =
7784 5715 : poBlock ? poBlock->GetDataRef() : pafTemp.get();
7785 :
7786 5715 : if (bFloat32Optim)
7787 : {
7788 4729 : const float *const pafSrcData =
7789 : static_cast<const float *>(pData);
7790 :
7791 4735 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7792 6 : !std::isnan(sNoDataValues.fNoDataValue);
7793 4729 : const int nTasks = std::min(nYCheck, nThreads);
7794 4729 : const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
7795 4729 : tasksFloat32.clear();
7796 9462 : for (int i = 0; i < nTasks; ++i)
7797 : {
7798 4733 : StatisticsTaskFloat32 task;
7799 4733 : task.eDataType = eDataType;
7800 4733 : task.bHasNoData = bHasNoData;
7801 4733 : task.psNoDataValues = &sNoDataValues;
7802 4733 : task.nChunkXSize = nChunkXSize;
7803 4733 : task.fMin = fMin;
7804 4733 : task.fMax = fMax;
7805 4733 : task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
7806 4733 : nRowsPerTask *
7807 4733 : nChunkXSize;
7808 4733 : task.nXCheck = nXCheck;
7809 4733 : task.nYCheck =
7810 4733 : std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
7811 4733 : tasksFloat32.emplace_back(std::move(task));
7812 : }
7813 4729 : if (psThreadPool)
7814 : {
7815 0 : auto poJobQueue = psThreadPool->CreateJobQueue();
7816 0 : for (auto &task : tasksFloat32)
7817 : {
7818 0 : poJobQueue->SubmitJob([&task]() { task.Perform(); });
7819 : }
7820 0 : poJobQueue->WaitCompletion();
7821 : }
7822 : else
7823 : {
7824 4729 : tasksFloat32[0].Perform();
7825 : }
7826 :
7827 9462 : for (const auto &task : tasksFloat32)
7828 : {
7829 4733 : if (task.dfBlockValidCount > 0)
7830 : {
7831 4729 : fMin = std::min(fMin, task.fMin);
7832 4729 : fMax = std::max(fMax, task.fMax);
7833 :
7834 : // Update the global mean and M2 (the difference of the
7835 : // square to the mean) from the values of the block
7836 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7837 4729 : const auto nNewValidCount =
7838 4729 : nValidCount +
7839 4729 : static_cast<int>(task.dfBlockValidCount);
7840 4729 : dfM2 += task.dfBlockM2;
7841 4729 : if (task.dfBlockMean != dfMean)
7842 : {
7843 1167 : if (nValidCount == 0)
7844 : {
7845 50 : dfMean = task.dfBlockMean;
7846 : }
7847 : else
7848 : {
7849 1117 : const double dfDelta =
7850 1117 : task.dfBlockMean - dfMean;
7851 1117 : const double dfNewValidCount =
7852 : static_cast<double>(nNewValidCount);
7853 1117 : dfMean += dfDelta * (task.dfBlockValidCount /
7854 : dfNewValidCount);
7855 1117 : dfM2 += dfDelta * dfDelta *
7856 1117 : static_cast<double>(nValidCount) *
7857 1117 : task.dfBlockValidCount /
7858 : dfNewValidCount;
7859 : }
7860 : }
7861 4729 : nValidCount = nNewValidCount;
7862 : }
7863 : }
7864 : }
7865 :
7866 : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
7867 986 : else if (bFloat64Optim)
7868 : {
7869 : const bool bHasNoData =
7870 563 : sNoDataValues.bGotNoDataValue &&
7871 269 : !std::isnan(sNoDataValues.dfNoDataValue);
7872 294 : double dfBlockMean = 0;
7873 294 : double dfBlockM2 = 0;
7874 294 : double dfBlockValidCount = 0;
7875 2661 : for (int iY = 0; iY < nYCheck; iY++)
7876 : {
7877 2367 : const int iOffset = iY * nChunkXSize;
7878 2367 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7879 : {
7880 1817 : int iX = 0;
7881 1817 : if (bHasNoData)
7882 : {
7883 : iX = ComputeStatisticsFloat64_SSE2<
7884 : /* bCheckMinEqMax = */ false,
7885 387 : /* bHasNoData = */ true>(
7886 387 : static_cast<const double *>(pData) + iOffset,
7887 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7888 : dfMax, dfBlockMean, dfBlockM2,
7889 : dfBlockValidCount);
7890 : }
7891 : else
7892 : {
7893 : iX = ComputeStatisticsFloat64_SSE2<
7894 : /* bCheckMinEqMax = */ false,
7895 1430 : /* bHasNoData = */ false>(
7896 1430 : static_cast<const double *>(pData) + iOffset,
7897 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7898 : dfMax, dfBlockMean, dfBlockM2,
7899 : dfBlockValidCount);
7900 : }
7901 2959 : for (; iX < nXCheck; iX++)
7902 : {
7903 1142 : const double dfValue = static_cast<const double *>(
7904 1142 : pData)[iOffset + iX];
7905 1665 : if (std::isnan(dfValue) ||
7906 523 : (bHasNoData &&
7907 523 : dfValue == sNoDataValues.dfNoDataValue))
7908 59 : continue;
7909 1083 : dfMin = std::min(dfMin, dfValue);
7910 1083 : dfMax = std::max(dfMax, dfValue);
7911 1083 : dfBlockValidCount += 1.0;
7912 1083 : const double dfDelta = dfValue - dfBlockMean;
7913 1083 : dfBlockMean += dfDelta / dfBlockValidCount;
7914 1083 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7915 1817 : }
7916 : }
7917 : else
7918 : {
7919 550 : int iX = 0;
7920 550 : if (dfBlockValidCount == 0)
7921 : {
7922 7673 : for (; iX < nXCheck; iX++)
7923 : {
7924 7639 : const double dfValue =
7925 : static_cast<const double *>(
7926 7639 : pData)[iOffset + iX];
7927 15253 : if (std::isnan(dfValue) ||
7928 7614 : (bHasNoData &&
7929 7614 : dfValue == sNoDataValues.dfNoDataValue))
7930 7377 : continue;
7931 262 : dfMin = std::min(dfMin, dfValue);
7932 262 : dfMax = std::max(dfMax, dfValue);
7933 262 : dfBlockValidCount = 1;
7934 262 : dfBlockMean = dfValue;
7935 262 : iX++;
7936 262 : break;
7937 : }
7938 : }
7939 550 : if (bHasNoData)
7940 : {
7941 : iX = ComputeStatisticsFloat64_SSE2<
7942 : /* bCheckMinEqMax = */ true,
7943 398 : /* bHasNoData = */ true>(
7944 398 : static_cast<const double *>(pData) + iOffset,
7945 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7946 : dfMax, dfBlockMean, dfBlockM2,
7947 : dfBlockValidCount);
7948 : }
7949 : else
7950 : {
7951 : iX = ComputeStatisticsFloat64_SSE2<
7952 : /* bCheckMinEqMax = */ true,
7953 152 : /* bHasNoData = */ false>(
7954 152 : static_cast<const double *>(pData) + iOffset,
7955 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7956 : dfMax, dfBlockMean, dfBlockM2,
7957 : dfBlockValidCount);
7958 : }
7959 1121 : for (; iX < nXCheck; iX++)
7960 : {
7961 571 : const double dfValue = static_cast<const double *>(
7962 571 : pData)[iOffset + iX];
7963 1103 : if (std::isnan(dfValue) ||
7964 532 : (bHasNoData &&
7965 532 : dfValue == sNoDataValues.dfNoDataValue))
7966 146 : continue;
7967 425 : dfMin = std::min(dfMin, dfValue);
7968 425 : dfMax = std::max(dfMax, dfValue);
7969 425 : dfBlockValidCount += 1.0;
7970 425 : if (dfMin != dfMax)
7971 : {
7972 150 : const double dfDelta = dfValue - dfBlockMean;
7973 150 : dfBlockMean += dfDelta / dfBlockValidCount;
7974 150 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7975 : }
7976 : }
7977 : }
7978 : }
7979 :
7980 294 : if (dfBlockValidCount > 0)
7981 : {
7982 : // Update the global mean and M2 (the difference of the
7983 : // square to the mean) from the values of the block
7984 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7985 262 : const auto nNewValidCount =
7986 262 : nValidCount + static_cast<int>(dfBlockValidCount);
7987 262 : dfM2 += dfBlockM2;
7988 262 : if (dfBlockMean != dfMean)
7989 : {
7990 249 : if (nValidCount == 0)
7991 : {
7992 20 : dfMean = dfBlockMean;
7993 : }
7994 : else
7995 : {
7996 229 : const double dfDelta = dfBlockMean - dfMean;
7997 229 : const double dfNewValidCount =
7998 : static_cast<double>(nNewValidCount);
7999 229 : dfMean +=
8000 229 : dfDelta * (dfBlockValidCount / dfNewValidCount);
8001 229 : dfM2 += dfDelta * dfDelta *
8002 229 : static_cast<double>(nValidCount) *
8003 229 : dfBlockValidCount / dfNewValidCount;
8004 : }
8005 : }
8006 262 : nValidCount = nNewValidCount;
8007 : }
8008 : }
8009 : #endif // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
8010 :
8011 : else
8012 : {
8013 : // This isn't the fastest way to do this, but is easier for now.
8014 6046 : for (int iY = 0; iY < nYCheck; iY++)
8015 : {
8016 5354 : if (nValidCount && dfMin != dfMax)
8017 : {
8018 712990 : for (int iX = 0; iX < nXCheck; iX++)
8019 : {
8020 708474 : const GPtrDiff_t iOffset =
8021 708474 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8022 708474 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8023 9653 : continue;
8024 :
8025 698847 : bool bValid = true;
8026 : double dfValue =
8027 698847 : GetPixelValue(eDataType, bSignedByte, pData,
8028 698847 : iOffset, sNoDataValues, bValid);
8029 :
8030 698847 : if (!bValid)
8031 26 : continue;
8032 :
8033 698821 : dfMin = std::min(dfMin, dfValue);
8034 698821 : dfMax = std::max(dfMax, dfValue);
8035 :
8036 698821 : nValidCount++;
8037 698821 : const double dfDelta = dfValue - dfMean;
8038 698821 : dfMean += dfDelta / nValidCount;
8039 698821 : dfM2 += dfDelta * (dfValue - dfMean);
8040 4516 : }
8041 : }
8042 : else
8043 : {
8044 838 : int iX = 0;
8045 838 : if (nValidCount == 0)
8046 : {
8047 94429 : for (; iX < nXCheck; iX++)
8048 : {
8049 94372 : const GPtrDiff_t iOffset =
8050 94372 : iX +
8051 94372 : static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8052 94372 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8053 94281 : continue;
8054 :
8055 91 : bool bValid = true;
8056 91 : double dfValue = GetPixelValue(
8057 : eDataType, bSignedByte, pData, iOffset,
8058 : sNoDataValues, bValid);
8059 :
8060 91 : if (!bValid)
8061 0 : continue;
8062 :
8063 91 : dfMin = dfValue;
8064 91 : dfMax = dfValue;
8065 91 : dfMean = dfValue;
8066 91 : nValidCount = 1;
8067 91 : iX++;
8068 91 : break;
8069 : }
8070 : }
8071 167021 : for (; iX < nXCheck; iX++)
8072 : {
8073 166183 : const GPtrDiff_t iOffset =
8074 166183 : iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
8075 166183 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8076 376 : continue;
8077 :
8078 165822 : bool bValid = true;
8079 : double dfValue =
8080 165822 : GetPixelValue(eDataType, bSignedByte, pData,
8081 165822 : iOffset, sNoDataValues, bValid);
8082 :
8083 165822 : if (!bValid)
8084 15 : continue;
8085 :
8086 165807 : dfMin = std::min(dfMin, dfValue);
8087 165807 : dfMax = std::max(dfMax, dfValue);
8088 :
8089 165807 : nValidCount++;
8090 165807 : if (dfMin != dfMax)
8091 : {
8092 2636 : const double dfDelta = dfValue - dfMean;
8093 2636 : dfMean += dfDelta / nValidCount;
8094 2636 : dfM2 += dfDelta * (dfValue - dfMean);
8095 : }
8096 : }
8097 : }
8098 : }
8099 : }
8100 :
8101 5715 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
8102 :
8103 5715 : if (poBlock)
8104 3322 : poBlock->DropLock();
8105 :
8106 5715 : if (!pfnProgress(
8107 5715 : static_cast<double>(iSampleBlock) /
8108 5715 : (static_cast<double>(nChunksPerRow) * nChunksPerCol),
8109 : "Compute Statistics", pProgressData))
8110 : {
8111 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8112 0 : CPLFree(pabyMaskData);
8113 0 : return CE_Failure;
8114 : }
8115 : }
8116 :
8117 : #undef nBlockXSize
8118 : #undef nBlockYSize
8119 : #undef nBlocksPerRow
8120 : #undef nBlocksPerColumn
8121 :
8122 319 : if (bFloat32Optim)
8123 : {
8124 207 : dfMin = static_cast<double>(fMin);
8125 207 : dfMax = static_cast<double>(fMax);
8126 : }
8127 319 : CPLFree(pabyMaskData);
8128 : }
8129 :
8130 319 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
8131 : {
8132 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
8133 0 : return CE_Failure;
8134 : }
8135 :
8136 : /* -------------------------------------------------------------------- */
8137 : /* Save computed information. */
8138 : /* -------------------------------------------------------------------- */
8139 319 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
8140 :
8141 319 : if (nValidCount > 0)
8142 : {
8143 318 : if (bApproxOK)
8144 : {
8145 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
8146 : }
8147 310 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
8148 : {
8149 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
8150 : }
8151 318 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8152 : }
8153 : else
8154 : {
8155 1 : dfMin = 0.0;
8156 1 : dfMax = 0.0;
8157 : }
8158 :
8159 319 : SetValidPercent(nSampleCount, nValidCount);
8160 :
8161 : /* -------------------------------------------------------------------- */
8162 : /* Record results. */
8163 : /* -------------------------------------------------------------------- */
8164 319 : if (pdfMin != nullptr)
8165 316 : *pdfMin = dfMin;
8166 319 : if (pdfMax != nullptr)
8167 316 : *pdfMax = dfMax;
8168 :
8169 319 : if (pdfMean != nullptr)
8170 313 : *pdfMean = dfMean;
8171 :
8172 319 : if (pdfStdDev != nullptr)
8173 313 : *pdfStdDev = dfStdDev;
8174 :
8175 319 : if (nValidCount > 0)
8176 318 : return CE_None;
8177 :
8178 1 : ReportError(
8179 : CE_Failure, CPLE_AppDefined,
8180 : "Failed to compute statistics, no valid pixels found in sampling.");
8181 1 : return CE_Failure;
8182 : }
8183 :
8184 : /************************************************************************/
8185 : /* GDALComputeRasterStatistics() */
8186 : /************************************************************************/
8187 :
8188 : /**
8189 : * \brief Compute image statistics.
8190 : *
8191 : * @see GDALRasterBand::ComputeStatistics()
8192 : */
8193 :
8194 238 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
8195 : int bApproxOK, double *pdfMin,
8196 : double *pdfMax, double *pdfMean,
8197 : double *pdfStdDev,
8198 : GDALProgressFunc pfnProgress,
8199 : void *pProgressData)
8200 :
8201 : {
8202 238 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
8203 :
8204 238 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8205 :
8206 238 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
8207 238 : pdfStdDev, pfnProgress, pProgressData);
8208 : }
8209 :
8210 : /************************************************************************/
8211 : /* SetStatistics() */
8212 : /************************************************************************/
8213 :
8214 : /**
8215 : * \brief Set statistics on band.
8216 : *
8217 : * This method can be used to store min/max/mean/standard deviation
8218 : * statistics on a raster band.
8219 : *
8220 : * The default implementation stores them as metadata, and will only work
8221 : * on formats that can save arbitrary metadata. This method cannot detect
8222 : * whether metadata will be properly saved and so may return CE_None even
8223 : * if the statistics will never be saved.
8224 : *
8225 : * This method is the same as the C function GDALSetRasterStatistics().
8226 : *
8227 : * @param dfMin minimum pixel value.
8228 : *
8229 : * @param dfMax maximum pixel value.
8230 : *
8231 : * @param dfMean mean (average) of all pixel values.
8232 : *
8233 : * @param dfStdDev Standard deviation of all pixel values.
8234 : *
8235 : * @return CE_None on success or CE_Failure on failure.
8236 : */
8237 :
8238 597 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
8239 : double dfStdDev)
8240 :
8241 : {
8242 597 : char szValue[128] = {0};
8243 :
8244 597 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
8245 597 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
8246 :
8247 597 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
8248 597 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
8249 :
8250 597 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
8251 597 : SetMetadataItem("STATISTICS_MEAN", szValue);
8252 :
8253 597 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
8254 597 : SetMetadataItem("STATISTICS_STDDEV", szValue);
8255 :
8256 597 : return CE_None;
8257 : }
8258 :
8259 : /************************************************************************/
8260 : /* GDALSetRasterStatistics() */
8261 : /************************************************************************/
8262 :
8263 : /**
8264 : * \brief Set statistics on band.
8265 : *
8266 : * @see GDALRasterBand::SetStatistics()
8267 : */
8268 :
8269 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
8270 : double dfMax, double dfMean,
8271 : double dfStdDev)
8272 :
8273 : {
8274 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
8275 :
8276 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8277 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
8278 : }
8279 :
8280 : /************************************************************************/
8281 : /* ComputeRasterMinMax() */
8282 : /************************************************************************/
8283 :
8284 : template <class T, bool HAS_NODATA>
8285 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
8286 : T *pMax)
8287 : {
8288 2 : T min0 = *pMin;
8289 2 : T max0 = *pMax;
8290 2 : T min1 = *pMin;
8291 2 : T max1 = *pMax;
8292 : size_t i;
8293 2 : for (i = 0; i + 1 < nElts; i += 2)
8294 : {
8295 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8296 : {
8297 0 : min0 = std::min(min0, buffer[i]);
8298 0 : max0 = std::max(max0, buffer[i]);
8299 : }
8300 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
8301 : {
8302 0 : min1 = std::min(min1, buffer[i + 1]);
8303 0 : max1 = std::max(max1, buffer[i + 1]);
8304 : }
8305 : }
8306 2 : T min = std::min(min0, min1);
8307 2 : T max = std::max(max0, max1);
8308 2 : if (i < nElts)
8309 : {
8310 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
8311 : {
8312 2 : min = std::min(min, buffer[i]);
8313 2 : max = std::max(max, buffer[i]);
8314 : }
8315 : }
8316 2 : *pMin = min;
8317 2 : *pMax = max;
8318 2 : }
8319 :
8320 : template <GDALDataType eDataType, bool bSignedByte>
8321 : static void
8322 6743 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
8323 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
8324 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
8325 : {
8326 6743 : double dfLocalMin = dfMin;
8327 6743 : double dfLocalMax = dfMax;
8328 :
8329 22131 : for (int iY = 0; iY < nYCheck; iY++)
8330 : {
8331 14858621 : for (int iX = 0; iX < nXCheck; iX++)
8332 : {
8333 14843185 : const GPtrDiff_t iOffset =
8334 14843185 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8335 14843185 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8336 109852 : continue;
8337 14760202 : bool bValid = true;
8338 14760202 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8339 : iOffset, sNoDataValues, bValid);
8340 14760202 : if (!bValid)
8341 26871 : continue;
8342 :
8343 14733402 : dfLocalMin = std::min(dfLocalMin, dfValue);
8344 14733402 : dfLocalMax = std::max(dfLocalMax, dfValue);
8345 : }
8346 : }
8347 :
8348 6743 : dfMin = dfLocalMin;
8349 6743 : dfMax = dfLocalMax;
8350 6743 : }
8351 :
8352 6743 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8353 : bool bSignedByte, int nXCheck, int nYCheck,
8354 : int nBlockXSize,
8355 : const GDALNoDataValues &sNoDataValues,
8356 : const GByte *pabyMaskData, double &dfMin,
8357 : double &dfMax)
8358 : {
8359 6743 : switch (eDataType)
8360 : {
8361 0 : case GDT_Unknown:
8362 0 : CPLAssert(false);
8363 : break;
8364 660 : case GDT_UInt8:
8365 660 : if (bSignedByte)
8366 : {
8367 3 : ComputeMinMaxGeneric<GDT_UInt8, true>(
8368 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8369 : pabyMaskData, dfMin, dfMax);
8370 : }
8371 : else
8372 : {
8373 657 : ComputeMinMaxGeneric<GDT_UInt8, false>(
8374 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8375 : pabyMaskData, dfMin, dfMax);
8376 : }
8377 660 : break;
8378 4 : case GDT_Int8:
8379 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8380 : nBlockXSize, sNoDataValues,
8381 : pabyMaskData, dfMin, dfMax);
8382 4 : break;
8383 969 : case GDT_UInt16:
8384 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8385 : nBlockXSize, sNoDataValues,
8386 : pabyMaskData, dfMin, dfMax);
8387 969 : break;
8388 2 : case GDT_Int16:
8389 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8390 : nBlockXSize, sNoDataValues,
8391 : pabyMaskData, dfMin, dfMax);
8392 2 : break;
8393 3 : case GDT_UInt32:
8394 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8395 : nBlockXSize, sNoDataValues,
8396 : pabyMaskData, dfMin, dfMax);
8397 3 : break;
8398 3 : case GDT_Int32:
8399 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8400 : nBlockXSize, sNoDataValues,
8401 : pabyMaskData, dfMin, dfMax);
8402 3 : break;
8403 4 : case GDT_UInt64:
8404 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8405 : nBlockXSize, sNoDataValues,
8406 : pabyMaskData, dfMin, dfMax);
8407 4 : break;
8408 4 : case GDT_Int64:
8409 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8410 : nBlockXSize, sNoDataValues,
8411 : pabyMaskData, dfMin, dfMax);
8412 4 : break;
8413 2 : case GDT_Float16:
8414 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8415 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8416 : pabyMaskData, dfMin, dfMax);
8417 2 : break;
8418 4981 : case GDT_Float32:
8419 4981 : ComputeMinMaxGeneric<GDT_Float32, false>(
8420 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8421 : pabyMaskData, dfMin, dfMax);
8422 4981 : break;
8423 1 : case GDT_Float64:
8424 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8425 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8426 : pabyMaskData, dfMin, dfMax);
8427 1 : break;
8428 9 : case GDT_CInt16:
8429 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8430 : nBlockXSize, sNoDataValues,
8431 : pabyMaskData, dfMin, dfMax);
8432 9 : break;
8433 9 : case GDT_CInt32:
8434 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8435 : nBlockXSize, sNoDataValues,
8436 : pabyMaskData, dfMin, dfMax);
8437 9 : break;
8438 0 : case GDT_CFloat16:
8439 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8440 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8441 : pabyMaskData, dfMin, dfMax);
8442 0 : break;
8443 75 : case GDT_CFloat32:
8444 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8445 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8446 : pabyMaskData, dfMin, dfMax);
8447 75 : break;
8448 17 : case GDT_CFloat64:
8449 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8450 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8451 : pabyMaskData, dfMin, dfMax);
8452 17 : break;
8453 0 : case GDT_TypeCount:
8454 0 : CPLAssert(false);
8455 : break;
8456 : }
8457 6743 : }
8458 :
8459 209 : static bool ComputeMinMaxGenericIterBlocks(
8460 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8461 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8462 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8463 : double &dfMin, double &dfMax)
8464 :
8465 : {
8466 209 : GByte *pabyMaskData = nullptr;
8467 : int nBlockXSize, nBlockYSize;
8468 209 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8469 :
8470 209 : if (poMaskBand)
8471 : {
8472 : pabyMaskData =
8473 145 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8474 145 : if (!pabyMaskData)
8475 : {
8476 0 : return false;
8477 : }
8478 : }
8479 :
8480 6952 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8481 6743 : iSampleBlock += nSampleRate)
8482 : {
8483 6743 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8484 6743 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8485 :
8486 6743 : int nXCheck = 0, nYCheck = 0;
8487 6743 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8488 :
8489 13363 : if (poMaskBand &&
8490 6620 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8491 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8492 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8493 : nBlockXSize, nullptr) != CE_None)
8494 : {
8495 0 : CPLFree(pabyMaskData);
8496 0 : return false;
8497 : }
8498 :
8499 6743 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8500 6743 : if (poBlock == nullptr)
8501 : {
8502 0 : CPLFree(pabyMaskData);
8503 0 : return false;
8504 : }
8505 :
8506 6743 : void *const pData = poBlock->GetDataRef();
8507 :
8508 6743 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8509 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8510 : dfMax);
8511 :
8512 6743 : poBlock->DropLock();
8513 : }
8514 :
8515 209 : CPLFree(pabyMaskData);
8516 209 : return true;
8517 : }
8518 :
8519 : /**
8520 : * \brief Compute the min/max values for a band.
8521 : *
8522 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8523 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8524 : * get an approximate min/max. If the band has a nodata value it will
8525 : * be excluded from the minimum and maximum.
8526 : *
8527 : * If bApprox is FALSE, then all pixels will be read and used to compute
8528 : * an exact range.
8529 : *
8530 : * This method is the same as the C function GDALComputeRasterMinMax().
8531 : *
8532 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8533 : * FALSE.
8534 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8535 : * maximum (adfMinMax[1]) are returned.
8536 : *
8537 : * @return CE_None on success or CE_Failure on failure.
8538 : */
8539 :
8540 1953 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8541 : {
8542 : /* -------------------------------------------------------------------- */
8543 : /* Does the driver already know the min/max? */
8544 : /* -------------------------------------------------------------------- */
8545 1953 : if (bApproxOK)
8546 : {
8547 23 : int bSuccessMin = FALSE;
8548 23 : int bSuccessMax = FALSE;
8549 :
8550 23 : double dfMin = GetMinimum(&bSuccessMin);
8551 23 : double dfMax = GetMaximum(&bSuccessMax);
8552 :
8553 23 : if (bSuccessMin && bSuccessMax)
8554 : {
8555 1 : adfMinMax[0] = dfMin;
8556 1 : adfMinMax[1] = dfMax;
8557 1 : return CE_None;
8558 : }
8559 : }
8560 :
8561 : /* -------------------------------------------------------------------- */
8562 : /* If we have overview bands, use them for min/max. */
8563 : /* -------------------------------------------------------------------- */
8564 : // cppcheck-suppress knownConditionTrueFalse
8565 1952 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8566 : {
8567 : GDALRasterBand *poBand =
8568 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8569 :
8570 0 : if (poBand != this)
8571 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8572 : }
8573 :
8574 : /* -------------------------------------------------------------------- */
8575 : /* Read actual data and compute minimum and maximum. */
8576 : /* -------------------------------------------------------------------- */
8577 1952 : GDALNoDataValues sNoDataValues(this, eDataType);
8578 1952 : GDALRasterBand *poMaskBand = nullptr;
8579 1952 : if (!sNoDataValues.bGotNoDataValue)
8580 : {
8581 1589 : const int l_nMaskFlags = GetMaskFlags();
8582 1734 : if (l_nMaskFlags != GMF_ALL_VALID &&
8583 145 : GetColorInterpretation() != GCI_AlphaBand)
8584 : {
8585 145 : poMaskBand = GetMaskBand();
8586 : }
8587 : }
8588 :
8589 1952 : if (!bApproxOK &&
8590 1930 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8591 1770 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8592 1545 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8593 1499 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8594 1930 : eDataType == GDT_Float64) &&
8595 : !poMaskBand)
8596 : {
8597 1606 : CPLErr eErr = ComputeRasterMinMaxLocation(
8598 803 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8599 803 : if (eErr == CE_Warning)
8600 : {
8601 9 : ReportError(CE_Failure, CPLE_AppDefined,
8602 : "Failed to compute min/max, no valid pixels found in "
8603 : "sampling.");
8604 9 : eErr = CE_Failure;
8605 : }
8606 803 : return eErr;
8607 : }
8608 :
8609 1149 : bool bSignedByte = false;
8610 1149 : if (eDataType == GDT_UInt8)
8611 : {
8612 807 : EnablePixelTypeSignedByteWarning(false);
8613 : const char *pszPixelType =
8614 807 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8615 807 : EnablePixelTypeSignedByteWarning(true);
8616 807 : bSignedByte =
8617 807 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8618 : }
8619 :
8620 : GDALRasterIOExtraArg sExtraArg;
8621 1149 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8622 :
8623 2298 : GUInt32 nMin = (eDataType == GDT_UInt8)
8624 1149 : ? 255
8625 : : 65535; // used for GByte & GUInt16 cases
8626 1149 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8627 1149 : GInt16 nMinInt16 =
8628 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8629 1149 : GInt16 nMaxInt16 =
8630 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8631 1149 : double dfMin =
8632 : std::numeric_limits<double>::infinity(); // used for generic code path
8633 1149 : double dfMax =
8634 : -std::numeric_limits<double>::infinity(); // used for generic code path
8635 1149 : const bool bUseOptimizedPath =
8636 1377 : !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8637 228 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8638 :
8639 : const auto ComputeMinMaxForBlock =
8640 19640 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8641 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8642 113770 : int nYCheck)
8643 : {
8644 19640 : if (eDataType == GDT_UInt8 && !bSignedByte)
8645 : {
8646 : const bool bHasNoData =
8647 11612 : sNoDataValues.bGotNoDataValue &&
8648 29793 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8649 11612 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8650 11612 : sNoDataValues.dfNoDataValue;
8651 18181 : const GUInt32 nNoDataValue =
8652 18181 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8653 : : 0;
8654 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8655 : ComputeStatisticsInternal<GByte,
8656 : /* COMPUTE_OTHER_STATS = */ false>::
8657 18181 : f(nXCheck, nBufferWidth, nYCheck,
8658 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8659 18181 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8660 : }
8661 1459 : else if (eDataType == GDT_UInt16)
8662 : {
8663 : const bool bHasNoData =
8664 124 : sNoDataValues.bGotNoDataValue &&
8665 1581 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8666 124 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8667 124 : sNoDataValues.dfNoDataValue;
8668 1457 : const GUInt32 nNoDataValue =
8669 1457 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8670 : : 0;
8671 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8672 : ComputeStatisticsInternal<GUInt16,
8673 : /* COMPUTE_OTHER_STATS = */ false>::
8674 1457 : f(nXCheck, nBufferWidth, nYCheck,
8675 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8676 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8677 : }
8678 2 : else if (eDataType == GDT_Int16)
8679 : {
8680 : const bool bHasNoData =
8681 0 : sNoDataValues.bGotNoDataValue &&
8682 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8683 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8684 0 : sNoDataValues.dfNoDataValue;
8685 2 : if (bHasNoData)
8686 : {
8687 0 : const int16_t nNoDataValue =
8688 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8689 0 : for (int iY = 0; iY < nYCheck; iY++)
8690 : {
8691 0 : ComputeMinMax<int16_t, true>(
8692 0 : static_cast<const int16_t *>(pData) +
8693 0 : static_cast<size_t>(iY) * nBufferWidth,
8694 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8695 : }
8696 : }
8697 : else
8698 : {
8699 4 : for (int iY = 0; iY < nYCheck; iY++)
8700 : {
8701 2 : ComputeMinMax<int16_t, false>(
8702 2 : static_cast<const int16_t *>(pData) +
8703 2 : static_cast<size_t>(iY) * nBufferWidth,
8704 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8705 : }
8706 : }
8707 : }
8708 19640 : };
8709 :
8710 1149 : if (bApproxOK && HasArbitraryOverviews())
8711 : {
8712 : /* --------------------------------------------------------------------
8713 : */
8714 : /* Figure out how much the image should be reduced to get an */
8715 : /* approximate value. */
8716 : /* --------------------------------------------------------------------
8717 : */
8718 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8719 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8720 :
8721 0 : int nXReduced = nRasterXSize;
8722 0 : int nYReduced = nRasterYSize;
8723 0 : if (dfReduction > 1.0)
8724 : {
8725 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8726 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8727 :
8728 : // Catch the case of huge resizing ratios here
8729 0 : if (nXReduced == 0)
8730 0 : nXReduced = 1;
8731 0 : if (nYReduced == 0)
8732 0 : nYReduced = 1;
8733 : }
8734 :
8735 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8736 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8737 :
8738 : const CPLErr eErr =
8739 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8740 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8741 0 : if (eErr != CE_None)
8742 : {
8743 0 : CPLFree(pData);
8744 0 : return eErr;
8745 : }
8746 :
8747 0 : GByte *pabyMaskData = nullptr;
8748 0 : if (poMaskBand)
8749 : {
8750 : pabyMaskData =
8751 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8752 0 : if (!pabyMaskData)
8753 : {
8754 0 : CPLFree(pData);
8755 0 : return CE_Failure;
8756 : }
8757 :
8758 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8759 : pabyMaskData, nXReduced, nYReduced,
8760 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
8761 : {
8762 0 : CPLFree(pData);
8763 0 : CPLFree(pabyMaskData);
8764 0 : return CE_Failure;
8765 : }
8766 : }
8767 :
8768 0 : if (bUseOptimizedPath)
8769 : {
8770 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8771 : }
8772 : else
8773 : {
8774 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8775 : nYReduced, nXReduced, sNoDataValues,
8776 : pabyMaskData, dfMin, dfMax);
8777 : }
8778 :
8779 0 : CPLFree(pData);
8780 0 : CPLFree(pabyMaskData);
8781 : }
8782 :
8783 : else // No arbitrary overviews
8784 : {
8785 1149 : if (!InitBlockInfo())
8786 0 : return CE_Failure;
8787 :
8788 : /* --------------------------------------------------------------------
8789 : */
8790 : /* Figure out the ratio of blocks we will read to get an */
8791 : /* approximate value. */
8792 : /* --------------------------------------------------------------------
8793 : */
8794 1149 : int nSampleRate = 1;
8795 :
8796 1149 : if (bApproxOK)
8797 : {
8798 22 : nSampleRate = static_cast<int>(std::max(
8799 44 : 1.0,
8800 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8801 : // We want to avoid probing only the first column of blocks for
8802 : // a square shaped raster, because it is not unlikely that it may
8803 : // be padding only (#6378).
8804 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8805 0 : nSampleRate += 1;
8806 : }
8807 :
8808 1149 : if (bUseOptimizedPath)
8809 : {
8810 940 : for (GIntBig iSampleBlock = 0;
8811 20506 : iSampleBlock <
8812 20506 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8813 19566 : iSampleBlock += nSampleRate)
8814 : {
8815 19642 : const int iYBlock =
8816 19642 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8817 19642 : const int iXBlock =
8818 19642 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8819 :
8820 19642 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8821 19642 : if (poBlock == nullptr)
8822 2 : return CE_Failure;
8823 :
8824 19640 : void *const pData = poBlock->GetDataRef();
8825 :
8826 19640 : int nXCheck = 0, nYCheck = 0;
8827 19640 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8828 :
8829 19640 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8830 :
8831 19640 : poBlock->DropLock();
8832 :
8833 19640 : if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8834 4114 : nMax == 255)
8835 74 : break;
8836 : }
8837 : }
8838 : else
8839 : {
8840 209 : const GIntBig nTotalBlocks =
8841 209 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8842 209 : if (!ComputeMinMaxGenericIterBlocks(
8843 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8844 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8845 : {
8846 0 : return CE_Failure;
8847 : }
8848 : }
8849 : }
8850 :
8851 1147 : if (bUseOptimizedPath)
8852 : {
8853 938 : if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8854 : {
8855 937 : dfMin = nMin;
8856 937 : dfMax = nMax;
8857 : }
8858 1 : else if (eDataType == GDT_Int16)
8859 : {
8860 1 : dfMin = nMinInt16;
8861 1 : dfMax = nMaxInt16;
8862 : }
8863 : }
8864 :
8865 1147 : if (dfMin > dfMax)
8866 : {
8867 24 : adfMinMax[0] = 0;
8868 24 : adfMinMax[1] = 0;
8869 24 : ReportError(
8870 : CE_Failure, CPLE_AppDefined,
8871 : "Failed to compute min/max, no valid pixels found in sampling.");
8872 24 : return CE_Failure;
8873 : }
8874 :
8875 1123 : adfMinMax[0] = dfMin;
8876 1123 : adfMinMax[1] = dfMax;
8877 :
8878 1123 : return CE_None;
8879 : }
8880 :
8881 : /************************************************************************/
8882 : /* GDALComputeRasterMinMax() */
8883 : /************************************************************************/
8884 :
8885 : /**
8886 : * \brief Compute the min/max values for a band.
8887 : *
8888 : * @see GDALRasterBand::ComputeRasterMinMax()
8889 : *
8890 : * @note Prior to GDAL 3.6, this function returned void
8891 : */
8892 :
8893 1802 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8894 : double adfMinMax[2])
8895 :
8896 : {
8897 1802 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8898 :
8899 1802 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8900 1802 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8901 : }
8902 :
8903 : /************************************************************************/
8904 : /* ComputeRasterMinMaxLocation() */
8905 : /************************************************************************/
8906 :
8907 : /**
8908 : * \brief Compute the min/max values for a band, and their location.
8909 : *
8910 : * Pixels whose value matches the nodata value or are masked by the mask
8911 : * band are ignored.
8912 : *
8913 : * If the minimum or maximum value is hit in several locations, it is not
8914 : * specified which one will be returned.
8915 : *
8916 : * @param[out] pdfMin Pointer to the minimum value.
8917 : * @param[out] pdfMax Pointer to the maximum value.
8918 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8919 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8920 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8921 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8922 : *
8923 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8924 : * CE_Failure in case of error.
8925 : *
8926 : * @since GDAL 3.11
8927 : */
8928 :
8929 819 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8930 : double *pdfMax, int *pnMinX,
8931 : int *pnMinY, int *pnMaxX,
8932 : int *pnMaxY)
8933 : {
8934 819 : int nMinX = -1;
8935 819 : int nMinY = -1;
8936 819 : int nMaxX = -1;
8937 819 : int nMaxY = -1;
8938 819 : double dfMin = std::numeric_limits<double>::infinity();
8939 819 : double dfMax = -std::numeric_limits<double>::infinity();
8940 819 : if (pdfMin)
8941 816 : *pdfMin = dfMin;
8942 819 : if (pdfMax)
8943 816 : *pdfMax = dfMax;
8944 819 : if (pnMinX)
8945 14 : *pnMinX = nMinX;
8946 819 : if (pnMinY)
8947 14 : *pnMinY = nMinY;
8948 819 : if (pnMaxX)
8949 14 : *pnMaxX = nMaxX;
8950 819 : if (pnMaxY)
8951 14 : *pnMaxY = nMaxY;
8952 :
8953 819 : if (GDALDataTypeIsComplex(eDataType))
8954 : {
8955 0 : CPLError(CE_Failure, CPLE_NotSupported,
8956 : "Complex data type not supported");
8957 0 : return CE_Failure;
8958 : }
8959 :
8960 819 : if (!InitBlockInfo())
8961 0 : return CE_Failure;
8962 :
8963 819 : GDALNoDataValues sNoDataValues(this, eDataType);
8964 819 : GDALRasterBand *poMaskBand = nullptr;
8965 819 : if (!sNoDataValues.bGotNoDataValue)
8966 : {
8967 586 : const int l_nMaskFlags = GetMaskFlags();
8968 587 : if (l_nMaskFlags != GMF_ALL_VALID &&
8969 1 : GetColorInterpretation() != GCI_AlphaBand)
8970 : {
8971 1 : poMaskBand = GetMaskBand();
8972 : }
8973 : }
8974 :
8975 819 : bool bSignedByte = false;
8976 819 : if (eDataType == GDT_UInt8)
8977 : {
8978 7 : EnablePixelTypeSignedByteWarning(false);
8979 : const char *pszPixelType =
8980 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8981 7 : EnablePixelTypeSignedByteWarning(true);
8982 7 : bSignedByte =
8983 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8984 : }
8985 :
8986 819 : GByte *pabyMaskData = nullptr;
8987 819 : if (poMaskBand)
8988 : {
8989 : pabyMaskData =
8990 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8991 1 : if (!pabyMaskData)
8992 : {
8993 0 : return CE_Failure;
8994 : }
8995 : }
8996 :
8997 819 : const GIntBig nTotalBlocks =
8998 819 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8999 819 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
9000 819 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
9001 8061 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
9002 : {
9003 7245 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
9004 7245 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
9005 :
9006 7245 : int nXCheck = 0, nYCheck = 0;
9007 7245 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
9008 :
9009 7247 : if (poMaskBand &&
9010 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
9011 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
9012 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
9013 2 : nBlockXSize, nullptr) != CE_None)
9014 : {
9015 0 : CPLFree(pabyMaskData);
9016 0 : return CE_Failure;
9017 : }
9018 :
9019 7245 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
9020 7245 : if (poBlock == nullptr)
9021 : {
9022 0 : CPLFree(pabyMaskData);
9023 0 : return CE_Failure;
9024 : }
9025 :
9026 7245 : void *const pData = poBlock->GetDataRef();
9027 :
9028 7245 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
9029 : {
9030 5059 : for (int iY = 0; iY < nYCheck; ++iY)
9031 : {
9032 238290 : for (int iX = 0; iX < nXCheck; ++iX)
9033 : {
9034 233478 : const GPtrDiff_t iOffset =
9035 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
9036 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
9037 2 : continue;
9038 233476 : bool bValid = true;
9039 : double dfValue =
9040 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
9041 : sNoDataValues, bValid);
9042 233476 : if (!bValid)
9043 0 : continue;
9044 233476 : if (dfValue < dfMin)
9045 : {
9046 606 : dfMin = dfValue;
9047 606 : nMinX = iXBlock * nBlockXSize + iX;
9048 606 : nMinY = iYBlock * nBlockYSize + iY;
9049 : }
9050 233476 : if (dfValue > dfMax)
9051 : {
9052 1515 : dfMax = dfValue;
9053 1515 : nMaxX = iXBlock * nBlockXSize + iX;
9054 1515 : nMaxY = iYBlock * nBlockYSize + iY;
9055 : }
9056 : }
9057 247 : }
9058 : }
9059 : else
9060 : {
9061 6998 : size_t pos_min = 0;
9062 6998 : size_t pos_max = 0;
9063 6998 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
9064 6998 : if (bNeedsMin && bNeedsMax)
9065 : {
9066 13988 : std::tie(pos_min, pos_max) = gdal::minmax_element(
9067 6994 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9068 6994 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
9069 13988 : sNoDataValues.dfNoDataValue);
9070 : }
9071 4 : else if (bNeedsMin)
9072 : {
9073 1 : pos_min = gdal::min_element(
9074 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9075 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
9076 : sNoDataValues.dfNoDataValue);
9077 : }
9078 3 : else if (bNeedsMax)
9079 : {
9080 2 : pos_max = gdal::max_element(
9081 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
9082 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
9083 : sNoDataValues.dfNoDataValue);
9084 : }
9085 :
9086 6998 : if (bNeedsMin)
9087 : {
9088 6995 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
9089 6995 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
9090 6995 : bool bValid = true;
9091 : const double dfMinValueBlock =
9092 6995 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
9093 : sNoDataValues, bValid);
9094 6995 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
9095 : {
9096 1110 : dfMin = dfMinValueBlock;
9097 1110 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
9098 1110 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
9099 : }
9100 : }
9101 :
9102 6998 : if (bNeedsMax)
9103 : {
9104 6996 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
9105 6996 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
9106 6996 : bool bValid = true;
9107 : const double dfMaxValueBlock =
9108 6996 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
9109 : sNoDataValues, bValid);
9110 6996 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
9111 : {
9112 1098 : dfMax = dfMaxValueBlock;
9113 1098 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
9114 1098 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
9115 : }
9116 : }
9117 : }
9118 :
9119 7245 : poBlock->DropLock();
9120 :
9121 7245 : if (eDataType == GDT_UInt8)
9122 : {
9123 10 : if (bNeedsMin && dfMin == 0)
9124 : {
9125 1 : bNeedsMin = false;
9126 : }
9127 10 : if (bNeedsMax && dfMax == 255)
9128 : {
9129 4 : bNeedsMax = false;
9130 : }
9131 10 : if (!bNeedsMin && !bNeedsMax)
9132 : {
9133 3 : break;
9134 : }
9135 : }
9136 : }
9137 :
9138 819 : CPLFree(pabyMaskData);
9139 :
9140 819 : if (pdfMin)
9141 816 : *pdfMin = dfMin;
9142 819 : if (pdfMax)
9143 816 : *pdfMax = dfMax;
9144 819 : if (pnMinX)
9145 14 : *pnMinX = nMinX;
9146 819 : if (pnMinY)
9147 14 : *pnMinY = nMinY;
9148 819 : if (pnMaxX)
9149 14 : *pnMaxX = nMaxX;
9150 819 : if (pnMaxY)
9151 14 : *pnMaxY = nMaxY;
9152 819 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
9153 819 : : CE_None;
9154 : }
9155 :
9156 : /************************************************************************/
9157 : /* GDALComputeRasterMinMaxLocation() */
9158 : /************************************************************************/
9159 :
9160 : /**
9161 : * \brief Compute the min/max values for a band, and their location.
9162 : *
9163 : * @see GDALRasterBand::ComputeRasterMinMax()
9164 : * @since GDAL 3.11
9165 : */
9166 :
9167 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
9168 : double *pdfMax, int *pnMinX, int *pnMinY,
9169 : int *pnMaxX, int *pnMaxY)
9170 :
9171 : {
9172 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
9173 :
9174 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9175 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
9176 14 : pnMaxX, pnMaxY);
9177 : }
9178 :
9179 : /************************************************************************/
9180 : /* SetDefaultHistogram() */
9181 : /************************************************************************/
9182 :
9183 : /* FIXME : add proper documentation */
9184 : /**
9185 : * \brief Set default histogram.
9186 : *
9187 : * This method is the same as the C function GDALSetDefaultHistogram() and
9188 : * GDALSetDefaultHistogramEx()
9189 : */
9190 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
9191 : double /* dfMax */,
9192 : int /* nBuckets */,
9193 : GUIntBig * /* panHistogram */)
9194 :
9195 : {
9196 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9197 0 : ReportError(CE_Failure, CPLE_NotSupported,
9198 : "SetDefaultHistogram() not implemented for this format.");
9199 :
9200 0 : return CE_Failure;
9201 : }
9202 :
9203 : /************************************************************************/
9204 : /* GDALSetDefaultHistogram() */
9205 : /************************************************************************/
9206 :
9207 : /**
9208 : * \brief Set default histogram.
9209 : *
9210 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
9211 : * 2 billion.
9212 : *
9213 : * @see GDALRasterBand::SetDefaultHistogram()
9214 : * @see GDALSetRasterHistogramEx()
9215 : */
9216 :
9217 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
9218 : double dfMax, int nBuckets,
9219 : int *panHistogram)
9220 :
9221 : {
9222 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
9223 :
9224 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9225 :
9226 : GUIntBig *panHistogramTemp =
9227 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
9228 0 : if (panHistogramTemp == nullptr)
9229 : {
9230 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
9231 : "Out of memory in GDALSetDefaultHistogram().");
9232 0 : return CE_Failure;
9233 : }
9234 :
9235 0 : for (int i = 0; i < nBuckets; ++i)
9236 : {
9237 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
9238 : }
9239 :
9240 : const CPLErr eErr =
9241 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
9242 :
9243 0 : CPLFree(panHistogramTemp);
9244 :
9245 0 : return eErr;
9246 : }
9247 :
9248 : /************************************************************************/
9249 : /* GDALSetDefaultHistogramEx() */
9250 : /************************************************************************/
9251 :
9252 : /**
9253 : * \brief Set default histogram.
9254 : *
9255 : * @see GDALRasterBand::SetDefaultHistogram()
9256 : *
9257 : */
9258 :
9259 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
9260 : double dfMin, double dfMax,
9261 : int nBuckets,
9262 : GUIntBig *panHistogram)
9263 :
9264 : {
9265 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
9266 :
9267 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9268 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
9269 : }
9270 :
9271 : /************************************************************************/
9272 : /* GetDefaultRAT() */
9273 : /************************************************************************/
9274 :
9275 : /**
9276 : * \brief Fetch default Raster Attribute Table.
9277 : *
9278 : * A RAT will be returned if there is a default one associated with the
9279 : * band, otherwise NULL is returned. The returned RAT is owned by the
9280 : * band and should not be deleted by the application.
9281 : *
9282 : * This method is the same as the C function GDALGetDefaultRAT().
9283 : *
9284 : * @return NULL, or a pointer to an internal RAT owned by the band.
9285 : */
9286 :
9287 251 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
9288 :
9289 : {
9290 251 : return nullptr;
9291 : }
9292 :
9293 : /************************************************************************/
9294 : /* GDALGetDefaultRAT() */
9295 : /************************************************************************/
9296 :
9297 : /**
9298 : * \brief Fetch default Raster Attribute Table.
9299 : *
9300 : * @see GDALRasterBand::GetDefaultRAT()
9301 : */
9302 :
9303 1343 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
9304 :
9305 : {
9306 1343 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
9307 :
9308 1343 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9309 1343 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
9310 : }
9311 :
9312 : /************************************************************************/
9313 : /* SetDefaultRAT() */
9314 : /************************************************************************/
9315 :
9316 : /**
9317 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
9318 : * \brief Set default Raster Attribute Table.
9319 : *
9320 : * Associates a default RAT with the band. If not implemented for the
9321 : * format a CPLE_NotSupported error will be issued. If successful a copy
9322 : * of the RAT is made, the original remains owned by the caller.
9323 : *
9324 : * This method is the same as the C function GDALSetDefaultRAT().
9325 : *
9326 : * @param poRAT the RAT to assign to the band.
9327 : *
9328 : * @return CE_None on success or CE_Failure if unsupported or otherwise
9329 : * failing.
9330 : */
9331 :
9332 : /**/
9333 : /**/
9334 :
9335 : CPLErr
9336 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9337 : {
9338 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9339 : {
9340 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
9341 0 : ReportError(CE_Failure, CPLE_NotSupported,
9342 : "SetDefaultRAT() not implemented for this format.");
9343 0 : CPLPopErrorHandler();
9344 : }
9345 0 : return CE_Failure;
9346 : }
9347 :
9348 : /************************************************************************/
9349 : /* GDALSetDefaultRAT() */
9350 : /************************************************************************/
9351 :
9352 : /**
9353 : * \brief Set default Raster Attribute Table.
9354 : *
9355 : * @see GDALRasterBand::GDALSetDefaultRAT()
9356 : */
9357 :
9358 65 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9359 : GDALRasterAttributeTableH hRAT)
9360 :
9361 : {
9362 65 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9363 :
9364 65 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9365 :
9366 65 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9367 : }
9368 :
9369 : /************************************************************************/
9370 : /* HasNoData() */
9371 : /************************************************************************/
9372 :
9373 137164 : bool GDALRasterBand::HasNoData() const
9374 : {
9375 137164 : int bHaveNoDataRaw = FALSE;
9376 137164 : bool bHaveNoData = false;
9377 137164 : GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
9378 137164 : if (eDataType == GDT_Int64)
9379 : {
9380 212 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
9381 212 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9382 : }
9383 136952 : else if (eDataType == GDT_UInt64)
9384 : {
9385 160 : CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9386 160 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9387 : }
9388 : else
9389 : {
9390 136792 : const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
9391 136792 : if (bHaveNoDataRaw &&
9392 136792 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9393 : {
9394 1256 : bHaveNoData = true;
9395 : }
9396 : }
9397 137164 : return bHaveNoData;
9398 : }
9399 :
9400 : /************************************************************************/
9401 : /* GetMaskBand() */
9402 : /************************************************************************/
9403 :
9404 : /**
9405 : * \brief Return the mask band associated with the band.
9406 : *
9407 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9408 : * that returns one of four default implementations :
9409 : * <ul>
9410 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9411 : * </li>
9412 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9413 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9414 : * GMF_NODATA | GMF_PER_DATASET.
9415 : * </li>
9416 : * <li>If the band has a nodata value set, an instance of the new
9417 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9418 : * GMF_NODATA.
9419 : * </li>
9420 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9421 : * to apply to this band (specific rules yet to be determined) and that is of
9422 : * type GDT_UInt8 then that alpha band will be returned, and the flags
9423 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9424 : * </li>
9425 : * <li>If neither of the above apply, an instance of the new
9426 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9427 : * pixels. The null flags will return GMF_ALL_VALID.
9428 : * </li>
9429 : * </ul>
9430 : *
9431 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9432 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9433 : *
9434 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9435 : * dataset, with the same name as the main dataset and suffixed with .msk,
9436 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9437 : * main dataset.
9438 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9439 : * level, where xx matches the band number of a band of the main dataset. The
9440 : * value of those items is a combination of the flags GMF_ALL_VALID,
9441 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9442 : * a band, then the other rules explained above will be used to generate a
9443 : * on-the-fly mask band.
9444 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9445 : *
9446 : * This method is the same as the C function GDALGetMaskBand().
9447 : *
9448 : * @return a valid mask band.
9449 : *
9450 : *
9451 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9452 : *
9453 : */
9454 825158 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9455 :
9456 : {
9457 825158 : if (poMask != nullptr)
9458 : {
9459 725214 : if (poMask.IsOwned())
9460 : {
9461 337865 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9462 : {
9463 37169 : if (HasNoData())
9464 : {
9465 9 : InvalidateMaskBand();
9466 : }
9467 : }
9468 300696 : else if (auto poNoDataMaskBand =
9469 300696 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9470 : {
9471 435 : int bHaveNoDataRaw = FALSE;
9472 435 : bool bIsSame = false;
9473 435 : if (eDataType == GDT_Int64)
9474 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9475 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9476 10 : bHaveNoDataRaw;
9477 418 : else if (eDataType == GDT_UInt64)
9478 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9479 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9480 10 : bHaveNoDataRaw;
9481 : else
9482 : {
9483 : const double dfNoDataValue =
9484 401 : GetNoDataValue(&bHaveNoDataRaw);
9485 401 : if (bHaveNoDataRaw)
9486 : {
9487 398 : bIsSame =
9488 398 : std::isnan(dfNoDataValue)
9489 398 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9490 363 : : poNoDataMaskBand->m_dfNoDataValue ==
9491 : dfNoDataValue;
9492 : }
9493 : }
9494 435 : if (!bIsSame)
9495 23 : InvalidateMaskBand();
9496 : }
9497 : }
9498 :
9499 725214 : if (poMask)
9500 725182 : return poMask.get();
9501 : }
9502 :
9503 : /* -------------------------------------------------------------------- */
9504 : /* Check for a mask in a .msk file. */
9505 : /* -------------------------------------------------------------------- */
9506 99976 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9507 : {
9508 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9509 47 : if (poMask != nullptr)
9510 : {
9511 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9512 45 : return poMask.get();
9513 : }
9514 : }
9515 :
9516 : /* -------------------------------------------------------------------- */
9517 : /* Check for NODATA_VALUES metadata. */
9518 : /* -------------------------------------------------------------------- */
9519 99931 : if (poDS != nullptr)
9520 : {
9521 : const char *pszGDALNoDataValues =
9522 99911 : poDS->GetMetadataItem("NODATA_VALUES");
9523 99911 : if (pszGDALNoDataValues != nullptr)
9524 : {
9525 62 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9526 : pszGDALNoDataValues, " ", FALSE, FALSE);
9527 :
9528 : // Make sure we have as many values as bands.
9529 122 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9530 60 : poDS->GetRasterCount() != 0)
9531 : {
9532 : // Make sure that all bands have the same data type
9533 : // This is clearly not a fundamental condition, just a
9534 : // condition to make implementation easier.
9535 60 : GDALDataType eDT = GDT_Unknown;
9536 60 : int i = 0; // Used after for.
9537 236 : for (; i < poDS->GetRasterCount(); ++i)
9538 : {
9539 176 : if (i == 0)
9540 60 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9541 116 : else if (eDT !=
9542 116 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9543 : {
9544 0 : break;
9545 : }
9546 : }
9547 60 : if (i == poDS->GetRasterCount())
9548 : {
9549 60 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9550 : try
9551 : {
9552 60 : poMask.reset(
9553 120 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9554 : }
9555 0 : catch (const std::bad_alloc &)
9556 : {
9557 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9558 0 : poMask.reset();
9559 : }
9560 60 : CSLDestroy(papszGDALNoDataValues);
9561 60 : return poMask.get();
9562 : }
9563 : else
9564 : {
9565 0 : ReportError(CE_Warning, CPLE_AppDefined,
9566 : "All bands should have the same type in "
9567 : "order the NODATA_VALUES metadata item "
9568 : "to be used as a mask.");
9569 : }
9570 : }
9571 : else
9572 : {
9573 2 : ReportError(
9574 : CE_Warning, CPLE_AppDefined,
9575 : "NODATA_VALUES metadata item doesn't have the same number "
9576 : "of values as the number of bands. "
9577 : "Ignoring it for mask.");
9578 : }
9579 :
9580 2 : CSLDestroy(papszGDALNoDataValues);
9581 : }
9582 : }
9583 :
9584 : /* -------------------------------------------------------------------- */
9585 : /* Check for nodata case. */
9586 : /* -------------------------------------------------------------------- */
9587 99871 : if (HasNoData())
9588 : {
9589 1244 : nMaskFlags = GMF_NODATA;
9590 : try
9591 : {
9592 1244 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9593 : }
9594 0 : catch (const std::bad_alloc &)
9595 : {
9596 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9597 0 : poMask.reset();
9598 : }
9599 1244 : return poMask.get();
9600 : }
9601 :
9602 : /* -------------------------------------------------------------------- */
9603 : /* Check for alpha case. */
9604 : /* -------------------------------------------------------------------- */
9605 98608 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9606 197864 : this == poDS->GetRasterBand(1) &&
9607 629 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9608 : {
9609 228 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9610 : {
9611 184 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9612 184 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9613 184 : return poMask.get();
9614 : }
9615 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9616 : {
9617 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9618 : try
9619 : {
9620 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9621 46 : poDS->GetRasterBand(2)));
9622 : }
9623 0 : catch (const std::bad_alloc &)
9624 : {
9625 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9626 0 : poMask.reset();
9627 : }
9628 23 : return poMask.get();
9629 : }
9630 : }
9631 :
9632 98401 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9633 3002 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9634 197526 : this == poDS->GetRasterBand(3)) &&
9635 2334 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9636 : {
9637 1455 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9638 : {
9639 1399 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9640 1399 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9641 1399 : return poMask.get();
9642 : }
9643 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9644 : {
9645 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9646 : try
9647 : {
9648 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9649 84 : poDS->GetRasterBand(4)));
9650 : }
9651 0 : catch (const std::bad_alloc &)
9652 : {
9653 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9654 0 : poMask.reset();
9655 : }
9656 42 : return poMask.get();
9657 : }
9658 : }
9659 :
9660 : /* -------------------------------------------------------------------- */
9661 : /* Fallback to all valid case. */
9662 : /* -------------------------------------------------------------------- */
9663 96979 : nMaskFlags = GMF_ALL_VALID;
9664 : try
9665 : {
9666 96979 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9667 : }
9668 0 : catch (const std::bad_alloc &)
9669 : {
9670 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9671 0 : poMask.reset();
9672 : }
9673 :
9674 96979 : return poMask.get();
9675 : }
9676 :
9677 : /************************************************************************/
9678 : /* GDALGetMaskBand() */
9679 : /************************************************************************/
9680 :
9681 : /**
9682 : * \brief Return the mask band associated with the band.
9683 : *
9684 : * @see GDALRasterBand::GetMaskBand()
9685 : */
9686 :
9687 10997 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9688 :
9689 : {
9690 10997 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9691 :
9692 10997 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9693 10997 : return poBand->GetMaskBand();
9694 : }
9695 :
9696 : /************************************************************************/
9697 : /* GetMaskFlags() */
9698 : /************************************************************************/
9699 :
9700 : /**
9701 : * \brief Return the status flags of the mask band associated with the band.
9702 : *
9703 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9704 : * the following available definitions that may be extended in the future:
9705 : * <ul>
9706 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9707 : * 255. When used this will normally be the only flag set.
9708 : * </li>
9709 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9710 : * dataset.
9711 : * </li>
9712 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9713 : * and may have values other than 0 and 255.
9714 : * </li>
9715 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9716 : * nodata values. (mutually exclusive of GMF_ALPHA)
9717 : * </li>
9718 : * </ul>
9719 : *
9720 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9721 : * that returns one of four default implementations:
9722 : * <ul>
9723 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9724 : * </li>
9725 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9726 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9727 : * GMF_NODATA | GMF_PER_DATASET.
9728 : * </li>
9729 : * <li>If the band has a nodata value set, an instance of the new
9730 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9731 : * GMF_NODATA.
9732 : * </li>
9733 : * <li>If there is no nodata value, but the dataset has an alpha band that
9734 : * seems to apply to this band (specific rules yet to be determined) and that is
9735 : * of type GDT_UInt8 then that alpha band will be returned, and the flags
9736 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9737 : * </li>
9738 : * <li>If neither of the above apply, an instance of the new
9739 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9740 : * pixels. The null flags will return GMF_ALL_VALID.
9741 : * </li>
9742 : * </ul>
9743 : *
9744 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9745 : * dataset, with the same name as the main dataset and suffixed with .msk,
9746 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9747 : * main dataset.
9748 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9749 : * level, where xx matches the band number of a band of the main dataset. The
9750 : * value of those items is a combination of the flags GMF_ALL_VALID,
9751 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9752 : * a band, then the other rules explained above will be used to generate a
9753 : * on-the-fly mask band.
9754 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9755 : *
9756 : * This method is the same as the C function GDALGetMaskFlags().
9757 : *
9758 : *
9759 : * @return a valid mask band.
9760 : *
9761 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9762 : *
9763 : */
9764 172031 : int GDALRasterBand::GetMaskFlags()
9765 :
9766 : {
9767 : // If we don't have a band yet, force this now so that the masks value
9768 : // will be initialized.
9769 :
9770 172031 : if (poMask == nullptr)
9771 98372 : GetMaskBand();
9772 :
9773 172031 : return nMaskFlags;
9774 : }
9775 :
9776 : /************************************************************************/
9777 : /* GDALGetMaskFlags() */
9778 : /************************************************************************/
9779 :
9780 : /**
9781 : * \brief Return the status flags of the mask band associated with the band.
9782 : *
9783 : * @see GDALRasterBand::GetMaskFlags()
9784 : */
9785 :
9786 9955 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9787 :
9788 : {
9789 9955 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9790 :
9791 9955 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9792 9955 : return poBand->GetMaskFlags();
9793 : }
9794 :
9795 : /************************************************************************/
9796 : /* InvalidateMaskBand() */
9797 : /************************************************************************/
9798 :
9799 : //! @cond Doxygen_Suppress
9800 1871040 : void GDALRasterBand::InvalidateMaskBand()
9801 : {
9802 1871040 : poMask.reset();
9803 1871040 : nMaskFlags = 0;
9804 1871040 : }
9805 :
9806 : //! @endcond
9807 :
9808 : /************************************************************************/
9809 : /* CreateMaskBand() */
9810 : /************************************************************************/
9811 :
9812 : /**
9813 : * \brief Adds a mask band to the current band
9814 : *
9815 : * The default implementation of the CreateMaskBand() method is implemented
9816 : * based on similar rules to the .ovr handling implemented using the
9817 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9818 : * be created with the same basename as the original file, and it will have
9819 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9820 : * The mask images will be deflate compressed tiled images with the same
9821 : * block size as the original image if possible.
9822 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9823 : * level, where xx matches the band number of a band of the main dataset. The
9824 : * value of those items will be the one of the nFlagsIn parameter.
9825 : *
9826 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9827 : * it might be invalidated by CreateMaskBand(). So you have to call
9828 : * GetMaskBand() again.
9829 : *
9830 : * This method is the same as the C function GDALCreateMaskBand().
9831 : *
9832 : *
9833 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9834 : *
9835 : * @return CE_None on success or CE_Failure on an error.
9836 : *
9837 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9838 : * @see GDALDataset::CreateMaskBand()
9839 : *
9840 : */
9841 :
9842 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9843 :
9844 : {
9845 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9846 : {
9847 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9848 10 : if (eErr != CE_None)
9849 1 : return eErr;
9850 :
9851 9 : InvalidateMaskBand();
9852 :
9853 9 : return CE_None;
9854 : }
9855 :
9856 0 : ReportError(CE_Failure, CPLE_NotSupported,
9857 : "CreateMaskBand() not supported for this band.");
9858 :
9859 0 : return CE_Failure;
9860 : }
9861 :
9862 : /************************************************************************/
9863 : /* GDALCreateMaskBand() */
9864 : /************************************************************************/
9865 :
9866 : /**
9867 : * \brief Adds a mask band to the current band
9868 : *
9869 : * @see GDALRasterBand::CreateMaskBand()
9870 : */
9871 :
9872 36 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9873 :
9874 : {
9875 36 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9876 :
9877 36 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9878 36 : return poBand->CreateMaskBand(nFlags);
9879 : }
9880 :
9881 : /************************************************************************/
9882 : /* IsMaskBand() */
9883 : /************************************************************************/
9884 :
9885 : /**
9886 : * \brief Returns whether a band is a mask band.
9887 : *
9888 : * Mask band must be understood in the broad term: it can be a per-dataset
9889 : * mask band, an alpha band, or an implicit mask band.
9890 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9891 : *
9892 : * This method is the same as the C function GDALIsMaskBand().
9893 : *
9894 : * @return true if the band is a mask band.
9895 : *
9896 : * @see GDALDataset::CreateMaskBand()
9897 : *
9898 : * @since GDAL 3.5.0
9899 : *
9900 : */
9901 :
9902 303 : bool GDALRasterBand::IsMaskBand() const
9903 : {
9904 : // The GeoTIFF driver, among others, override this method to
9905 : // also handle external .msk bands.
9906 303 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9907 303 : GCI_AlphaBand;
9908 : }
9909 :
9910 : /************************************************************************/
9911 : /* GDALIsMaskBand() */
9912 : /************************************************************************/
9913 :
9914 : /**
9915 : * \brief Returns whether a band is a mask band.
9916 : *
9917 : * Mask band must be understood in the broad term: it can be a per-dataset
9918 : * mask band, an alpha band, or an implicit mask band.
9919 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9920 : *
9921 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9922 : *
9923 : * @return true if the band is a mask band.
9924 : *
9925 : * @see GDALRasterBand::IsMaskBand()
9926 : *
9927 : * @since GDAL 3.5.0
9928 : *
9929 : */
9930 :
9931 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9932 :
9933 : {
9934 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9935 :
9936 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9937 37 : return poBand->IsMaskBand();
9938 : }
9939 :
9940 : /************************************************************************/
9941 : /* GetMaskValueRange() */
9942 : /************************************************************************/
9943 :
9944 : /**
9945 : * \brief Returns the range of values that a mask band can take.
9946 : *
9947 : * @return the range of values that a mask band can take.
9948 : *
9949 : * @since GDAL 3.5.0
9950 : *
9951 : */
9952 :
9953 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9954 : {
9955 0 : return GMVR_UNKNOWN;
9956 : }
9957 :
9958 : /************************************************************************/
9959 : /* HasConflictingMaskSources() */
9960 : /************************************************************************/
9961 :
9962 : /**
9963 : * \brief Returns whether a raster band has conflicting mask sources.
9964 : *
9965 : * That is, if more than one of the following conditions is met:
9966 : * - it has a binary mask band (that is not an alpha band)
9967 : * - it has an external mask flags (.msk file)
9968 : * - it has a nodata value
9969 : * - it belongs to a dataset with the NODATA_VALUES metadata item set
9970 : * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
9971 : *
9972 : * @param[out] posDetailMessage Pointer to a string that will contain the
9973 : * details of the conflict.
9974 : * @param bMentionPrioritarySource Whether the mask source used should be
9975 : * mentioned in *posDetailMessage.
9976 : * @since GDAL 3.13.0
9977 : */
9978 :
9979 124 : bool GDALRasterBand::HasConflictingMaskSources(
9980 : std::string *posDetailMessage, bool bMentionPrioritarySource) const
9981 : {
9982 124 : const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
9983 : const bool bHasBinaryMaskBand =
9984 124 : ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
9985 146 : (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
9986 22 : (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
9987 124 : const bool bHasNoData = HasNoData();
9988 : const bool bHasNODATA_VALUES =
9989 124 : poDS && poDS->GetMetadataItem("NODATA_VALUES");
9990 : const bool bHasAlphaBand =
9991 244 : poDS &&
9992 120 : poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
9993 124 : GCI_AlphaBand;
9994 : const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
9995 124 : bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
9996 : const size_t nCount =
9997 124 : std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
9998 124 : if (nCount >= 2)
9999 : {
10000 23 : if (posDetailMessage)
10001 : {
10002 17 : *posDetailMessage = "Raster band ";
10003 17 : *posDetailMessage += std::to_string(nBand);
10004 17 : if (poDS && poDS->GetDescription()[0])
10005 : {
10006 11 : *posDetailMessage += " of dataset ";
10007 11 : *posDetailMessage += poDS->GetDescription();
10008 : }
10009 17 : *posDetailMessage += " has several conflicting mask sources:\n";
10010 17 : if (bHasExternalMask)
10011 1 : *posDetailMessage += "- internal binary mask band\n";
10012 17 : if (bHasExternalMask)
10013 1 : *posDetailMessage += "- external mask band (.msk)\n";
10014 17 : if (bHasNoData)
10015 13 : *posDetailMessage += "- nodata value\n";
10016 17 : if (bHasNODATA_VALUES)
10017 9 : *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
10018 17 : if (bHasAlphaBand)
10019 : *posDetailMessage +=
10020 7 : "- related to a raster band that is an alpha band\n";
10021 17 : if (bMentionPrioritarySource)
10022 : *posDetailMessage +=
10023 6 : "Only the first listed one will be taken into account.";
10024 : }
10025 23 : return true;
10026 : }
10027 101 : return false;
10028 : }
10029 :
10030 : /************************************************************************/
10031 : /* GetIndexColorTranslationTo() */
10032 : /************************************************************************/
10033 :
10034 : /**
10035 : * \brief Compute translation table for color tables.
10036 : *
10037 : * When the raster band has a palette index, it may be useful to compute
10038 : * the "translation" of this palette to the palette of another band.
10039 : * The translation tries to do exact matching first, and then approximate
10040 : * matching if no exact matching is possible.
10041 : * This method returns a table such that table[i] = j where i is an index
10042 : * of the 'this' rasterband and j the corresponding index for the reference
10043 : * rasterband.
10044 : *
10045 : * This method is thought as internal to GDAL and is used for drivers
10046 : * like RPFTOC.
10047 : *
10048 : * The implementation only supports 1-byte palette rasterbands.
10049 : *
10050 : * @param poReferenceBand the raster band
10051 : * @param pTranslationTable an already allocated translation table (at least 256
10052 : * bytes), or NULL to let the method allocate it
10053 : * @param pApproximateMatching a pointer to a flag that is set if the matching
10054 : * is approximate. May be NULL.
10055 : *
10056 : * @return a translation table if the two bands are palette index and that they
10057 : * do not match or NULL in other cases. The table must be freed with CPLFree if
10058 : * NULL was passed for pTranslationTable.
10059 : */
10060 :
10061 : unsigned char *
10062 5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
10063 : unsigned char *pTranslationTable,
10064 : int *pApproximateMatching)
10065 : {
10066 5 : if (poReferenceBand == nullptr)
10067 0 : return nullptr;
10068 :
10069 : // cppcheck-suppress knownConditionTrueFalse
10070 5 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
10071 : // cppcheck-suppress knownConditionTrueFalse
10072 5 : GetColorInterpretation() == GCI_PaletteIndex &&
10073 15 : poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
10074 5 : GetRasterDataType() == GDT_UInt8)
10075 : {
10076 5 : const GDALColorTable *srcColorTable = GetColorTable();
10077 5 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
10078 5 : if (srcColorTable != nullptr && destColorTable != nullptr)
10079 : {
10080 5 : const int nEntries = srcColorTable->GetColorEntryCount();
10081 5 : const int nRefEntries = destColorTable->GetColorEntryCount();
10082 :
10083 5 : int bHasNoDataValueSrc = FALSE;
10084 5 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
10085 5 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
10086 5 : dfNoDataValueSrc <= 255 &&
10087 5 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
10088 0 : bHasNoDataValueSrc = FALSE;
10089 5 : const int noDataValueSrc =
10090 5 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
10091 :
10092 5 : int bHasNoDataValueRef = FALSE;
10093 : const double dfNoDataValueRef =
10094 5 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
10095 5 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
10096 4 : dfNoDataValueRef <= 255 &&
10097 4 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
10098 1 : bHasNoDataValueRef = FALSE;
10099 5 : const int noDataValueRef =
10100 5 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
10101 :
10102 5 : bool samePalette = false;
10103 :
10104 5 : if (pApproximateMatching)
10105 4 : *pApproximateMatching = FALSE;
10106 :
10107 5 : if (nEntries == nRefEntries &&
10108 4 : bHasNoDataValueSrc == bHasNoDataValueRef &&
10109 4 : (bHasNoDataValueSrc == FALSE ||
10110 : noDataValueSrc == noDataValueRef))
10111 : {
10112 4 : samePalette = true;
10113 872 : for (int i = 0; i < nEntries; ++i)
10114 : {
10115 868 : if (noDataValueSrc == i)
10116 4 : continue;
10117 : const GDALColorEntry *entry =
10118 864 : srcColorTable->GetColorEntry(i);
10119 : const GDALColorEntry *entryRef =
10120 864 : destColorTable->GetColorEntry(i);
10121 864 : if (entry->c1 != entryRef->c1 ||
10122 864 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
10123 : {
10124 0 : samePalette = false;
10125 : }
10126 : }
10127 : }
10128 :
10129 5 : if (!samePalette)
10130 : {
10131 1 : if (pTranslationTable == nullptr)
10132 : {
10133 : pTranslationTable = static_cast<unsigned char *>(
10134 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
10135 1 : if (pTranslationTable == nullptr)
10136 1 : return nullptr;
10137 : }
10138 :
10139 : // Trying to remap the product palette on the subdataset
10140 : // palette.
10141 5 : for (int i = 0; i < nEntries; ++i)
10142 : {
10143 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
10144 : noDataValueSrc == i)
10145 0 : continue;
10146 : const GDALColorEntry *entry =
10147 4 : srcColorTable->GetColorEntry(i);
10148 4 : bool bMatchFound = false;
10149 13 : for (int j = 0; j < nRefEntries; ++j)
10150 : {
10151 10 : if (bHasNoDataValueRef && noDataValueRef == j)
10152 0 : continue;
10153 : const GDALColorEntry *entryRef =
10154 10 : destColorTable->GetColorEntry(j);
10155 10 : if (entry->c1 == entryRef->c1 &&
10156 2 : entry->c2 == entryRef->c2 &&
10157 2 : entry->c3 == entryRef->c3)
10158 : {
10159 1 : pTranslationTable[i] =
10160 : static_cast<unsigned char>(j);
10161 1 : bMatchFound = true;
10162 1 : break;
10163 : }
10164 : }
10165 4 : if (!bMatchFound)
10166 : {
10167 : // No exact match. Looking for closest color now.
10168 3 : int best_j = 0;
10169 3 : int best_distance = 0;
10170 3 : if (pApproximateMatching)
10171 0 : *pApproximateMatching = TRUE;
10172 12 : for (int j = 0; j < nRefEntries; ++j)
10173 : {
10174 : const GDALColorEntry *entryRef =
10175 9 : destColorTable->GetColorEntry(j);
10176 9 : int distance = (entry->c1 - entryRef->c1) *
10177 9 : (entry->c1 - entryRef->c1) +
10178 9 : (entry->c2 - entryRef->c2) *
10179 9 : (entry->c2 - entryRef->c2) +
10180 9 : (entry->c3 - entryRef->c3) *
10181 9 : (entry->c3 - entryRef->c3);
10182 9 : if (j == 0 || distance < best_distance)
10183 : {
10184 7 : best_j = j;
10185 7 : best_distance = distance;
10186 : }
10187 : }
10188 3 : pTranslationTable[i] =
10189 : static_cast<unsigned char>(best_j);
10190 : }
10191 : }
10192 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
10193 0 : pTranslationTable[noDataValueSrc] =
10194 : static_cast<unsigned char>(noDataValueRef);
10195 :
10196 1 : return pTranslationTable;
10197 : }
10198 : }
10199 : }
10200 4 : return nullptr;
10201 : }
10202 :
10203 : /************************************************************************/
10204 : /* SetFlushBlockErr() */
10205 : /************************************************************************/
10206 :
10207 : /**
10208 : * \brief Store that an error occurred while writing a dirty block.
10209 : *
10210 : * This function stores the fact that an error occurred while writing a dirty
10211 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
10212 : * flushed when the block cache get full, it is not convenient/possible to
10213 : * report that a dirty block could not be written correctly. This function
10214 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
10215 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
10216 : * places where the user can easily match the error with the relevant dataset.
10217 : */
10218 :
10219 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
10220 : {
10221 0 : eFlushBlockErr = eErr;
10222 0 : }
10223 :
10224 : /************************************************************************/
10225 : /* IncDirtyBlocks() */
10226 : /************************************************************************/
10227 :
10228 : /**
10229 : * \brief Increment/decrement the number of dirty blocks
10230 : */
10231 :
10232 815921 : void GDALRasterBand::IncDirtyBlocks(int nInc)
10233 : {
10234 815921 : if (poBandBlockCache)
10235 815921 : poBandBlockCache->IncDirtyBlocks(nInc);
10236 815921 : }
10237 :
10238 : /************************************************************************/
10239 : /* ReportError() */
10240 : /************************************************************************/
10241 :
10242 : #ifndef DOXYGEN_XML
10243 : /**
10244 : * \brief Emits an error related to a raster band.
10245 : *
10246 : * This function is a wrapper for regular CPLError(). The only difference
10247 : * with CPLError() is that it prepends the error message with the dataset
10248 : * name and the band number.
10249 : *
10250 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
10251 : * @param err_no the error number (CPLE_*) from cpl_error.h.
10252 : * @param fmt a printf() style format string. Any additional arguments
10253 : * will be treated as arguments to fill in this format in a manner
10254 : * similar to printf().
10255 : *
10256 : */
10257 :
10258 2501 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
10259 : const char *fmt, ...) const
10260 : {
10261 : va_list args;
10262 :
10263 2501 : va_start(args, fmt);
10264 :
10265 2501 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
10266 2501 : pszDSName = CPLGetFilename(pszDSName);
10267 2501 : if (pszDSName[0] != '\0')
10268 : {
10269 2408 : CPLError(eErrClass, err_no, "%s",
10270 4816 : CPLString()
10271 2408 : .Printf("%s, band %d: ", pszDSName, GetBand())
10272 4816 : .append(CPLString().vPrintf(fmt, args))
10273 : .c_str());
10274 : }
10275 : else
10276 : {
10277 93 : CPLErrorV(eErrClass, err_no, fmt, args);
10278 : }
10279 :
10280 2501 : va_end(args);
10281 2501 : }
10282 : #endif
10283 :
10284 : /************************************************************************/
10285 : /* GetVirtualMemAuto() */
10286 : /************************************************************************/
10287 :
10288 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
10289 : *
10290 : * Only supported on Linux and Unix systems with mmap() for now.
10291 : *
10292 : * This method allows creating a virtual memory object for a GDALRasterBand,
10293 : * that exposes the whole image data as a virtual array.
10294 : *
10295 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
10296 : * specialized implementation, such as for raw files, may also directly use
10297 : * mechanisms of the operating system to create a view of the underlying file
10298 : * into virtual memory ( CPLVirtualMemFileMapNew() )
10299 : *
10300 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
10301 : * offer a specialized implementation with direct file mapping, provided that
10302 : * some requirements are met :
10303 : * - for all drivers, the dataset must be backed by a "real" file in the file
10304 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
10305 : * must match the native ordering of the CPU.
10306 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
10307 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
10308 : * the file in sequential order, and be equally spaced (which is generally the
10309 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
10310 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
10311 : *
10312 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
10313 : * CPLVirtualMemFree() must be called before the raster band object is
10314 : * destroyed.
10315 : *
10316 : * If p is such a pointer and base_type the type matching
10317 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
10318 : * accessed with
10319 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
10320 : *
10321 : * This method is the same as the C GDALGetVirtualMemAuto() function.
10322 : *
10323 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
10324 : * read/write the band.
10325 : *
10326 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
10327 : * one pixel value in the buffer to the start of the next pixel value within a
10328 : * scanline.
10329 : *
10330 : * @param pnLineSpace Output parameter giving the byte offset from the start of
10331 : * one scanline in the buffer to the start of the next.
10332 : *
10333 : * @param papszOptions NULL terminated list of options.
10334 : * If a specialized implementation exists, defining
10335 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
10336 : * used. On the contrary, defining
10337 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
10338 : * being used (thus only allowing efficient implementations to be used). When
10339 : * requiring or falling back to the default implementation, the following
10340 : * options are available : CACHE_SIZE (in bytes, defaults to
10341 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
10342 : * to FALSE)
10343 : *
10344 : * @return a virtual memory object that must be unreferenced by
10345 : * CPLVirtualMemFree(), or NULL in case of failure.
10346 : *
10347 : */
10348 :
10349 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
10350 : int *pnPixelSpace,
10351 : GIntBig *pnLineSpace,
10352 : CSLConstList papszOptions)
10353 : {
10354 9 : const char *pszImpl = CSLFetchNameValueDef(
10355 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
10356 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
10357 8 : EQUAL(pszImpl, "FALSE"))
10358 : {
10359 1 : return nullptr;
10360 : }
10361 :
10362 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
10363 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
10364 8 : if (pnPixelSpace)
10365 8 : *pnPixelSpace = nPixelSpace;
10366 8 : if (pnLineSpace)
10367 8 : *pnLineSpace = nLineSpace;
10368 : const size_t nCacheSize =
10369 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
10370 : const size_t nPageSizeHint =
10371 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
10372 8 : const bool bSingleThreadUsage = CPLTestBool(
10373 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
10374 8 : return GDALRasterBandGetVirtualMem(
10375 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
10376 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
10377 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
10378 8 : papszOptions);
10379 : }
10380 :
10381 : /************************************************************************/
10382 : /* GDALGetVirtualMemAuto() */
10383 : /************************************************************************/
10384 :
10385 : /**
10386 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
10387 : *
10388 : * @see GDALRasterBand::GetVirtualMemAuto()
10389 : */
10390 :
10391 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
10392 : int *pnPixelSpace, GIntBig *pnLineSpace,
10393 : CSLConstList papszOptions)
10394 : {
10395 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
10396 :
10397 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10398 :
10399 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
10400 31 : const_cast<char **>(papszOptions));
10401 : }
10402 :
10403 : /************************************************************************/
10404 : /* GDALGetDataCoverageStatus() */
10405 : /************************************************************************/
10406 :
10407 : /**
10408 : * \brief Get the coverage status of a sub-window of the raster.
10409 : *
10410 : * Returns whether a sub-window of the raster contains only data, only empty
10411 : * blocks or a mix of both. This function can be used to determine quickly
10412 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10413 : * be sparse.
10414 : *
10415 : * Empty blocks are blocks that are generally not physically present in the
10416 : * file, and when read through GDAL, contain only pixels whose value is the
10417 : * nodata value when it is set, or whose value is 0 when the nodata value is
10418 : * not set.
10419 : *
10420 : * The query is done in an efficient way without reading the actual pixel
10421 : * values. If not possible, or not implemented at all by the driver,
10422 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10423 : * be returned.
10424 : *
10425 : * The values that can be returned by the function are the following,
10426 : * potentially combined with the binary or operator :
10427 : * <ul>
10428 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10429 : * GetDataCoverageStatus(). This flag should be returned together with
10430 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10431 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10432 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10433 : * the queried window. This is typically identified by the concept of missing
10434 : * block in formats that supports it.
10435 : * </li>
10436 : * </ul>
10437 : *
10438 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10439 : * should be interpreted more as hint of potential presence of data. For example
10440 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10441 : * nodata value), instead of using the missing block mechanism,
10442 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10443 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10444 : *
10445 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10446 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10447 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10448 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10449 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10450 : * the function will exit, so that you can potentially refine the requested area
10451 : * to find which particular region(s) have missing blocks.
10452 : *
10453 : * @see GDALRasterBand::GetDataCoverageStatus()
10454 : *
10455 : * @param hBand raster band
10456 : *
10457 : * @param nXOff The pixel offset to the top left corner of the region
10458 : * of the band to be queried. This would be zero to start from the left side.
10459 : *
10460 : * @param nYOff The line offset to the top left corner of the region
10461 : * of the band to be queried. This would be zero to start from the top.
10462 : *
10463 : * @param nXSize The width of the region of the band to be queried in pixels.
10464 : *
10465 : * @param nYSize The height of the region of the band to be queried in lines.
10466 : *
10467 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10468 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10469 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10470 : * as the computation of the coverage matches the mask, the computation will be
10471 : * stopped. *pdfDataPct will not be valid in that case.
10472 : *
10473 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10474 : * to the (approximate) percentage in [0,100] of pixels in the queried
10475 : * sub-window that have valid values. The implementation might not always be
10476 : * able to compute it, in which case it will be set to a negative value.
10477 : *
10478 : * @return a binary-or'ed combination of possible values
10479 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10480 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10481 : */
10482 :
10483 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10484 : int nYOff, int nXSize, int nYSize,
10485 : int nMaskFlagStop, double *pdfDataPct)
10486 : {
10487 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10488 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10489 :
10490 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10491 :
10492 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10493 29 : nMaskFlagStop, pdfDataPct);
10494 : }
10495 :
10496 : /************************************************************************/
10497 : /* GetDataCoverageStatus() */
10498 : /************************************************************************/
10499 :
10500 : /**
10501 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10502 : * int nYOff,
10503 : * int nXSize,
10504 : * int nYSize,
10505 : * int nMaskFlagStop,
10506 : * double* pdfDataPct)
10507 : * \brief Get the coverage status of a sub-window of the raster.
10508 : *
10509 : * Returns whether a sub-window of the raster contains only data, only empty
10510 : * blocks or a mix of both. This function can be used to determine quickly
10511 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10512 : * be sparse.
10513 : *
10514 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10515 : * value when it is set, or whose value is 0 when the nodata value is not set.
10516 : *
10517 : * The query is done in an efficient way without reading the actual pixel
10518 : * values. If not possible, or not implemented at all by the driver,
10519 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10520 : * be returned.
10521 : *
10522 : * The values that can be returned by the function are the following,
10523 : * potentially combined with the binary or operator :
10524 : * <ul>
10525 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10526 : * GetDataCoverageStatus(). This flag should be returned together with
10527 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10528 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10529 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10530 : * the queried window. This is typically identified by the concept of missing
10531 : * block in formats that supports it.
10532 : * </li>
10533 : * </ul>
10534 : *
10535 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10536 : * should be interpreted more as hint of potential presence of data. For example
10537 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10538 : * nodata value), instead of using the missing block mechanism,
10539 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10540 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10541 : *
10542 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10543 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10544 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10545 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10546 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10547 : * the function will exit, so that you can potentially refine the requested area
10548 : * to find which particular region(s) have missing blocks.
10549 : *
10550 : * @see GDALGetDataCoverageStatus()
10551 : *
10552 : * @param nXOff The pixel offset to the top left corner of the region
10553 : * of the band to be queried. This would be zero to start from the left side.
10554 : *
10555 : * @param nYOff The line offset to the top left corner of the region
10556 : * of the band to be queried. This would be zero to start from the top.
10557 : *
10558 : * @param nXSize The width of the region of the band to be queried in pixels.
10559 : *
10560 : * @param nYSize The height of the region of the band to be queried in lines.
10561 : *
10562 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10563 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10564 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10565 : * as the computation of the coverage matches the mask, the computation will be
10566 : * stopped. *pdfDataPct will not be valid in that case.
10567 : *
10568 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10569 : * to the (approximate) percentage in [0,100] of pixels in the queried
10570 : * sub-window that have valid values. The implementation might not always be
10571 : * able to compute it, in which case it will be set to a negative value.
10572 : *
10573 : * @return a binary-or'ed combination of possible values
10574 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10575 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10576 : */
10577 :
10578 : /**
10579 : * \brief Get the coverage status of a sub-window of the raster.
10580 : *
10581 : * Returns whether a sub-window of the raster contains only data, only empty
10582 : * blocks or a mix of both. This function can be used to determine quickly
10583 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10584 : * be sparse.
10585 : *
10586 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10587 : * value when it is set, or whose value is 0 when the nodata value is not set.
10588 : *
10589 : * The query is done in an efficient way without reading the actual pixel
10590 : * values. If not possible, or not implemented at all by the driver,
10591 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10592 : * be returned.
10593 : *
10594 : * The values that can be returned by the function are the following,
10595 : * potentially combined with the binary or operator :
10596 : * <ul>
10597 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10598 : * GetDataCoverageStatus(). This flag should be returned together with
10599 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10600 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10601 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10602 : * the queried window. This is typically identified by the concept of missing
10603 : * block in formats that supports it.
10604 : * </li>
10605 : * </ul>
10606 : *
10607 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10608 : * should be interpreted more as hint of potential presence of data. For example
10609 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10610 : * nodata value), instead of using the missing block mechanism,
10611 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10612 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10613 : *
10614 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10615 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10616 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10617 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10618 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10619 : * the function will exit, so that you can potentially refine the requested area
10620 : * to find which particular region(s) have missing blocks.
10621 : *
10622 : * @see GDALGetDataCoverageStatus()
10623 : *
10624 : * @param nXOff The pixel offset to the top left corner of the region
10625 : * of the band to be queried. This would be zero to start from the left side.
10626 : *
10627 : * @param nYOff The line offset to the top left corner of the region
10628 : * of the band to be queried. This would be zero to start from the top.
10629 : *
10630 : * @param nXSize The width of the region of the band to be queried in pixels.
10631 : *
10632 : * @param nYSize The height of the region of the band to be queried in lines.
10633 : *
10634 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10635 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10636 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10637 : * as the computation of the coverage matches the mask, the computation will be
10638 : * stopped. *pdfDataPct will not be valid in that case.
10639 : *
10640 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10641 : * to the (approximate) percentage in [0,100] of pixels in the queried
10642 : * sub-window that have valid values. The implementation might not always be
10643 : * able to compute it, in which case it will be set to a negative value.
10644 : *
10645 : * @return a binary-or'ed combination of possible values
10646 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10647 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10648 : */
10649 :
10650 4753 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10651 : int nYSize, int nMaskFlagStop,
10652 : double *pdfDataPct)
10653 : {
10654 4753 : if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
10655 4753 : nYSize > nRasterYSize - nYOff)
10656 : {
10657 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10658 0 : if (pdfDataPct)
10659 0 : *pdfDataPct = 0.0;
10660 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10661 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10662 : }
10663 4753 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10664 4753 : pdfDataPct);
10665 : }
10666 :
10667 : /************************************************************************/
10668 : /* IGetDataCoverageStatus() */
10669 : /************************************************************************/
10670 :
10671 692 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10672 : int /*nXSize*/, int /*nYSize*/,
10673 : int /*nMaskFlagStop*/,
10674 : double *pdfDataPct)
10675 : {
10676 692 : if (pdfDataPct != nullptr)
10677 0 : *pdfDataPct = 100.0;
10678 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10679 692 : GDAL_DATA_COVERAGE_STATUS_DATA;
10680 : }
10681 :
10682 : //! @cond Doxygen_Suppress
10683 : /************************************************************************/
10684 : /* EnterReadWrite() */
10685 : /************************************************************************/
10686 :
10687 8059500 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10688 : {
10689 8059500 : if (poDS != nullptr)
10690 7290940 : return poDS->EnterReadWrite(eRWFlag);
10691 768558 : return FALSE;
10692 : }
10693 :
10694 : /************************************************************************/
10695 : /* LeaveReadWrite() */
10696 : /************************************************************************/
10697 :
10698 1145470 : void GDALRasterBand::LeaveReadWrite()
10699 : {
10700 1145470 : if (poDS != nullptr)
10701 1145470 : poDS->LeaveReadWrite();
10702 1145470 : }
10703 :
10704 : /************************************************************************/
10705 : /* InitRWLock() */
10706 : /************************************************************************/
10707 :
10708 3989040 : void GDALRasterBand::InitRWLock()
10709 : {
10710 3989040 : if (poDS != nullptr)
10711 3988630 : poDS->InitRWLock();
10712 3989040 : }
10713 :
10714 : //! @endcond
10715 :
10716 : // clang-format off
10717 :
10718 : /**
10719 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10720 : * \brief Set metadata.
10721 : *
10722 : * CAUTION: depending on the format, older values of the updated information
10723 : * might still be found in the file in a "ghost" state, even if no longer
10724 : * accessible through the GDAL API. This is for example the case of the GTiff
10725 : * format (this is not a exhaustive list)
10726 : *
10727 : * The C function GDALSetMetadata() does the same thing as this method.
10728 : *
10729 : * @param papszMetadata the metadata in name=value string list format to
10730 : * apply.
10731 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10732 : * domain.
10733 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10734 : * metadata has been accepted, but is likely not maintained persistently
10735 : * by the underlying object between sessions.
10736 : */
10737 :
10738 : /**
10739 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10740 : * \brief Set single metadata item.
10741 : *
10742 : * CAUTION: depending on the format, older values of the updated information
10743 : * might still be found in the file in a "ghost" state, even if no longer
10744 : * accessible through the GDAL API. This is for example the case of the GTiff
10745 : * format (this is not a exhaustive list)
10746 : *
10747 : * The C function GDALSetMetadataItem() does the same thing as this method.
10748 : *
10749 : * @param pszName the key for the metadata item to fetch.
10750 : * @param pszValue the value to assign to the key.
10751 : * @param pszDomain the domain to set within, use NULL for the default domain.
10752 : *
10753 : * @return CE_None on success, or an error code on failure.
10754 : */
10755 :
10756 : // clang-format on
10757 :
10758 : //! @cond Doxygen_Suppress
10759 : /************************************************************************/
10760 : /* EnablePixelTypeSignedByteWarning() */
10761 : /************************************************************************/
10762 :
10763 157817 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10764 : {
10765 157817 : m_bEnablePixelTypeSignedByteWarning = b;
10766 157817 : }
10767 :
10768 4882 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10769 : {
10770 4882 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10771 4882 : }
10772 :
10773 : //! @endcond
10774 :
10775 : /************************************************************************/
10776 : /* GetMetadataItem() */
10777 : /************************************************************************/
10778 :
10779 633712 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10780 : const char *pszDomain)
10781 : {
10782 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10783 633712 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10784 474300 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10785 333559 : EQUAL(pszName, "PIXELTYPE"))
10786 : {
10787 2 : CPLError(CE_Warning, CPLE_AppDefined,
10788 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10789 : "used to signal signed 8-bit raster. Change your code to "
10790 : "test for the new GDT_Int8 data type instead.");
10791 : }
10792 633712 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10793 : }
10794 :
10795 : /************************************************************************/
10796 : /* GDALRasterBandAsMDArray() */
10797 : /************************************************************************/
10798 :
10799 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10800 : *
10801 : * The band must be linked to a GDALDataset. If this dataset is not already
10802 : * marked as shared, it will be, so that the returned array holds a reference
10803 : * to it.
10804 : *
10805 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10806 : * returned array will have an associated indexing variable.
10807 : *
10808 : * The returned pointer must be released with GDALMDArrayRelease().
10809 : *
10810 : * This is the same as the C++ method GDALRasterBand::AsMDArray().
10811 : *
10812 : * @return a new array, or NULL.
10813 : *
10814 : * @since GDAL 3.1
10815 : */
10816 25 : GDALMDArrayH GDALRasterBandAsMDArray(GDALRasterBandH hBand)
10817 : {
10818 25 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10819 50 : auto poArray(GDALRasterBand::FromHandle(hBand)->AsMDArray());
10820 25 : if (!poArray)
10821 0 : return nullptr;
10822 25 : return new GDALMDArrayHS(poArray);
10823 : }
10824 :
10825 : /************************************************************************/
10826 : /* WindowIterator */
10827 : /************************************************************************/
10828 :
10829 : //! @cond Doxygen_Suppress
10830 :
10831 696 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10832 : int nRasterYSize,
10833 : int nBlockXSize, int nBlockYSize,
10834 696 : int nRow, int nCol)
10835 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10836 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10837 696 : m_col(nCol)
10838 : {
10839 696 : }
10840 :
10841 751 : bool GDALRasterBand::WindowIterator::operator==(
10842 : const WindowIterator &other) const
10843 : {
10844 310 : return m_row == other.m_row && m_col == other.m_col &&
10845 310 : m_nRasterXSize == other.m_nRasterXSize &&
10846 310 : m_nRasterYSize == other.m_nRasterYSize &&
10847 1371 : m_nBlockXSize == other.m_nBlockXSize &&
10848 1061 : m_nBlockYSize == other.m_nBlockYSize;
10849 : }
10850 :
10851 727 : bool GDALRasterBand::WindowIterator::operator!=(
10852 : const WindowIterator &other) const
10853 : {
10854 727 : return !(*this == other);
10855 : }
10856 :
10857 : GDALRasterBand::WindowIterator::value_type
10858 440 : GDALRasterBand::WindowIterator::operator*() const
10859 : {
10860 : GDALRasterWindow ret;
10861 440 : ret.nXOff = m_col * m_nBlockXSize;
10862 440 : ret.nYOff = m_row * m_nBlockYSize;
10863 440 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10864 440 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10865 :
10866 440 : return ret;
10867 : }
10868 :
10869 431 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10870 : {
10871 431 : m_col++;
10872 431 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10873 : {
10874 335 : m_col = 0;
10875 335 : m_row++;
10876 : }
10877 431 : return *this;
10878 : }
10879 :
10880 163 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10881 163 : const GDALRasterBand &band, size_t maxSize)
10882 163 : : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
10883 163 : band.nBlockYSize, maxSize)
10884 : {
10885 163 : }
10886 :
10887 201 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10888 201 : const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
10889 201 : : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
10890 201 : std::min(band1.GetYSize(), band2.GetYSize()),
10891 201 : std::lcm(band1.nBlockXSize, band2.nBlockXSize),
10892 201 : std::lcm(band1.nBlockYSize, band2.nBlockYSize),
10893 603 : maxSize)
10894 : {
10895 402 : if (band1.GetXSize() != band2.GetXSize() ||
10896 201 : band1.GetYSize() != band2.GetYSize())
10897 : {
10898 0 : CPLError(CE_Warning, CPLE_AppDefined,
10899 : "WindowIteratorWrapper called on bands of different "
10900 : "dimensions. Selecting smallest one");
10901 : }
10902 201 : }
10903 :
10904 364 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
10905 : int nRasterYSize,
10906 : int nBlockXSize,
10907 : int nBlockYSize,
10908 364 : size_t maxSize)
10909 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10910 364 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
10911 : {
10912 : #ifdef CSA_BUILD
10913 : assert(this);
10914 : #endif
10915 364 : int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
10916 364 : int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
10917 :
10918 364 : if (nXSize < 1 || nYSize < 1)
10919 : {
10920 : // If invalid block size is reported, assume scanlines
10921 8 : nXSize = m_nRasterXSize;
10922 8 : nYSize = 1;
10923 : }
10924 :
10925 364 : if (maxSize == 0)
10926 : {
10927 69 : m_nBlockXSize = nXSize;
10928 69 : m_nBlockYSize = nYSize;
10929 69 : return;
10930 : }
10931 :
10932 295 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10933 295 : const double dfBlocksPerChunk =
10934 295 : static_cast<double>(maxSize) /
10935 295 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10936 :
10937 295 : if (dfBlocksPerChunk < dfBlocksPerRow)
10938 : {
10939 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10940 14 : m_nRasterXSize,
10941 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10942 14 : m_nBlockYSize = nYSize;
10943 : }
10944 : else
10945 : {
10946 281 : m_nBlockXSize = m_nRasterXSize;
10947 281 : m_nBlockYSize = static_cast<int>(std::min<double>(
10948 281 : m_nRasterYSize,
10949 281 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10950 : }
10951 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10952 : {
10953 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10954 : {
10955 : m_nBlockXSize = m_nRasterXSize;
10956 : m_nBlockYSize = 1;
10957 : }
10958 : }
10959 : }
10960 :
10961 : GDALRasterBand::WindowIterator
10962 333 : GDALRasterBand::WindowIteratorWrapper::begin() const
10963 : {
10964 333 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10965 333 : m_nBlockYSize, 0, 0);
10966 : }
10967 :
10968 : GDALRasterBand::WindowIterator
10969 333 : GDALRasterBand::WindowIteratorWrapper::end() const
10970 : {
10971 333 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10972 333 : m_nBlockYSize,
10973 333 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10974 : }
10975 :
10976 63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10977 : {
10978 63 : return static_cast<uint64_t>(
10979 63 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10980 63 : static_cast<uint64_t>(
10981 63 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10982 : }
10983 :
10984 : //! @endcond
10985 :
10986 : /** Return an object whose begin() and end() methods can be used to iterate
10987 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10988 : * band. The iteration order is from left to right, then from top to bottom.
10989 : *
10990 : \code{.cpp}
10991 : std::vector<double> pixelValues;
10992 : for (const auto& window : poBand->IterateWindows()) {
10993 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10994 : window.nXSize, window.nYSize);
10995 : // check eErr
10996 : }
10997 : \endcode
10998 : *
10999 : *
11000 : * @param maxSize The maximum number of pixels in each window. If set to
11001 : * zero (the default), or a number smaller than the block size,
11002 : * the window size will be the same as the block size.
11003 : * @since GDAL 3.12
11004 : */
11005 : GDALRasterBand::WindowIteratorWrapper
11006 163 : GDALRasterBand::IterateWindows(size_t maxSize) const
11007 : {
11008 163 : return WindowIteratorWrapper(*this, maxSize);
11009 : }
11010 :
11011 : /************************************************************************/
11012 : /* MayMultiBlockReadingBeMultiThreaded() */
11013 : /************************************************************************/
11014 :
11015 : /** Return whether a RasterIO(GF_Read) request spanning over multiple
11016 : * blocks may be accelerated internally using multi-threading.
11017 : *
11018 : * This can be used to determine the best chunk size to read a raster band.
11019 : *
11020 : * Note that such optimizations may require that the window is perfectly aligned
11021 : * on block boundaries and does not involve resampling or data type translation
11022 : * occurs, etc.
11023 : *
11024 : * @since GDAL 3.13
11025 : */
11026 0 : bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
11027 : {
11028 0 : return false;
11029 : }
11030 :
11031 : /************************************************************************/
11032 : /* GDALMDArrayFromRasterBand */
11033 : /************************************************************************/
11034 :
11035 : class GDALMDArrayFromRasterBand final : public GDALMDArray
11036 : {
11037 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
11038 :
11039 : GDALDataset *m_poDS;
11040 : GDALRasterBand *m_poBand;
11041 : GDALExtendedDataType m_dt;
11042 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
11043 : std::string m_osUnit;
11044 : std::vector<GByte> m_pabyNoData{};
11045 : std::shared_ptr<GDALMDArray> m_varX{};
11046 : std::shared_ptr<GDALMDArray> m_varY{};
11047 : std::string m_osFilename{};
11048 : mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
11049 :
11050 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
11051 : const size_t *count, const GInt64 *arrayStep,
11052 : const GPtrDiff_t *bufferStride,
11053 : const GDALExtendedDataType &bufferDataType,
11054 : void *pBuffer) const;
11055 :
11056 : protected:
11057 36 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
11058 72 : : GDALAbstractMDArray(std::string(),
11059 72 : std::string(poDS->GetDescription()) +
11060 : CPLSPrintf(" band %d", poBand->GetBand())),
11061 72 : GDALMDArray(std::string(),
11062 72 : std::string(poDS->GetDescription()) +
11063 : CPLSPrintf(" band %d", poBand->GetBand())),
11064 : m_poDS(poDS), m_poBand(poBand),
11065 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
11066 180 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
11067 : {
11068 36 : m_poDS->Reference();
11069 :
11070 36 : int bHasNoData = false;
11071 36 : if (m_poBand->GetRasterDataType() == GDT_Int64)
11072 : {
11073 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
11074 0 : if (bHasNoData)
11075 : {
11076 0 : m_pabyNoData.resize(m_dt.GetSize());
11077 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
11078 : m_dt.GetNumericDataType(), 0, 1);
11079 : }
11080 : }
11081 36 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
11082 : {
11083 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
11084 0 : if (bHasNoData)
11085 : {
11086 0 : m_pabyNoData.resize(m_dt.GetSize());
11087 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
11088 : m_dt.GetNumericDataType(), 0, 1);
11089 : }
11090 : }
11091 : else
11092 : {
11093 36 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
11094 36 : if (bHasNoData)
11095 : {
11096 1 : m_pabyNoData.resize(m_dt.GetSize());
11097 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
11098 : m_dt.GetNumericDataType(), 0, 1);
11099 : }
11100 : }
11101 :
11102 36 : const int nXSize = poBand->GetXSize();
11103 36 : const int nYSize = poBand->GetYSize();
11104 :
11105 36 : auto poSRS = m_poDS->GetSpatialRef();
11106 72 : std::string osTypeY;
11107 72 : std::string osTypeX;
11108 72 : std::string osDirectionY;
11109 72 : std::string osDirectionX;
11110 36 : if (poSRS && poSRS->GetAxesCount() == 2)
11111 : {
11112 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
11113 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
11114 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
11115 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
11116 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
11117 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
11118 : {
11119 8 : if (mapping == std::vector<int>{1, 2})
11120 : {
11121 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11122 8 : osDirectionY = "NORTH";
11123 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11124 8 : osDirectionX = "EAST";
11125 : }
11126 : }
11127 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
11128 : {
11129 16 : if (mapping == std::vector<int>{2, 1})
11130 : {
11131 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
11132 16 : osDirectionY = "NORTH";
11133 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
11134 16 : osDirectionX = "EAST";
11135 : }
11136 : }
11137 : }
11138 :
11139 180 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
11140 : "/", "Y", osTypeY, osDirectionY, nYSize),
11141 72 : std::make_shared<GDALDimensionWeakIndexingVar>(
11142 108 : "/", "X", osTypeX, osDirectionX, nXSize)};
11143 :
11144 36 : GDALGeoTransform gt;
11145 36 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
11146 : {
11147 50 : m_varX = GDALMDArrayRegularlySpaced::Create(
11148 50 : "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
11149 25 : m_dims[1]->SetIndexingVariable(m_varX);
11150 :
11151 50 : m_varY = GDALMDArrayRegularlySpaced::Create(
11152 50 : "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
11153 25 : m_dims[0]->SetIndexingVariable(m_varY);
11154 : }
11155 36 : }
11156 :
11157 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
11158 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11159 : const GDALExtendedDataType &bufferDataType,
11160 : void *pDstBuffer) const override;
11161 :
11162 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
11163 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11164 : const GDALExtendedDataType &bufferDataType,
11165 : const void *pSrcBuffer) override
11166 : {
11167 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
11168 : bufferStride, bufferDataType,
11169 1 : const_cast<void *>(pSrcBuffer));
11170 : }
11171 :
11172 : public:
11173 72 : ~GDALMDArrayFromRasterBand() override
11174 36 : {
11175 36 : m_poDS->ReleaseRef();
11176 72 : }
11177 :
11178 36 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
11179 : GDALRasterBand *poBand)
11180 : {
11181 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
11182 72 : new GDALMDArrayFromRasterBand(poDS, poBand)));
11183 36 : array->SetSelf(array);
11184 72 : return array;
11185 : }
11186 :
11187 5 : bool IsWritable() const override
11188 : {
11189 5 : return m_poDS->GetAccess() == GA_Update;
11190 : }
11191 :
11192 112 : const std::string &GetFilename() const override
11193 : {
11194 112 : return m_osFilename;
11195 : }
11196 :
11197 : const std::vector<std::shared_ptr<GDALDimension>> &
11198 350 : GetDimensions() const override
11199 : {
11200 350 : return m_dims;
11201 : }
11202 :
11203 158 : const GDALExtendedDataType &GetDataType() const override
11204 : {
11205 158 : return m_dt;
11206 : }
11207 :
11208 5 : const std::string &GetUnit() const override
11209 : {
11210 5 : return m_osUnit;
11211 : }
11212 :
11213 32 : const void *GetRawNoDataValue() const override
11214 : {
11215 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
11216 : }
11217 :
11218 4 : double GetOffset(bool *pbHasOffset,
11219 : GDALDataType *peStorageType) const override
11220 : {
11221 4 : int bHasOffset = false;
11222 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
11223 4 : if (pbHasOffset)
11224 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
11225 4 : if (peStorageType)
11226 1 : *peStorageType = GDT_Unknown;
11227 4 : return dfRes;
11228 : }
11229 :
11230 4 : double GetScale(bool *pbHasScale,
11231 : GDALDataType *peStorageType) const override
11232 : {
11233 4 : int bHasScale = false;
11234 4 : double dfRes = m_poBand->GetScale(&bHasScale);
11235 4 : if (pbHasScale)
11236 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
11237 4 : if (peStorageType)
11238 1 : *peStorageType = GDT_Unknown;
11239 4 : return dfRes;
11240 : }
11241 :
11242 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
11243 : {
11244 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
11245 88 : if (!poSrcSRS)
11246 2 : return nullptr;
11247 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
11248 :
11249 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
11250 86 : constexpr int iYDim = 0;
11251 86 : constexpr int iXDim = 1;
11252 258 : for (auto &m : axisMapping)
11253 : {
11254 172 : if (m == 1)
11255 86 : m = iXDim + 1;
11256 86 : else if (m == 2)
11257 86 : m = iYDim + 1;
11258 : else
11259 0 : m = 0;
11260 : }
11261 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
11262 86 : return poSRS;
11263 : }
11264 :
11265 32 : std::vector<GUInt64> GetBlockSize() const override
11266 : {
11267 32 : int nBlockXSize = 0;
11268 32 : int nBlockYSize = 0;
11269 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
11270 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
11271 32 : static_cast<GUInt64>(nBlockXSize)};
11272 : }
11273 :
11274 : std::vector<std::shared_ptr<GDALAttribute>>
11275 23 : GetAttributes(CSLConstList) const override
11276 : {
11277 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
11278 23 : auto papszMD = m_poBand->GetMetadata();
11279 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
11280 : {
11281 2 : char *pszKey = nullptr;
11282 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
11283 2 : if (pszKey && pszValue)
11284 : {
11285 : res.emplace_back(
11286 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
11287 : }
11288 2 : CPLFree(pszKey);
11289 : }
11290 23 : return res;
11291 : }
11292 :
11293 6 : int GetOverviewCount() const override
11294 : {
11295 6 : return m_poBand->GetOverviewCount();
11296 : }
11297 :
11298 4 : std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
11299 : {
11300 4 : const int nOverviews = GetOverviewCount();
11301 4 : if (idx < 0 || idx >= nOverviews)
11302 2 : return nullptr;
11303 2 : m_apoOverviews.resize(nOverviews);
11304 2 : if (!m_apoOverviews[idx])
11305 : {
11306 1 : if (auto poOvrBand = m_poBand->GetOverview(idx))
11307 : {
11308 1 : if (auto poOvrDS = poOvrBand->GetDataset())
11309 : {
11310 1 : m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
11311 : }
11312 : }
11313 : }
11314 2 : return m_apoOverviews[idx];
11315 : }
11316 : };
11317 :
11318 39 : bool GDALMDArrayFromRasterBand::IRead(
11319 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
11320 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
11321 : void *pDstBuffer) const
11322 : {
11323 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
11324 39 : bufferDataType, pDstBuffer);
11325 : }
11326 :
11327 : /************************************************************************/
11328 : /* ReadWrite() */
11329 : /************************************************************************/
11330 :
11331 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
11332 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
11333 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
11334 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
11335 : {
11336 40 : constexpr size_t iDimX = 1;
11337 40 : constexpr size_t iDimY = 0;
11338 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
11339 : arrayStartIdx, count, arrayStep, bufferStride,
11340 40 : bufferDataType, pBuffer);
11341 : }
11342 :
11343 : /************************************************************************/
11344 : /* GDALMDRasterIOFromBand() */
11345 : /************************************************************************/
11346 :
11347 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
11348 : size_t iDimX, size_t iDimY,
11349 : const GUInt64 *arrayStartIdx, const size_t *count,
11350 : const GInt64 *arrayStep,
11351 : const GPtrDiff_t *bufferStride,
11352 : const GDALExtendedDataType &bufferDataType,
11353 : void *pBuffer)
11354 : {
11355 73 : const auto eDT(bufferDataType.GetNumericDataType());
11356 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
11357 73 : const int nX =
11358 73 : arrayStep[iDimX] > 0
11359 73 : ? static_cast<int>(arrayStartIdx[iDimX])
11360 2 : : static_cast<int>(arrayStartIdx[iDimX] -
11361 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
11362 73 : const int nY =
11363 73 : arrayStep[iDimY] > 0
11364 73 : ? static_cast<int>(arrayStartIdx[iDimY])
11365 6 : : static_cast<int>(arrayStartIdx[iDimY] -
11366 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
11367 : const int nSizeX =
11368 73 : static_cast<int>(count[iDimX] * std::abs(arrayStep[iDimX]));
11369 : const int nSizeY =
11370 73 : static_cast<int>(count[iDimY] * std::abs(arrayStep[iDimY]));
11371 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
11372 73 : int nStrideXSign = 1;
11373 73 : if (arrayStep[iDimX] < 0)
11374 : {
11375 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
11376 2 : nStrideXSign = -1;
11377 : }
11378 73 : int nStrideYSign = 1;
11379 73 : if (arrayStep[iDimY] < 0)
11380 : {
11381 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
11382 6 : nStrideYSign = -1;
11383 : }
11384 :
11385 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
11386 73 : static_cast<int>(count[iDimX]),
11387 73 : static_cast<int>(count[iDimY]), eDT,
11388 : static_cast<GSpacing>(
11389 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
11390 : static_cast<GSpacing>(
11391 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
11392 73 : nullptr) == CE_None;
11393 : }
11394 :
11395 : /************************************************************************/
11396 : /* AsMDArray() */
11397 : /************************************************************************/
11398 :
11399 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
11400 : *
11401 : * The band must be linked to a GDALDataset. If this dataset is not already
11402 : * marked as shared, it will be, so that the returned array holds a reference
11403 : * to it.
11404 : *
11405 : * If the dataset has a geotransform attached, the X and Y dimensions of the
11406 : * returned array will have an associated indexing variable.
11407 : *
11408 : * This is the same as the C function GDALRasterBandAsMDArray().
11409 : *
11410 : * The "reverse" method is GDALMDArray::AsClassicDataset().
11411 : *
11412 : * @return a new array, or nullptr.
11413 : *
11414 : * @since GDAL 3.1
11415 : */
11416 35 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
11417 : {
11418 35 : if (!poDS)
11419 : {
11420 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
11421 0 : return nullptr;
11422 : }
11423 35 : if (!poDS->GetShared())
11424 : {
11425 33 : poDS->MarkAsShared();
11426 : }
11427 : return GDALMDArrayFromRasterBand::Create(
11428 35 : poDS, const_cast<GDALRasterBand *>(this));
11429 : }
11430 :
11431 : /************************************************************************/
11432 : /* InterpolateAtPoint() */
11433 : /************************************************************************/
11434 :
11435 : /**
11436 : * \brief Interpolates the value between pixels using a resampling algorithm,
11437 : * taking pixel/line coordinates as input.
11438 : *
11439 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
11440 : * @param dfLine line coordinate as a double, where interpolation should be done.
11441 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11442 : * @param pdfRealValue pointer to real part of interpolated value
11443 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11444 : *
11445 : * @return CE_None on success, or an error code on failure.
11446 : * @since GDAL 3.10
11447 : */
11448 :
11449 185 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
11450 : GDALRIOResampleAlg eInterpolation,
11451 : double *pdfRealValue,
11452 : double *pdfImagValue) const
11453 : {
11454 185 : if (eInterpolation != GRIORA_NearestNeighbour &&
11455 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
11456 : eInterpolation != GRIORA_CubicSpline)
11457 : {
11458 2 : CPLError(CE_Failure, CPLE_AppDefined,
11459 : "Only nearest, bilinear, cubic and cubicspline interpolation "
11460 : "methods "
11461 : "allowed");
11462 :
11463 2 : return CE_Failure;
11464 : }
11465 :
11466 183 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
11467 183 : if (!m_poPointsCache)
11468 103 : m_poPointsCache = new GDALDoublePointsCache();
11469 :
11470 : const bool res =
11471 183 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
11472 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
11473 :
11474 183 : return res ? CE_None : CE_Failure;
11475 : }
11476 :
11477 : /************************************************************************/
11478 : /* GDALRasterInterpolateAtPoint() */
11479 : /************************************************************************/
11480 :
11481 : /**
11482 : * \brief Interpolates the value between pixels using
11483 : * a resampling algorithm
11484 : *
11485 : * @see GDALRasterBand::InterpolateAtPoint()
11486 : * @since GDAL 3.10
11487 : */
11488 :
11489 162 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
11490 : double dfLine,
11491 : GDALRIOResampleAlg eInterpolation,
11492 : double *pdfRealValue, double *pdfImagValue)
11493 : {
11494 162 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
11495 :
11496 162 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11497 162 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
11498 162 : pdfRealValue, pdfImagValue);
11499 : }
11500 :
11501 : /************************************************************************/
11502 : /* InterpolateAtGeolocation() */
11503 : /************************************************************************/
11504 :
11505 : /**
11506 : * \brief Interpolates the value between pixels using a resampling algorithm,
11507 : * taking georeferenced coordinates as input.
11508 : *
11509 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11510 : * must be in the "natural" SRS of the dataset, that is the one returned by
11511 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11512 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11513 : * array (generally WGS 84) if there is a geolocation array.
11514 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11515 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11516 : * be a easting, and dfGeolocY a northing.
11517 : *
11518 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11519 : * expressed in that CRS, and that tuple must be conformant with the
11520 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11521 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11522 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11523 : * before calling this method, and in that case, dfGeolocX must be a longitude
11524 : * or an easting value, and dfGeolocX a latitude or a northing value.
11525 : *
11526 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11527 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11528 : * it for details on how that transformation is done.
11529 : *
11530 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11531 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11532 : * where interpolation should be done.
11533 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11534 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11535 : * where interpolation should be done.
11536 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11537 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11538 : * @param pdfRealValue pointer to real part of interpolated value
11539 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11540 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11541 : *
11542 : * @return CE_None on success, or an error code on failure.
11543 : * @since GDAL 3.11
11544 : */
11545 :
11546 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11547 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11548 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11549 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11550 : {
11551 : double dfPixel;
11552 : double dfLine;
11553 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11554 : &dfLine,
11555 15 : papszTransformerOptions) != CE_None)
11556 : {
11557 1 : return CE_Failure;
11558 : }
11559 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11560 14 : pdfImagValue);
11561 : }
11562 :
11563 : /************************************************************************/
11564 : /* GDALRasterInterpolateAtGeolocation() */
11565 : /************************************************************************/
11566 :
11567 : /**
11568 : * \brief Interpolates the value between pixels using a resampling algorithm,
11569 : * taking georeferenced coordinates as input.
11570 : *
11571 : * @see GDALRasterBand::InterpolateAtGeolocation()
11572 : * @since GDAL 3.11
11573 : */
11574 :
11575 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11576 : double dfGeolocX, double dfGeolocY,
11577 : OGRSpatialReferenceH hSRS,
11578 : GDALRIOResampleAlg eInterpolation,
11579 : double *pdfRealValue,
11580 : double *pdfImagValue,
11581 : CSLConstList papszTransformerOptions)
11582 : {
11583 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11584 :
11585 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11586 15 : return poBand->InterpolateAtGeolocation(
11587 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11588 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11589 : }
11590 :
11591 : /************************************************************************/
11592 : /* GDALRasterBand::SplitRasterIO() */
11593 : /************************************************************************/
11594 :
11595 : //! @cond Doxygen_Suppress
11596 :
11597 : /** Implements IRasterIO() by dividing the request in 2.
11598 : *
11599 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11600 : *
11601 : * Return CE_Warning if the split could not be done, CE_None in case of
11602 : * success and CE_Failure in case of error.
11603 : *
11604 : * @since 3.12
11605 : */
11606 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11607 : [[maybe_unused]] int nXSize,
11608 : [[maybe_unused]] int nYSize, void *pData,
11609 : int nBufXSize, int nBufYSize,
11610 : GDALDataType eBufType,
11611 : GSpacing nPixelSpace, GSpacing nLineSpace,
11612 : GDALRasterIOExtraArg *psExtraArg)
11613 : {
11614 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11615 :
11616 999 : GByte *pabyData = static_cast<GByte *>(pData);
11617 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11618 : {
11619 : GDALRasterIOExtraArg sArg;
11620 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11621 499 : const int nHalfHeight = nBufYSize / 2;
11622 :
11623 499 : sArg.pfnProgress = GDALScaledProgress;
11624 499 : sArg.pProgressData = GDALCreateScaledProgress(
11625 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11626 499 : if (sArg.pProgressData == nullptr)
11627 499 : sArg.pfnProgress = nullptr;
11628 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11629 : pabyData, nBufXSize, nHalfHeight, eBufType,
11630 499 : nPixelSpace, nLineSpace, &sArg);
11631 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11632 :
11633 499 : if (eErr == CE_None)
11634 : {
11635 499 : sArg.pfnProgress = GDALScaledProgress;
11636 499 : sArg.pProgressData = GDALCreateScaledProgress(
11637 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11638 499 : if (sArg.pProgressData == nullptr)
11639 499 : sArg.pfnProgress = nullptr;
11640 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11641 : nBufYSize - nHalfHeight,
11642 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11643 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11644 499 : nLineSpace, &sArg);
11645 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11646 : }
11647 499 : return eErr;
11648 : }
11649 500 : else if (nBufXSize >= 2)
11650 : {
11651 : GDALRasterIOExtraArg sArg;
11652 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11653 500 : const int nHalfWidth = nBufXSize / 2;
11654 :
11655 500 : sArg.pfnProgress = GDALScaledProgress;
11656 500 : sArg.pProgressData = GDALCreateScaledProgress(
11657 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11658 500 : if (sArg.pProgressData == nullptr)
11659 500 : sArg.pfnProgress = nullptr;
11660 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11661 : pabyData, nHalfWidth, nBufYSize, eBufType,
11662 500 : nPixelSpace, nLineSpace, &sArg);
11663 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11664 :
11665 500 : if (eErr == CE_None)
11666 : {
11667 500 : sArg.pfnProgress = GDALScaledProgress;
11668 500 : sArg.pProgressData = GDALCreateScaledProgress(
11669 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11670 500 : if (sArg.pProgressData == nullptr)
11671 500 : sArg.pfnProgress = nullptr;
11672 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11673 : nBufXSize - nHalfWidth, nBufYSize,
11674 500 : pabyData + nHalfWidth * nPixelSpace,
11675 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11676 500 : nPixelSpace, nLineSpace, &sArg);
11677 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11678 : }
11679 500 : return eErr;
11680 : }
11681 :
11682 0 : return CE_Warning;
11683 : }
11684 :
11685 : //! @endcond
11686 :
11687 : /************************************************************************/
11688 : /* ThrowIfNotSameDimensions() */
11689 : /************************************************************************/
11690 :
11691 : //! @cond Doxygen_Suppress
11692 : /* static */
11693 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11694 : const GDALRasterBand &second)
11695 : {
11696 320 : if (first.GetXSize() != second.GetXSize() ||
11697 151 : first.GetYSize() != second.GetYSize())
11698 : {
11699 36 : throw std::runtime_error("Bands do not have the same dimensions");
11700 : }
11701 133 : }
11702 :
11703 : //! @endcond
11704 :
11705 : /************************************************************************/
11706 : /* GDALRasterBandUnaryOp() */
11707 : /************************************************************************/
11708 :
11709 : /** Apply a unary operation on this band.
11710 : *
11711 : * The resulting band is lazy evaluated. A reference is taken on the input
11712 : * dataset.
11713 : *
11714 : * @since 3.12
11715 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11716 : */
11717 : GDALComputedRasterBandH
11718 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11719 : GDALRasterAlgebraUnaryOperation eOp)
11720 : {
11721 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11722 6 : GDALComputedRasterBand::Operation cppOp{};
11723 6 : switch (eOp)
11724 : {
11725 2 : case GRAUO_LOGICAL_NOT:
11726 : return new GDALComputedRasterBand(
11727 : GDALComputedRasterBand::Operation::OP_NE,
11728 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11729 1 : case GRAUO_ABS:
11730 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11731 1 : break;
11732 1 : case GRAUO_SQRT:
11733 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11734 1 : break;
11735 1 : case GRAUO_LOG:
11736 : #ifndef HAVE_MUPARSER
11737 : CPLError(
11738 : CE_Failure, CPLE_NotSupported,
11739 : "log(band) not available on a GDAL build without muparser");
11740 : return nullptr;
11741 : #else
11742 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11743 1 : break;
11744 : #endif
11745 1 : case GRAUO_LOG10:
11746 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11747 1 : break;
11748 : }
11749 : return new GDALComputedRasterBand(cppOp,
11750 4 : *(GDALRasterBand::FromHandle(hBand)));
11751 : }
11752 :
11753 : /************************************************************************/
11754 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11755 : /************************************************************************/
11756 :
11757 : static GDALComputedRasterBand::Operation
11758 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11759 : GDALRasterAlgebraBinaryOperation eOp)
11760 : {
11761 120 : switch (eOp)
11762 : {
11763 26 : case GRABO_ADD:
11764 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11765 2 : case GRABO_SUB:
11766 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11767 24 : case GRABO_MUL:
11768 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11769 3 : case GRABO_DIV:
11770 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11771 6 : case GRABO_GT:
11772 6 : return GDALComputedRasterBand::Operation::OP_GT;
11773 8 : case GRABO_GE:
11774 8 : return GDALComputedRasterBand::Operation::OP_GE;
11775 6 : case GRABO_LT:
11776 6 : return GDALComputedRasterBand::Operation::OP_LT;
11777 6 : case GRABO_LE:
11778 6 : return GDALComputedRasterBand::Operation::OP_LE;
11779 6 : case GRABO_EQ:
11780 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11781 6 : case GRABO_NE:
11782 6 : break;
11783 12 : case GRABO_LOGICAL_AND:
11784 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11785 12 : case GRABO_LOGICAL_OR:
11786 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11787 3 : case GRABO_POW:
11788 3 : return GDALComputedRasterBand::Operation::OP_POW;
11789 : }
11790 6 : return GDALComputedRasterBand::Operation::OP_NE;
11791 : }
11792 :
11793 : /************************************************************************/
11794 : /* GDALRasterBandBinaryOpBand() */
11795 : /************************************************************************/
11796 :
11797 : /** Apply a binary operation on this band with another one.
11798 : *
11799 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11800 : * "hBand1 - hBand2".
11801 : *
11802 : * The resulting band is lazy evaluated. A reference is taken on both input
11803 : * datasets.
11804 : *
11805 : * @since 3.12
11806 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11807 : */
11808 : GDALComputedRasterBandH
11809 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11810 : GDALRasterAlgebraBinaryOperation eOp,
11811 : GDALRasterBandH hOtherBand)
11812 : {
11813 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11814 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11815 : #ifndef HAVE_MUPARSER
11816 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11817 : {
11818 : CPLError(
11819 : CE_Failure, CPLE_NotSupported,
11820 : "Band comparison operators not available on a GDAL build without "
11821 : "muparser");
11822 : return nullptr;
11823 : }
11824 : else if (eOp == GRABO_POW)
11825 : {
11826 : CPLError(
11827 : CE_Failure, CPLE_NotSupported,
11828 : "pow(band, band) not available on a GDAL build without muparser");
11829 : return nullptr;
11830 : }
11831 : #endif
11832 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11833 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11834 : try
11835 : {
11836 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11837 : }
11838 13 : catch (const std::exception &e)
11839 : {
11840 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11841 13 : return nullptr;
11842 : }
11843 : return new GDALComputedRasterBand(
11844 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11845 44 : secondBand);
11846 : }
11847 :
11848 : /************************************************************************/
11849 : /* GDALRasterBandBinaryOpDouble() */
11850 : /************************************************************************/
11851 :
11852 : /** Apply a binary operation on this band with a constant
11853 : *
11854 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11855 : * "hBand - constant".
11856 : *
11857 : * The resulting band is lazy evaluated. A reference is taken on the input
11858 : * dataset.
11859 : *
11860 : * @since 3.12
11861 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11862 : */
11863 : GDALComputedRasterBandH
11864 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11865 : GDALRasterAlgebraBinaryOperation eOp,
11866 : double constant)
11867 : {
11868 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11869 : #ifndef HAVE_MUPARSER
11870 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11871 : {
11872 : CPLError(
11873 : CE_Failure, CPLE_NotSupported,
11874 : "Band comparison operators not available on a GDAL build without "
11875 : "muparser");
11876 : return nullptr;
11877 : }
11878 : #endif
11879 : return new GDALComputedRasterBand(
11880 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11881 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11882 : }
11883 :
11884 : /************************************************************************/
11885 : /* GDALRasterBandBinaryOpDoubleToBand() */
11886 : /************************************************************************/
11887 :
11888 : /** Apply a binary operation on the constant with this band
11889 : *
11890 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11891 : * "constant - hBand".
11892 : *
11893 : * The resulting band is lazy evaluated. A reference is taken on the input
11894 : * dataset.
11895 : *
11896 : * @since 3.12
11897 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11898 : */
11899 : GDALComputedRasterBandH
11900 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11901 : GDALRasterAlgebraBinaryOperation eOp,
11902 : GDALRasterBandH hBand)
11903 : {
11904 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11905 : #ifndef HAVE_MUPARSER
11906 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11907 : {
11908 : CPLError(
11909 : CE_Failure, CPLE_NotSupported,
11910 : "Band comparison operators not available on a GDAL build without "
11911 : "muparser");
11912 : return nullptr;
11913 : }
11914 : #endif
11915 18 : switch (eOp)
11916 : {
11917 15 : case GRABO_ADD:
11918 : case GRABO_MUL:
11919 : {
11920 : return new GDALComputedRasterBand(
11921 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11922 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11923 : }
11924 :
11925 2 : case GRABO_DIV:
11926 : case GRABO_GT:
11927 : case GRABO_GE:
11928 : case GRABO_LT:
11929 : case GRABO_LE:
11930 : case GRABO_EQ:
11931 : case GRABO_NE:
11932 : case GRABO_LOGICAL_AND:
11933 : case GRABO_LOGICAL_OR:
11934 : case GRABO_POW:
11935 : {
11936 : return new GDALComputedRasterBand(
11937 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11938 2 : *(GDALRasterBand::FromHandle(hBand)));
11939 : }
11940 :
11941 1 : case GRABO_SUB:
11942 : {
11943 1 : break;
11944 : }
11945 : }
11946 :
11947 : return new GDALComputedRasterBand(
11948 : GDALComputedRasterBand::Operation::OP_ADD,
11949 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11950 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11951 1 : constant);
11952 : }
11953 :
11954 : /************************************************************************/
11955 : /* operator+() */
11956 : /************************************************************************/
11957 :
11958 : /** Add this band with another one.
11959 : *
11960 : * The resulting band is lazy evaluated. A reference is taken on both input
11961 : * datasets.
11962 : *
11963 : * @since 3.12
11964 : * @throw std::runtime_error if both bands do not have the same dimensions.
11965 : */
11966 : GDALComputedRasterBand
11967 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11968 : {
11969 8 : ThrowIfNotSameDimensions(*this, other);
11970 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11971 7 : *this, other);
11972 : }
11973 :
11974 : /************************************************************************/
11975 : /* operator+() */
11976 : /************************************************************************/
11977 :
11978 : /** Add this band with a constant.
11979 : *
11980 : * The resulting band is lazy evaluated. A reference is taken on the input
11981 : * dataset.
11982 : *
11983 : * @since 3.12
11984 : */
11985 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11986 : {
11987 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11988 13 : *this, constant);
11989 : }
11990 :
11991 : /************************************************************************/
11992 : /* operator+() */
11993 : /************************************************************************/
11994 :
11995 : /** Add a band with a constant.
11996 : *
11997 : * The resulting band is lazy evaluated. A reference is taken on the input
11998 : * dataset.
11999 : *
12000 : * @since 3.12
12001 : */
12002 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
12003 : {
12004 1 : return other + constant;
12005 : }
12006 :
12007 : /************************************************************************/
12008 : /* operator-() */
12009 : /************************************************************************/
12010 :
12011 : /** Return a band whose value is the opposite value of the band for each
12012 : * pixel.
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 GDALRasterBand::operator-() const
12020 : {
12021 2 : return 0 - *this;
12022 : }
12023 :
12024 : /************************************************************************/
12025 : /* operator-() */
12026 : /************************************************************************/
12027 :
12028 : /** Subtract this band with another one.
12029 : *
12030 : * The resulting band is lazy evaluated. A reference is taken on both input
12031 : * datasets.
12032 : *
12033 : * @since 3.12
12034 : * @throw std::runtime_error if both bands do not have the same dimensions.
12035 : */
12036 : GDALComputedRasterBand
12037 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
12038 : {
12039 2 : ThrowIfNotSameDimensions(*this, other);
12040 : return GDALComputedRasterBand(
12041 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
12042 : }
12043 :
12044 : /************************************************************************/
12045 : /* operator-() */
12046 : /************************************************************************/
12047 :
12048 : /** Subtract this band with a constant.
12049 : *
12050 : * The resulting band is lazy evaluated. A reference is taken on the input
12051 : * dataset.
12052 : *
12053 : * @since 3.12
12054 : */
12055 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
12056 : {
12057 : return GDALComputedRasterBand(
12058 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
12059 : }
12060 :
12061 : /************************************************************************/
12062 : /* operator-() */
12063 : /************************************************************************/
12064 :
12065 : /** Subtract a constant with a band.
12066 : *
12067 : * The resulting band is lazy evaluated. A reference is taken on the input
12068 : * dataset.
12069 : *
12070 : * @since 3.12
12071 : */
12072 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
12073 : {
12074 6 : return other * (-1.0) + constant;
12075 : }
12076 :
12077 : /************************************************************************/
12078 : /* operator*() */
12079 : /************************************************************************/
12080 :
12081 : /** Multiply this band with another one.
12082 : *
12083 : * The resulting band is lazy evaluated. A reference is taken on both input
12084 : * datasets.
12085 : *
12086 : * @since 3.12
12087 : * @throw std::runtime_error if both bands do not have the same dimensions.
12088 : */
12089 : GDALComputedRasterBand
12090 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
12091 : {
12092 2 : ThrowIfNotSameDimensions(*this, other);
12093 : return GDALComputedRasterBand(
12094 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
12095 : }
12096 :
12097 : /************************************************************************/
12098 : /* operator*() */
12099 : /************************************************************************/
12100 :
12101 : /** Multiply this band by a constant.
12102 : *
12103 : * The resulting band is lazy evaluated. A reference is taken on the input
12104 : * dataset.
12105 : *
12106 : * @since 3.12
12107 : */
12108 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
12109 : {
12110 : return GDALComputedRasterBand(
12111 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
12112 : }
12113 :
12114 : /************************************************************************/
12115 : /* operator*() */
12116 : /************************************************************************/
12117 :
12118 : /** Multiply a band with a constant.
12119 : *
12120 : * The resulting band is lazy evaluated. A reference is taken on the input
12121 : * dataset.
12122 : *
12123 : * @since 3.12
12124 : */
12125 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
12126 : {
12127 2 : return other * constant;
12128 : }
12129 :
12130 : /************************************************************************/
12131 : /* operator/() */
12132 : /************************************************************************/
12133 :
12134 : /** Divide this band with another one.
12135 : *
12136 : * The resulting band is lazy evaluated. A reference is taken on both input
12137 : * datasets.
12138 : *
12139 : * @since 3.12
12140 : * @throw std::runtime_error if both bands do not have the same dimensions.
12141 : */
12142 : GDALComputedRasterBand
12143 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
12144 : {
12145 2 : ThrowIfNotSameDimensions(*this, other);
12146 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12147 2 : *this, other);
12148 : }
12149 :
12150 : /************************************************************************/
12151 : /* operator/() */
12152 : /************************************************************************/
12153 :
12154 : /** Divide this band by a constant.
12155 : *
12156 : * The resulting band is lazy evaluated. A reference is taken on the input
12157 : * dataset.
12158 : *
12159 : * @since 3.12
12160 : */
12161 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
12162 : {
12163 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12164 0 : *this, constant);
12165 : }
12166 :
12167 : /************************************************************************/
12168 : /* operator/() */
12169 : /************************************************************************/
12170 :
12171 : /** Divide a constant by a band.
12172 : *
12173 : * The resulting band is lazy evaluated. A reference is taken on the input
12174 : * dataset.
12175 : *
12176 : * @since 3.12
12177 : */
12178 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
12179 : {
12180 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
12181 1 : constant, other);
12182 : }
12183 :
12184 : /************************************************************************/
12185 : /* ThrowIfNotMuparser() */
12186 : /************************************************************************/
12187 :
12188 : #ifndef HAVE_MUPARSER
12189 : static GDALComputedRasterBand ThrowIfNotMuparser()
12190 : {
12191 : throw std::runtime_error("Operator not available on a "
12192 : "GDAL build without muparser");
12193 : }
12194 : #endif
12195 :
12196 : /************************************************************************/
12197 : /* operator>() */
12198 : /************************************************************************/
12199 :
12200 : /** Return a band whose value is 1 if the pixel value of the left operand
12201 : * is greater than the pixel value of the right operand.
12202 : *
12203 : * The resulting band is lazy evaluated. A reference is taken on the input
12204 : * dataset.
12205 : *
12206 : * @since 3.12
12207 : */
12208 : GDALComputedRasterBand
12209 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
12210 : {
12211 : #ifndef HAVE_MUPARSER
12212 : (void)other;
12213 : return ThrowIfNotMuparser();
12214 : #else
12215 3 : ThrowIfNotSameDimensions(*this, other);
12216 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12217 2 : *this, other);
12218 : #endif
12219 : }
12220 :
12221 : /************************************************************************/
12222 : /* operator>() */
12223 : /************************************************************************/
12224 :
12225 : /** Return a band whose value is 1 if the pixel value of the left operand
12226 : * is greater than the constant.
12227 : *
12228 : * The resulting band is lazy evaluated. A reference is taken on the input
12229 : * dataset.
12230 : *
12231 : * @since 3.12
12232 : */
12233 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
12234 : {
12235 : #ifndef HAVE_MUPARSER
12236 : (void)constant;
12237 : return ThrowIfNotMuparser();
12238 : #else
12239 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12240 3 : *this, constant);
12241 : #endif
12242 : }
12243 :
12244 : /************************************************************************/
12245 : /* operator>() */
12246 : /************************************************************************/
12247 :
12248 : /** Return a band whose value is 1 if the constant is greater than the pixel
12249 : * value of the right operand.
12250 : *
12251 : * The resulting band is lazy evaluated. A reference is taken on the input
12252 : * dataset.
12253 : *
12254 : * @since 3.12
12255 : */
12256 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
12257 : {
12258 : #ifndef HAVE_MUPARSER
12259 : (void)constant;
12260 : (void)other;
12261 : return ThrowIfNotMuparser();
12262 : #else
12263 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
12264 2 : constant, other);
12265 : #endif
12266 : }
12267 :
12268 : /************************************************************************/
12269 : /* operator>=() */
12270 : /************************************************************************/
12271 :
12272 : /** Return a band whose value is 1 if the pixel value of the left operand
12273 : * is greater or equal to the pixel value of the right operand.
12274 : *
12275 : * The resulting band is lazy evaluated. A reference is taken on the input
12276 : * dataset.
12277 : *
12278 : * @since 3.12
12279 : */
12280 : GDALComputedRasterBand
12281 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
12282 : {
12283 : #ifndef HAVE_MUPARSER
12284 : (void)other;
12285 : return ThrowIfNotMuparser();
12286 : #else
12287 4 : ThrowIfNotSameDimensions(*this, other);
12288 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12289 3 : *this, other);
12290 : #endif
12291 : }
12292 :
12293 : /************************************************************************/
12294 : /* operator>=() */
12295 : /************************************************************************/
12296 :
12297 : /** Return a band whose value is 1 if the pixel value of the left operand
12298 : * is greater or equal to the constant.
12299 : *
12300 : * The resulting band is lazy evaluated. A reference is taken on the input
12301 : * dataset.
12302 : *
12303 : * @since 3.12
12304 : */
12305 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
12306 : {
12307 : #ifndef HAVE_MUPARSER
12308 : (void)constant;
12309 : return ThrowIfNotMuparser();
12310 : #else
12311 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12312 3 : *this, constant);
12313 : #endif
12314 : }
12315 :
12316 : /************************************************************************/
12317 : /* operator>=() */
12318 : /************************************************************************/
12319 :
12320 : /** Return a band whose value is 1 if the constant is greater or equal to
12321 : * the pixel value of the right operand.
12322 : *
12323 : * The resulting band is lazy evaluated. A reference is taken on the input
12324 : * dataset.
12325 : *
12326 : * @since 3.12
12327 : */
12328 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
12329 : {
12330 : #ifndef HAVE_MUPARSER
12331 : (void)constant;
12332 : (void)other;
12333 : return ThrowIfNotMuparser();
12334 : #else
12335 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
12336 2 : constant, other);
12337 : #endif
12338 : }
12339 :
12340 : /************************************************************************/
12341 : /* operator<() */
12342 : /************************************************************************/
12343 :
12344 : /** Return a band whose value is 1 if the pixel value of the left operand
12345 : * is lesser than the pixel value of the right operand.
12346 : *
12347 : * The resulting band is lazy evaluated. A reference is taken on the input
12348 : * dataset.
12349 : *
12350 : * @since 3.12
12351 : */
12352 : GDALComputedRasterBand
12353 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
12354 : {
12355 : #ifndef HAVE_MUPARSER
12356 : (void)other;
12357 : return ThrowIfNotMuparser();
12358 : #else
12359 3 : ThrowIfNotSameDimensions(*this, other);
12360 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12361 2 : *this, other);
12362 : #endif
12363 : }
12364 :
12365 : /************************************************************************/
12366 : /* operator<() */
12367 : /************************************************************************/
12368 :
12369 : /** Return a band whose value is 1 if the pixel value of the left operand
12370 : * is lesser than the constant.
12371 : *
12372 : * The resulting band is lazy evaluated. A reference is taken on the input
12373 : * dataset.
12374 : *
12375 : * @since 3.12
12376 : */
12377 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
12378 : {
12379 : #ifndef HAVE_MUPARSER
12380 : (void)constant;
12381 : return ThrowIfNotMuparser();
12382 : #else
12383 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12384 3 : *this, constant);
12385 : #endif
12386 : }
12387 :
12388 : /************************************************************************/
12389 : /* operator<() */
12390 : /************************************************************************/
12391 :
12392 : /** Return a band whose value is 1 if the constant is lesser than the pixel
12393 : * value of the right operand.
12394 : *
12395 : * The resulting band is lazy evaluated. A reference is taken on the input
12396 : * dataset.
12397 : *
12398 : * @since 3.12
12399 : */
12400 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
12401 : {
12402 : #ifndef HAVE_MUPARSER
12403 : (void)constant;
12404 : (void)other;
12405 : return ThrowIfNotMuparser();
12406 : #else
12407 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
12408 2 : constant, other);
12409 : #endif
12410 : }
12411 :
12412 : /************************************************************************/
12413 : /* operator<=() */
12414 : /************************************************************************/
12415 :
12416 : /** Return a band whose value is 1 if the pixel value of the left operand
12417 : * is lesser or equal to the pixel value of the right operand.
12418 : *
12419 : * The resulting band is lazy evaluated. A reference is taken on the input
12420 : * dataset.
12421 : *
12422 : * @since 3.12
12423 : */
12424 : GDALComputedRasterBand
12425 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
12426 : {
12427 : #ifndef HAVE_MUPARSER
12428 : (void)other;
12429 : return ThrowIfNotMuparser();
12430 : #else
12431 4 : ThrowIfNotSameDimensions(*this, other);
12432 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12433 3 : *this, other);
12434 : #endif
12435 : }
12436 :
12437 : /************************************************************************/
12438 : /* operator<=() */
12439 : /************************************************************************/
12440 :
12441 : /** Return a band whose value is 1 if the pixel value of the left operand
12442 : * is lesser or equal to the constant.
12443 : *
12444 : * The resulting band is lazy evaluated. A reference is taken on the input
12445 : * dataset.
12446 : *
12447 : * @since 3.12
12448 : */
12449 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
12450 : {
12451 : #ifndef HAVE_MUPARSER
12452 : (void)constant;
12453 : return ThrowIfNotMuparser();
12454 : #else
12455 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12456 3 : *this, constant);
12457 : #endif
12458 : }
12459 :
12460 : /************************************************************************/
12461 : /* operator<=() */
12462 : /************************************************************************/
12463 :
12464 : /** Return a band whose value is 1 if the constant is lesser or equal to
12465 : * the pixel value of the right operand.
12466 : *
12467 : * The resulting band is lazy evaluated. A reference is taken on the input
12468 : * dataset.
12469 : *
12470 : * @since 3.12
12471 : */
12472 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
12473 : {
12474 : #ifndef HAVE_MUPARSER
12475 : (void)constant;
12476 : (void)other;
12477 : return ThrowIfNotMuparser();
12478 : #else
12479 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
12480 2 : constant, other);
12481 : #endif
12482 : }
12483 :
12484 : /************************************************************************/
12485 : /* operator==() */
12486 : /************************************************************************/
12487 :
12488 : /** Return a band whose value is 1 if the pixel value of the left operand
12489 : * is equal to the pixel value of the right operand.
12490 : *
12491 : * The resulting band is lazy evaluated. A reference is taken on the input
12492 : * dataset.
12493 : *
12494 : * @since 3.12
12495 : */
12496 : GDALComputedRasterBand
12497 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
12498 : {
12499 : #ifndef HAVE_MUPARSER
12500 : (void)other;
12501 : return ThrowIfNotMuparser();
12502 : #else
12503 3 : ThrowIfNotSameDimensions(*this, other);
12504 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12505 2 : *this, other);
12506 : #endif
12507 : }
12508 :
12509 : /************************************************************************/
12510 : /* operator==() */
12511 : /************************************************************************/
12512 :
12513 : /** Return a band whose value is 1 if the pixel value of the left operand
12514 : * is equal to the constant.
12515 : *
12516 : * The resulting band is lazy evaluated. A reference is taken on the input
12517 : * dataset.
12518 : *
12519 : * @since 3.12
12520 : */
12521 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12522 : {
12523 : #ifndef HAVE_MUPARSER
12524 : (void)constant;
12525 : return ThrowIfNotMuparser();
12526 : #else
12527 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12528 8 : *this, constant);
12529 : #endif
12530 : }
12531 :
12532 : /************************************************************************/
12533 : /* operator==() */
12534 : /************************************************************************/
12535 :
12536 : /** Return a band whose value is 1 if the constant is equal to
12537 : * the pixel value of the right operand.
12538 : *
12539 : * The resulting band is lazy evaluated. A reference is taken on the input
12540 : * dataset.
12541 : *
12542 : * @since 3.12
12543 : */
12544 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12545 : {
12546 : #ifndef HAVE_MUPARSER
12547 : (void)constant;
12548 : (void)other;
12549 : return ThrowIfNotMuparser();
12550 : #else
12551 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12552 2 : constant, other);
12553 : #endif
12554 : }
12555 :
12556 : /************************************************************************/
12557 : /* operator!=() */
12558 : /************************************************************************/
12559 :
12560 : /** Return a band whose value is 1 if the pixel value of the left operand
12561 : * is different from the pixel value of the right operand.
12562 : *
12563 : * The resulting band is lazy evaluated. A reference is taken on the input
12564 : * dataset.
12565 : *
12566 : * @since 3.12
12567 : */
12568 : GDALComputedRasterBand
12569 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12570 : {
12571 : #ifndef HAVE_MUPARSER
12572 : (void)other;
12573 : return ThrowIfNotMuparser();
12574 : #else
12575 3 : ThrowIfNotSameDimensions(*this, other);
12576 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12577 2 : *this, other);
12578 : #endif
12579 : }
12580 :
12581 : /************************************************************************/
12582 : /* operator!=() */
12583 : /************************************************************************/
12584 :
12585 : /** Return a band whose value is 1 if the pixel value of the left operand
12586 : * is different from the constant.
12587 : *
12588 : * The resulting band is lazy evaluated. A reference is taken on the input
12589 : * dataset.
12590 : *
12591 : * @since 3.12
12592 : */
12593 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12594 : {
12595 : #ifndef HAVE_MUPARSER
12596 : (void)constant;
12597 : return ThrowIfNotMuparser();
12598 : #else
12599 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12600 6 : *this, constant);
12601 : #endif
12602 : }
12603 :
12604 : /************************************************************************/
12605 : /* operator!=() */
12606 : /************************************************************************/
12607 :
12608 : /** Return a band whose value is 1 if the constant is different from
12609 : * the pixel value of the right operand.
12610 : *
12611 : * The resulting band is lazy evaluated. A reference is taken on the input
12612 : * dataset.
12613 : *
12614 : * @since 3.12
12615 : */
12616 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12617 : {
12618 : #ifndef HAVE_MUPARSER
12619 : (void)constant;
12620 : (void)other;
12621 : return ThrowIfNotMuparser();
12622 : #else
12623 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12624 2 : constant, other);
12625 : #endif
12626 : }
12627 :
12628 : #if defined(__GNUC__)
12629 : #pragma GCC diagnostic push
12630 : #pragma GCC diagnostic ignored "-Weffc++"
12631 : #endif
12632 :
12633 : /************************************************************************/
12634 : /* operator&&() */
12635 : /************************************************************************/
12636 :
12637 : /** Return a band whose value is 1 if the pixel value of the left and right
12638 : * operands is true.
12639 : *
12640 : * The resulting band is lazy evaluated. A reference is taken on the input
12641 : * dataset.
12642 : *
12643 : * @since 3.12
12644 : */
12645 : GDALComputedRasterBand
12646 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12647 : {
12648 : #ifndef HAVE_MUPARSER
12649 : (void)other;
12650 : return ThrowIfNotMuparser();
12651 : #else
12652 3 : ThrowIfNotSameDimensions(*this, other);
12653 : return GDALComputedRasterBand(
12654 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12655 : #endif
12656 : }
12657 :
12658 : /************************************************************************/
12659 : /* operator&&() */
12660 : /************************************************************************/
12661 :
12662 : /** Return a band whose value is 1 if the pixel value of the left operand
12663 : * is true, as well as the constant
12664 : *
12665 : * The resulting band is lazy evaluated. A reference is taken on the input
12666 : * dataset.
12667 : *
12668 : * @since 3.12
12669 : */
12670 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12671 : {
12672 : #ifndef HAVE_MUPARSER
12673 : (void)constant;
12674 : return ThrowIfNotMuparser();
12675 : #else
12676 : return GDALComputedRasterBand(
12677 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12678 : #endif
12679 : }
12680 :
12681 : /************************************************************************/
12682 : /* operator&&() */
12683 : /************************************************************************/
12684 :
12685 : /** Return a band whose value is 1 if the constant is true, as well as
12686 : * the pixel value of the right operand.
12687 : *
12688 : * The resulting band is lazy evaluated. A reference is taken on the input
12689 : * dataset.
12690 : *
12691 : * @since 3.12
12692 : */
12693 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12694 : {
12695 : #ifndef HAVE_MUPARSER
12696 : (void)constant;
12697 : (void)other;
12698 : return ThrowIfNotMuparser();
12699 : #else
12700 : return GDALComputedRasterBand(
12701 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12702 : #endif
12703 : }
12704 :
12705 : /************************************************************************/
12706 : /* operator||() */
12707 : /************************************************************************/
12708 :
12709 : /** Return a band whose value is 1 if the pixel value of the left or right
12710 : * operands is true.
12711 : *
12712 : * The resulting band is lazy evaluated. A reference is taken on the input
12713 : * dataset.
12714 : *
12715 : * @since 3.12
12716 : */
12717 : GDALComputedRasterBand
12718 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12719 : {
12720 : #ifndef HAVE_MUPARSER
12721 : (void)other;
12722 : return ThrowIfNotMuparser();
12723 : #else
12724 4 : ThrowIfNotSameDimensions(*this, other);
12725 : return GDALComputedRasterBand(
12726 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12727 : #endif
12728 : }
12729 :
12730 : /************************************************************************/
12731 : /* operator||() */
12732 : /************************************************************************/
12733 :
12734 : /** Return a band whose value is 1 if the pixel value of the left operand
12735 : * is true, or if the constant is true
12736 : *
12737 : * The resulting band is lazy evaluated. A reference is taken on the input
12738 : * dataset.
12739 : *
12740 : * @since 3.12
12741 : */
12742 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12743 : {
12744 : #ifndef HAVE_MUPARSER
12745 : (void)constant;
12746 : return ThrowIfNotMuparser();
12747 : #else
12748 : return GDALComputedRasterBand(
12749 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12750 : #endif
12751 : }
12752 :
12753 : /************************************************************************/
12754 : /* operator||() */
12755 : /************************************************************************/
12756 :
12757 : /** Return a band whose value is 1 if the constant is true, or
12758 : * the pixel value of the right operand is true
12759 : *
12760 : * The resulting band is lazy evaluated. A reference is taken on the input
12761 : * dataset.
12762 : *
12763 : * @since 3.12
12764 : */
12765 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12766 : {
12767 : #ifndef HAVE_MUPARSER
12768 : (void)constant;
12769 : (void)other;
12770 : return ThrowIfNotMuparser();
12771 : #else
12772 : return GDALComputedRasterBand(
12773 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12774 : #endif
12775 : }
12776 :
12777 : #if defined(__GNUC__)
12778 : #pragma GCC diagnostic pop
12779 : #endif
12780 :
12781 : /************************************************************************/
12782 : /* operator!() */
12783 : /************************************************************************/
12784 :
12785 : /** Return a band whose value is the logical negation of the pixel value
12786 : *
12787 : * The resulting band is lazy evaluated. A reference is taken on the input
12788 : * dataset.
12789 : *
12790 : * @since 3.12
12791 : */
12792 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12793 : {
12794 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12795 2 : *this, true);
12796 : }
12797 :
12798 : namespace gdal
12799 : {
12800 :
12801 : /************************************************************************/
12802 : /* IfThenElse() */
12803 : /************************************************************************/
12804 :
12805 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12806 : * is not zero, or the one from elseBand otherwise.
12807 : *
12808 : * Variants of this method exits where thenBand and/or elseBand can be double
12809 : * values.
12810 : *
12811 : * The resulting band is lazy evaluated. A reference is taken on the input
12812 : * datasets.
12813 : *
12814 : * This method is the same as the C function GDALRasterBandIfThenElse()
12815 : *
12816 : * @since 3.12
12817 : */
12818 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12819 : const GDALRasterBand &thenBand,
12820 : const GDALRasterBand &elseBand)
12821 : {
12822 : #ifndef HAVE_MUPARSER
12823 : (void)condBand;
12824 : (void)thenBand;
12825 : (void)elseBand;
12826 : return ThrowIfNotMuparser();
12827 : #else
12828 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12829 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12830 : return GDALComputedRasterBand(
12831 : GDALComputedRasterBand::Operation::OP_TERNARY,
12832 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12833 : #endif
12834 : }
12835 :
12836 : //! @cond Doxygen_Suppress
12837 :
12838 : /************************************************************************/
12839 : /* IfThenElse() */
12840 : /************************************************************************/
12841 :
12842 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12843 : * is not zero, or the one from elseBand otherwise.
12844 : *
12845 : * The resulting band is lazy evaluated. A reference is taken on the input
12846 : * datasets.
12847 : *
12848 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12849 : * with thenBand = (condBand * 0) + thenValue
12850 : *
12851 : * @since 3.12
12852 : */
12853 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12854 : double thenValue,
12855 : const GDALRasterBand &elseBand)
12856 : {
12857 : #ifndef HAVE_MUPARSER
12858 : (void)condBand;
12859 : (void)thenValue;
12860 : (void)elseBand;
12861 : return ThrowIfNotMuparser();
12862 : #else
12863 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12864 : auto thenBand =
12865 1 : (condBand * 0)
12866 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12867 1 : thenValue;
12868 : return GDALComputedRasterBand(
12869 : GDALComputedRasterBand::Operation::OP_TERNARY,
12870 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12871 : #endif
12872 : }
12873 :
12874 : /************************************************************************/
12875 : /* IfThenElse() */
12876 : /************************************************************************/
12877 :
12878 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12879 : * is not zero, or the one from elseValue otherwise.
12880 : *
12881 : * The resulting band is lazy evaluated. A reference is taken on the input
12882 : * datasets.
12883 : *
12884 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12885 : * with elseBand = (condBand * 0) + elseValue
12886 :
12887 : * @since 3.12
12888 : */
12889 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12890 : const GDALRasterBand &thenBand,
12891 : double elseValue)
12892 : {
12893 : #ifndef HAVE_MUPARSER
12894 : (void)condBand;
12895 : (void)thenBand;
12896 : (void)elseValue;
12897 : return ThrowIfNotMuparser();
12898 : #else
12899 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12900 : auto elseBand =
12901 1 : (condBand * 0)
12902 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12903 1 : elseValue;
12904 : return GDALComputedRasterBand(
12905 : GDALComputedRasterBand::Operation::OP_TERNARY,
12906 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12907 : #endif
12908 : }
12909 :
12910 : /************************************************************************/
12911 : /* IfThenElse() */
12912 : /************************************************************************/
12913 :
12914 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12915 : * is not zero, or the one from elseValue otherwise.
12916 : *
12917 : * The resulting band is lazy evaluated. A reference is taken on the input
12918 : * datasets.
12919 : *
12920 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12921 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12922 : *
12923 : * @since 3.12
12924 : */
12925 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12926 : double thenValue, double elseValue)
12927 : {
12928 : #ifndef HAVE_MUPARSER
12929 : (void)condBand;
12930 : (void)thenValue;
12931 : (void)elseValue;
12932 : return ThrowIfNotMuparser();
12933 : #else
12934 : auto thenBand =
12935 3 : (condBand * 0)
12936 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12937 6 : thenValue;
12938 : auto elseBand =
12939 3 : (condBand * 0)
12940 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12941 3 : elseValue;
12942 : return GDALComputedRasterBand(
12943 : GDALComputedRasterBand::Operation::OP_TERNARY,
12944 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12945 : #endif
12946 : }
12947 :
12948 : //! @endcond
12949 :
12950 : } // namespace gdal
12951 :
12952 : /************************************************************************/
12953 : /* GDALRasterBandIfThenElse() */
12954 : /************************************************************************/
12955 :
12956 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12957 : * is not zero, or the one from hElseBand otherwise.
12958 : *
12959 : * The resulting band is lazy evaluated. A reference is taken on the input
12960 : * datasets.
12961 : *
12962 : * This function is the same as the C++ method gdal::IfThenElse()
12963 : *
12964 : * @since 3.12
12965 : */
12966 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12967 : GDALRasterBandH hThenBand,
12968 : GDALRasterBandH hElseBand)
12969 : {
12970 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12971 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12972 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12973 : #ifndef HAVE_MUPARSER
12974 : CPLError(CE_Failure, CPLE_NotSupported,
12975 : "Band comparison operators not available on a GDAL build without "
12976 : "muparser");
12977 : return nullptr;
12978 : #else
12979 :
12980 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12981 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12982 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12983 : try
12984 : {
12985 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12986 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12987 : }
12988 2 : catch (const std::exception &e)
12989 : {
12990 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12991 2 : return nullptr;
12992 : }
12993 : return new GDALComputedRasterBand(
12994 : GDALComputedRasterBand::Operation::OP_TERNARY,
12995 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12996 : #endif
12997 : }
12998 :
12999 : /************************************************************************/
13000 : /* GDALRasterBand::AsType() */
13001 : /************************************************************************/
13002 :
13003 : /** Cast this band to another type.
13004 : *
13005 : * The resulting band is lazy evaluated. A reference is taken on the input
13006 : * dataset.
13007 : *
13008 : * This method is the same as the C function GDALRasterBandAsDataType()
13009 : *
13010 : * @since 3.12
13011 : */
13012 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
13013 : {
13014 10 : if (dt == GDT_Unknown)
13015 : {
13016 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
13017 : }
13018 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
13019 9 : *this, dt);
13020 : }
13021 :
13022 : /************************************************************************/
13023 : /* GDALRasterBandAsDataType() */
13024 : /************************************************************************/
13025 :
13026 : /** Cast this band to another type.
13027 : *
13028 : * The resulting band is lazy evaluated. A reference is taken on the input
13029 : * dataset.
13030 : *
13031 : * This function is the same as the C++ method GDALRasterBand::AsType()
13032 : *
13033 : * @since 3.12
13034 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13035 : */
13036 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
13037 : GDALDataType eDT)
13038 : {
13039 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
13040 16 : if (eDT == GDT_Unknown)
13041 : {
13042 1 : CPLError(CE_Failure, CPLE_NotSupported,
13043 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
13044 1 : return nullptr;
13045 : }
13046 : return new GDALComputedRasterBand(
13047 : GDALComputedRasterBand::Operation::OP_CAST,
13048 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
13049 : }
13050 :
13051 : /************************************************************************/
13052 : /* GetBandVector() */
13053 : /************************************************************************/
13054 :
13055 : static std::vector<const GDALRasterBand *>
13056 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
13057 : {
13058 10 : std::vector<const GDALRasterBand *> bands;
13059 27 : for (size_t i = 0; i < nBandCount; ++i)
13060 : {
13061 20 : if (i > 0)
13062 : {
13063 10 : GDALRasterBand::ThrowIfNotSameDimensions(
13064 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
13065 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
13066 : }
13067 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
13068 : }
13069 7 : return bands;
13070 : }
13071 :
13072 : /************************************************************************/
13073 : /* GDALOperationOnNBands() */
13074 : /************************************************************************/
13075 :
13076 : static GDALComputedRasterBandH
13077 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
13078 : GDALRasterBandH *pahBands)
13079 : {
13080 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
13081 11 : if (nBandCount == 0)
13082 : {
13083 1 : CPLError(CE_Failure, CPLE_AppDefined,
13084 : "At least one band should be passed");
13085 1 : return nullptr;
13086 : }
13087 :
13088 20 : std::vector<const GDALRasterBand *> bands;
13089 : try
13090 : {
13091 10 : bands = GetBandVector(nBandCount, pahBands);
13092 : }
13093 3 : catch (const std::exception &e)
13094 : {
13095 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
13096 3 : return nullptr;
13097 : }
13098 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
13099 : }
13100 :
13101 : /************************************************************************/
13102 : /* GDALMaximumOfNBands() */
13103 : /************************************************************************/
13104 :
13105 : /** Return a band whose each pixel value is the maximum of the corresponding
13106 : * pixel values in the input bands.
13107 : *
13108 : * The resulting band is lazy evaluated. A reference is taken on input
13109 : * datasets.
13110 : *
13111 : * This function is the same as the C ++ method gdal::max()
13112 : *
13113 : * @since 3.12
13114 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13115 : */
13116 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
13117 : GDALRasterBandH *pahBands)
13118 : {
13119 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
13120 4 : nBandCount, pahBands);
13121 : }
13122 :
13123 : /************************************************************************/
13124 : /* gdal::max() */
13125 : /************************************************************************/
13126 :
13127 : namespace gdal
13128 : {
13129 : /** Return a band whose each pixel value is the maximum of the corresponding
13130 : * pixel values in the inputs (bands or constants)
13131 : *
13132 : * The resulting band is lazy evaluated. A reference is taken on input
13133 : * datasets.
13134 : *
13135 : * Two or more bands can be passed.
13136 : *
13137 : * This method is the same as the C function GDALMaximumOfNBands()
13138 : *
13139 : * @since 3.12
13140 : * @throw std::runtime_error if bands do not have the same dimensions.
13141 : */
13142 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
13143 : const GDALRasterBand &second)
13144 : {
13145 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13146 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
13147 1 : first, second);
13148 : }
13149 : } // namespace gdal
13150 :
13151 : /************************************************************************/
13152 : /* GDALRasterBandMaxConstant() */
13153 : /************************************************************************/
13154 :
13155 : /** Return a band whose each pixel value is the maximum of the corresponding
13156 : * pixel values in the input band and the constant.
13157 : *
13158 : * The resulting band is lazy evaluated. A reference is taken on the input
13159 : * dataset.
13160 : *
13161 : * This function is the same as the C ++ method gdal::max()
13162 : *
13163 : * @since 3.12
13164 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13165 : */
13166 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
13167 : double dfConstant)
13168 : {
13169 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13170 : GDALComputedRasterBand::Operation::OP_MAX,
13171 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13172 6 : dfConstant));
13173 : }
13174 :
13175 : /************************************************************************/
13176 : /* GDALMinimumOfNBands() */
13177 : /************************************************************************/
13178 :
13179 : /** Return a band whose each pixel value is the minimum of the corresponding
13180 : * pixel values in the input bands.
13181 : *
13182 : * The resulting band is lazy evaluated. A reference is taken on input
13183 : * datasets.
13184 : *
13185 : * This function is the same as the C ++ method gdal::min()
13186 : *
13187 : * @since 3.12
13188 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13189 : */
13190 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
13191 : GDALRasterBandH *pahBands)
13192 : {
13193 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
13194 4 : nBandCount, pahBands);
13195 : }
13196 :
13197 : /************************************************************************/
13198 : /* gdal::min() */
13199 : /************************************************************************/
13200 :
13201 : namespace gdal
13202 : {
13203 : /** Return a band whose each pixel value is the minimum of the corresponding
13204 : * pixel values in the inputs (bands or constants)
13205 : *
13206 : * The resulting band is lazy evaluated. A reference is taken on input
13207 : * datasets.
13208 : *
13209 : * Two or more bands can be passed.
13210 : *
13211 : * This method is the same as the C function GDALMinimumOfNBands()
13212 : *
13213 : * @since 3.12
13214 : * @throw std::runtime_error if bands do not have the same dimensions.
13215 : */
13216 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
13217 : const GDALRasterBand &second)
13218 : {
13219 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13220 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
13221 0 : first, second);
13222 : }
13223 : } // namespace gdal
13224 :
13225 : /************************************************************************/
13226 : /* GDALRasterBandMinConstant() */
13227 : /************************************************************************/
13228 :
13229 : /** Return a band whose each pixel value is the minimum of the corresponding
13230 : * pixel values in the input band and the constant.
13231 : *
13232 : * The resulting band is lazy evaluated. A reference is taken on the input
13233 : * dataset.
13234 : *
13235 : * This function is the same as the C ++ method gdal::min()
13236 : *
13237 : * @since 3.12
13238 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13239 : */
13240 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
13241 : double dfConstant)
13242 : {
13243 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
13244 : GDALComputedRasterBand::Operation::OP_MIN,
13245 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
13246 6 : dfConstant));
13247 : }
13248 :
13249 : /************************************************************************/
13250 : /* GDALMeanOfNBands() */
13251 : /************************************************************************/
13252 :
13253 : /** Return a band whose each pixel value is the arithmetic mean of the
13254 : * corresponding pixel values in the input bands.
13255 : *
13256 : * The resulting band is lazy evaluated. A reference is taken on input
13257 : * datasets.
13258 : *
13259 : * This function is the same as the C ++ method gdal::mean()
13260 : *
13261 : * @since 3.12
13262 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
13263 : */
13264 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
13265 : GDALRasterBandH *pahBands)
13266 : {
13267 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
13268 3 : nBandCount, pahBands);
13269 : }
13270 :
13271 : /************************************************************************/
13272 : /* gdal::mean() */
13273 : /************************************************************************/
13274 :
13275 : namespace gdal
13276 : {
13277 :
13278 : /** Return a band whose each pixel value is the arithmetic mean of the
13279 : * corresponding pixel values in the input bands.
13280 : *
13281 : * The resulting band is lazy evaluated. A reference is taken on input
13282 : * datasets.
13283 : *
13284 : * Two or more bands can be passed.
13285 : *
13286 : * This method is the same as the C function GDALMeanOfNBands()
13287 : *
13288 : * @since 3.12
13289 : * @throw std::runtime_error if bands do not have the same dimensions.
13290 : */
13291 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
13292 : const GDALRasterBand &second)
13293 : {
13294 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
13295 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
13296 0 : first, second);
13297 : }
13298 : } // namespace gdal
13299 :
13300 : /************************************************************************/
13301 : /* gdal::abs() */
13302 : /************************************************************************/
13303 :
13304 : namespace gdal
13305 : {
13306 :
13307 : /** Return a band whose each pixel value is the absolute value (or module
13308 : * for complex data type) of the corresponding pixel value in the input band.
13309 : *
13310 : * The resulting band is lazy evaluated. A reference is taken on input
13311 : * datasets.
13312 : *
13313 : * @since 3.12
13314 : */
13315 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
13316 : {
13317 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13318 1 : band);
13319 : }
13320 : } // namespace gdal
13321 :
13322 : /************************************************************************/
13323 : /* gdal::fabs() */
13324 : /************************************************************************/
13325 :
13326 : namespace gdal
13327 : {
13328 :
13329 : /** Return a band whose each pixel value is the absolute value (or module
13330 : * for complex data type) of the corresponding pixel value in the input band.
13331 : *
13332 : * The resulting band is lazy evaluated. A reference is taken on input
13333 : * datasets.
13334 : *
13335 : * @since 3.12
13336 : */
13337 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
13338 : {
13339 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
13340 1 : band);
13341 : }
13342 : } // namespace gdal
13343 :
13344 : /************************************************************************/
13345 : /* gdal::sqrt() */
13346 : /************************************************************************/
13347 :
13348 : namespace gdal
13349 : {
13350 :
13351 : /** Return a band whose each pixel value is the square root of the
13352 : * corresponding pixel value in the input band.
13353 : *
13354 : * The resulting band is lazy evaluated. A reference is taken on input
13355 : * datasets.
13356 : *
13357 : * @since 3.12
13358 : */
13359 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
13360 : {
13361 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
13362 1 : band);
13363 : }
13364 : } // namespace gdal
13365 :
13366 : /************************************************************************/
13367 : /* gdal::log() */
13368 : /************************************************************************/
13369 :
13370 : namespace gdal
13371 : {
13372 :
13373 : /** Return a band whose each pixel value is the natural logarithm of the
13374 : * corresponding pixel value in the input band.
13375 : *
13376 : * The resulting band is lazy evaluated. A reference is taken on input
13377 : * datasets.
13378 : *
13379 : * @since 3.12
13380 : */
13381 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
13382 : {
13383 : #ifndef HAVE_MUPARSER
13384 : (void)band;
13385 : return ThrowIfNotMuparser();
13386 : #else
13387 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
13388 1 : band);
13389 : #endif
13390 : }
13391 : } // namespace gdal
13392 :
13393 : /************************************************************************/
13394 : /* gdal::log10() */
13395 : /************************************************************************/
13396 :
13397 : namespace gdal
13398 : {
13399 :
13400 : /** Return a band whose each pixel value is the logarithm base 10 of the
13401 : * corresponding pixel value in the input band.
13402 : *
13403 : * The resulting band is lazy evaluated. A reference is taken on input
13404 : * datasets.
13405 : *
13406 : * @since 3.12
13407 : */
13408 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
13409 : {
13410 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
13411 1 : band);
13412 : }
13413 : } // namespace gdal
13414 :
13415 : /************************************************************************/
13416 : /* gdal::pow() */
13417 : /************************************************************************/
13418 :
13419 : namespace gdal
13420 : {
13421 :
13422 : #ifndef DOXYGEN_SKIP
13423 : /** Return a band whose each pixel value is the constant raised to the power of
13424 : * the corresponding pixel value in the input band.
13425 : *
13426 : * The resulting band is lazy evaluated. A reference is taken on input
13427 : * datasets.
13428 : *
13429 : * @since 3.12
13430 : */
13431 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
13432 : {
13433 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13434 1 : constant, band);
13435 : }
13436 : #endif
13437 :
13438 : } // namespace gdal
13439 :
13440 : /************************************************************************/
13441 : /* gdal::pow() */
13442 : /************************************************************************/
13443 :
13444 : namespace gdal
13445 : {
13446 :
13447 : /** Return a band whose each pixel value is the the corresponding pixel value
13448 : * in the input band raised to the power of the constant.
13449 : *
13450 : * The resulting band is lazy evaluated. A reference is taken on input
13451 : * datasets.
13452 : *
13453 : * @since 3.12
13454 : */
13455 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
13456 : {
13457 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13458 1 : band, constant);
13459 : }
13460 : } // namespace gdal
13461 :
13462 : /************************************************************************/
13463 : /* gdal::pow() */
13464 : /************************************************************************/
13465 :
13466 : namespace gdal
13467 : {
13468 :
13469 : #ifndef DOXYGEN_SKIP
13470 : /** Return a band whose each pixel value is the the corresponding pixel value
13471 : * in the input band1 raised to the power of the corresponding pixel value
13472 : * in the input band2
13473 : *
13474 : * The resulting band is lazy evaluated. A reference is taken on input
13475 : * datasets.
13476 : *
13477 : * @since 3.12
13478 : * @throw std::runtime_error if bands do not have the same dimensions.
13479 : */
13480 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
13481 : const GDALRasterBand &band2)
13482 : {
13483 : #ifndef HAVE_MUPARSER
13484 : (void)band1;
13485 : (void)band2;
13486 : return ThrowIfNotMuparser();
13487 : #else
13488 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
13489 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
13490 1 : band1, band2);
13491 : #endif
13492 : }
13493 : #endif
13494 : } // namespace gdal
|