Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Base class for format specific band class implementation. This
5 : * base class provides default implementation for many methods.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, Frank Warmerdam
10 : * Copyright (c) 2007-2016, Even Rouault <even dot rouault at spatialys dot com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "cpl_float.h"
17 :
18 : #include <cassert>
19 : #include <climits>
20 : #include <cmath>
21 : #include <cstdarg>
22 : #include <cstddef>
23 : #include <cstdio>
24 : #include <cstdlib>
25 : #include <cstring>
26 : #include <algorithm>
27 : #include <limits>
28 : #include <memory>
29 : #include <new>
30 : #include <type_traits>
31 :
32 : #include "cpl_conv.h"
33 : #include "cpl_error.h"
34 : #include "cpl_float.h"
35 : #include "cpl_progress.h"
36 : #include "cpl_string.h"
37 : #include "cpl_virtualmem.h"
38 : #include "cpl_vsi.h"
39 : #include "gdal.h"
40 : #include "gdal_abstractbandblockcache.h"
41 : #include "gdalantirecursion.h"
42 : #include "gdal_rat.h"
43 : #include "gdal_rasterband.h"
44 : #include "gdal_priv_templates.hpp"
45 : #include "gdal_interpolateatpoint.h"
46 : #include "gdal_minmax_element.hpp"
47 : #include "gdalmultidim_priv.h"
48 :
49 : #if defined(__AVX2__) || defined(__FMA__)
50 : #include <immintrin.h>
51 : #endif
52 :
53 : /************************************************************************/
54 : /* GDALRasterBand() */
55 : /************************************************************************/
56 :
57 : /*! Constructor. Applications should never create GDALRasterBands directly. */
58 :
59 1573270 : GDALRasterBand::GDALRasterBand()
60 : : GDALRasterBand(
61 1573270 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
62 : {
63 1573270 : }
64 :
65 : /** Constructor. Applications should never create GDALRasterBands directly.
66 : * @param bForceCachedIOIn Whether cached IO should be forced.
67 : */
68 1853200 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
69 1853200 : : bForceCachedIO(bForceCachedIOIn)
70 :
71 : {
72 1853200 : }
73 :
74 : /************************************************************************/
75 : /* ~GDALRasterBand() */
76 : /************************************************************************/
77 :
78 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
79 : instead destroy the GDALDataset. */
80 :
81 1853190 : GDALRasterBand::~GDALRasterBand()
82 :
83 : {
84 1853190 : if (poDS && poDS->IsMarkedSuppressOnClose())
85 : {
86 573 : if (poBandBlockCache)
87 510 : poBandBlockCache->DisableDirtyBlockWriting();
88 : }
89 1853190 : GDALRasterBand::FlushCache(true);
90 :
91 1853190 : delete poBandBlockCache;
92 :
93 1853190 : if (static_cast<GIntBig>(nBlockReads) >
94 1853190 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
95 229 : nBand == 1 && poDS != nullptr)
96 : {
97 338 : CPLDebug(
98 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
99 169 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
100 169 : poDS->GetDescription());
101 : }
102 :
103 1853190 : InvalidateMaskBand();
104 1853190 : nBand = -nBand;
105 :
106 1853190 : delete m_poPointsCache;
107 1853190 : }
108 :
109 : /************************************************************************/
110 : /* RasterIO() */
111 : /************************************************************************/
112 :
113 : /**
114 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
115 : * int nXOff, int nYOff, int nXSize, int nYSize,
116 : * void * pData, int nBufXSize, int nBufYSize,
117 : * GDALDataType eBufType,
118 : * GSpacing nPixelSpace,
119 : * GSpacing nLineSpace,
120 : * GDALRasterIOExtraArg* psExtraArg )
121 : * \brief Read/write a region of image data for this band.
122 : *
123 : * This method allows reading a region of a GDALRasterBand into a buffer,
124 : * or writing data from a buffer into a region of a GDALRasterBand. It
125 : * automatically takes care of data type translation if the data type
126 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
127 : * The method also takes care of image decimation / replication if the
128 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
129 : * region being accessed (nXSize x nYSize).
130 : *
131 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
132 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
133 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
134 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
135 : * Or use nLineSpace and a possibly shifted pData value.
136 : *
137 : * The nPixelSpace and nLineSpace parameters allow reading into or
138 : * writing from unusually organized buffers. This is primarily used
139 : * for buffers containing more than one bands raster data in interleaved
140 : * format.
141 : *
142 : * Some formats may efficiently implement decimation into a buffer by
143 : * reading from lower resolution overview images. The logic of the default
144 : * implementation in the base class GDALRasterBand is the following one. It
145 : * computes a target_downscaling_factor from the window of interest and buffer
146 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
147 : * It then walks through overviews and will select the first one whose
148 : * downscaling factor is greater than target_downscaling_factor / 1.2.
149 : *
150 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
151 : * The relationship between target_downscaling_factor and the select overview
152 : * level is the following one:
153 : *
154 : * target_downscaling_factor | selected_overview
155 : * ------------------------- | -----------------
156 : * ]0, 2 / 1.2] | full resolution band
157 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
158 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
159 : * ]8 / 1.2, infinity[ | 8x downsampled band
160 : *
161 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
162 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
163 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
164 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
165 : * this oversampling threshold defaults to 1. Consequently if there are overviews
166 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
167 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
168 : *
169 : * For highest performance full resolution data access, read and write
170 : * on "block boundaries" as returned by GetBlockSize(), or use the
171 : * ReadBlock() and WriteBlock() methods.
172 : *
173 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
174 : * functions.
175 : *
176 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
177 : * write a region of data.
178 : *
179 : * @param nXOff The pixel offset to the top left corner of the region
180 : * of the band to be accessed. This would be zero to start from the left side.
181 : *
182 : * @param nYOff The line offset to the top left corner of the region
183 : * of the band to be accessed. This would be zero to start from the top.
184 : *
185 : * @param nXSize The width of the region of the band to be accessed in pixels.
186 : *
187 : * @param nYSize The height of the region of the band to be accessed in lines.
188 : *
189 : * @param pData The buffer into which the data should be read, or from which
190 : * it should be written. This buffer must contain at least nBufXSize *
191 : * nBufYSize words of type eBufType. It is organized in left to right,
192 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
193 : * and nLineSpace parameters.
194 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
195 : * temporarily modified during the execution of this method (and eventually
196 : * restored back to its original content), so it is not safe to use a buffer
197 : * stored in a read-only section of the calling program.
198 : *
199 : * @param nBufXSize the width of the buffer image into which the desired region
200 : * is to be read, or from which it is to be written.
201 : *
202 : * @param nBufYSize the height of the buffer image into which the desired region
203 : * is to be read, or from which it is to be written.
204 : *
205 : * @param eBufType the type of the pixel values in the pData data buffer. The
206 : * pixel values will automatically be translated to/from the GDALRasterBand
207 : * data type as needed. Most driver implementations will use GDALCopyWords64()
208 : * to perform data type translation.
209 : *
210 : * @param nPixelSpace The byte offset from the start of one pixel value in
211 : * pData to the start of the next pixel value within a scanline. If defaulted
212 : * (0) the size of the datatype eBufType is used.
213 : *
214 : * @param nLineSpace The byte offset from the start of one scanline in
215 : * pData to the start of the next. If defaulted (0) the size of the datatype
216 : * eBufType * nBufXSize is used.
217 : *
218 : * @param psExtraArg Pointer to a GDALRasterIOExtraArg
219 : * structure with additional arguments to specify resampling and progress
220 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
221 : * configuration option can also be defined to override the default resampling
222 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
223 : *
224 : * @return CE_Failure if the access fails, otherwise CE_None.
225 : */
226 :
227 : /**
228 : * \brief Read/write a region of image data for this band.
229 : *
230 : * This method allows reading a region of a GDALRasterBand into a buffer,
231 : * or writing data from a buffer into a region of a GDALRasterBand. It
232 : * automatically takes care of data type translation if the data type
233 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
234 : * The method also takes care of image decimation / replication if the
235 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
236 : * region being accessed (nXSize x nYSize).
237 : *
238 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
239 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
240 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
241 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
242 : * Or use nLineSpace and a possibly shifted pData value.
243 : *
244 : * The nPixelSpace and nLineSpace parameters allow reading into or
245 : * writing from unusually organized buffers. This is primarily used
246 : * for buffers containing more than one bands raster data in interleaved
247 : * format.
248 : *
249 : * Some formats may efficiently implement decimation into a buffer by
250 : * reading from lower resolution overview images. The logic of the default
251 : * implementation in the base class GDALRasterBand is the following one. It
252 : * computes a target_downscaling_factor from the window of interest and buffer
253 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
254 : * It then walks through overviews and will select the first one whose
255 : * downscaling factor is greater than target_downscaling_factor / 1.2.
256 : *
257 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
258 : * The relationship between target_downscaling_factor and the select overview
259 : * level is the following one:
260 : *
261 : * target_downscaling_factor | selected_overview
262 : * ------------------------- | -----------------
263 : * ]0, 2 / 1.2] | full resolution band
264 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
265 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
266 : * ]8 / 1.2, infinity[ | 8x downsampled band
267 : *
268 : * For highest performance full resolution data access, read and write
269 : * on "block boundaries" as returned by GetBlockSize(), or use the
270 : * ReadBlock() and WriteBlock() methods.
271 : *
272 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
273 : * functions.
274 : *
275 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
276 : * more convenient to use for most common use cases.
277 : *
278 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
279 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
280 : * instance of this dataset) concurrently from several threads.
281 : *
282 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
283 : * write a region of data.
284 : *
285 : * @param nXOff The pixel offset to the top left corner of the region
286 : * of the band to be accessed. This would be zero to start from the left side.
287 : *
288 : * @param nYOff The line offset to the top left corner of the region
289 : * of the band to be accessed. This would be zero to start from the top.
290 : *
291 : * @param nXSize The width of the region of the band to be accessed in pixels.
292 : *
293 : * @param nYSize The height of the region of the band to be accessed in lines.
294 : *
295 : * @param[in,out] pData The buffer into which the data should be read, or from
296 : * which it should be written. This buffer must contain at least nBufXSize *
297 : * nBufYSize words of type eBufType. It is organized in left to right,
298 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
299 : * and nLineSpace parameters.
300 : *
301 : * @param nBufXSize the width of the buffer image into which the desired region
302 : * is to be read, or from which it is to be written.
303 : *
304 : * @param nBufYSize the height of the buffer image into which the desired region
305 : * is to be read, or from which it is to be written.
306 : *
307 : * @param eBufType the type of the pixel values in the pData data buffer. The
308 : * pixel values will automatically be translated to/from the GDALRasterBand
309 : * data type as needed.
310 : *
311 : * @param nPixelSpace The byte offset from the start of one pixel value in
312 : * pData to the start of the next pixel value within a scanline. If defaulted
313 : * (0) the size of the datatype eBufType is used.
314 : *
315 : * @param nLineSpace The byte offset from the start of one scanline in
316 : * pData to the start of the next. If defaulted (0) the size of the datatype
317 : * eBufType * nBufXSize is used.
318 : *
319 : * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
320 : * structure with additional arguments to specify resampling and progress
321 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
322 : * configuration option can also be defined to override the default resampling
323 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
324 : *
325 : * @return CE_Failure if the access fails, otherwise CE_None.
326 : *
327 : * @see GDALRasterBand::ReadRaster()
328 : */
329 :
330 4414300 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
331 : int nXSize, int nYSize, void *pData,
332 : int nBufXSize, int nBufYSize,
333 : GDALDataType eBufType, GSpacing nPixelSpace,
334 : GSpacing nLineSpace,
335 : GDALRasterIOExtraArg *psExtraArg)
336 :
337 : {
338 : GDALRasterIOExtraArg sExtraArg;
339 4414300 : if (psExtraArg == nullptr)
340 : {
341 3816830 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
342 3816830 : psExtraArg = &sExtraArg;
343 : }
344 597476 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
345 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
346 : {
347 0 : ReportError(CE_Failure, CPLE_AppDefined,
348 : "Unhandled version of GDALRasterIOExtraArg");
349 0 : return CE_Failure;
350 : }
351 :
352 4414300 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
353 : nBufYSize);
354 :
355 4414300 : if (CPL_UNLIKELY(nullptr == pData))
356 : {
357 0 : ReportError(CE_Failure, CPLE_AppDefined,
358 : "The buffer into which the data should be read is null");
359 0 : return CE_Failure;
360 : }
361 :
362 : /* -------------------------------------------------------------------- */
363 : /* Some size values are "noop". Lets just return to avoid */
364 : /* stressing lower level functions. */
365 : /* -------------------------------------------------------------------- */
366 4414300 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
367 : nBufYSize < 1))
368 : {
369 2 : CPLDebug("GDAL",
370 : "RasterIO() skipped for odd window or buffer size.\n"
371 : " Window = (%d,%d)x%dx%d\n"
372 : " Buffer = %dx%d\n",
373 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
374 :
375 2 : return CE_None;
376 : }
377 :
378 4414300 : if (eRWFlag == GF_Write)
379 : {
380 366201 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
381 : {
382 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
383 : "An error occurred while writing a dirty block "
384 : "from GDALRasterBand::RasterIO");
385 0 : CPLErr eErr = eFlushBlockErr;
386 0 : eFlushBlockErr = CE_None;
387 0 : return eErr;
388 : }
389 366201 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
390 : {
391 7 : return CE_Failure;
392 : }
393 : }
394 :
395 : /* -------------------------------------------------------------------- */
396 : /* If pixel and line spacing are defaulted assign reasonable */
397 : /* value assuming a packed buffer. */
398 : /* -------------------------------------------------------------------- */
399 4414290 : if (nPixelSpace == 0)
400 : {
401 4016280 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
402 : }
403 :
404 4414290 : if (nLineSpace == 0)
405 : {
406 4006330 : nLineSpace = nPixelSpace * nBufXSize;
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Do some validation of parameters. */
411 : /* -------------------------------------------------------------------- */
412 4414290 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
413 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
414 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
415 : {
416 15 : ReportError(CE_Failure, CPLE_IllegalArg,
417 : "Access window out of range in RasterIO(). Requested\n"
418 : "(%d,%d) of size %dx%d on raster of %dx%d.",
419 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
420 15 : return CE_Failure;
421 : }
422 :
423 4414280 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
424 : {
425 0 : ReportError(
426 : CE_Failure, CPLE_IllegalArg,
427 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
428 : eRWFlag);
429 0 : return CE_Failure;
430 : }
431 4414280 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
432 : {
433 2 : ReportError(CE_Failure, CPLE_IllegalArg,
434 : "Illegal GDT_Unknown/GDT_TypeCount argument");
435 2 : return CE_Failure;
436 : }
437 :
438 4414280 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
439 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
440 4414280 : nLineSpace, psExtraArg);
441 : }
442 :
443 : /************************************************************************/
444 : /* RasterIOInternal() */
445 : /************************************************************************/
446 :
447 4414310 : CPLErr GDALRasterBand::RasterIOInternal(
448 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
449 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
450 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
451 : {
452 : /* -------------------------------------------------------------------- */
453 : /* Call the format specific function. */
454 : /* -------------------------------------------------------------------- */
455 :
456 4414310 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
457 :
458 : CPLErr eErr;
459 4414310 : if (bForceCachedIO)
460 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
461 : pData, nBufXSize, nBufYSize, eBufType,
462 : nPixelSpace, nLineSpace, psExtraArg);
463 : else
464 : eErr =
465 4414290 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
466 4414290 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
467 :
468 4414310 : if (bCallLeaveReadWrite)
469 601042 : LeaveReadWrite();
470 :
471 4414310 : return eErr;
472 : }
473 :
474 : /************************************************************************/
475 : /* GDALRasterIO() */
476 : /************************************************************************/
477 :
478 : /**
479 : * \brief Read/write a region of image data for this band.
480 : *
481 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
482 : * resolution, progress callback, etc. are needed)
483 : *
484 : * @see GDALRasterBand::RasterIO()
485 : */
486 :
487 3403470 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
488 : int nXOff, int nYOff, int nXSize, int nYSize,
489 : void *pData, int nBufXSize, int nBufYSize,
490 : GDALDataType eBufType, int nPixelSpace,
491 : int nLineSpace)
492 :
493 : {
494 3403470 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
495 :
496 3403470 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
497 :
498 3403470 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
499 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
500 3403470 : nLineSpace, nullptr));
501 : }
502 :
503 : /************************************************************************/
504 : /* GDALRasterIOEx() */
505 : /************************************************************************/
506 :
507 : /**
508 : * \brief Read/write a region of image data for this band.
509 : *
510 : * @see GDALRasterBand::RasterIO()
511 : */
512 :
513 40734 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
514 : int nXOff, int nYOff, int nXSize, int nYSize,
515 : void *pData, int nBufXSize, int nBufYSize,
516 : GDALDataType eBufType, GSpacing nPixelSpace,
517 : GSpacing nLineSpace,
518 : GDALRasterIOExtraArg *psExtraArg)
519 :
520 : {
521 40734 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
522 :
523 40734 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
524 :
525 40734 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
526 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
527 40734 : nLineSpace, psExtraArg));
528 : }
529 :
530 : /************************************************************************/
531 : /* GetGDTFromCppType() */
532 : /************************************************************************/
533 :
534 : namespace
535 : {
536 : template <class T> struct GetGDTFromCppType;
537 :
538 : #define DEFINE_GetGDTFromCppType(T, eDT) \
539 : template <> struct GetGDTFromCppType<T> \
540 : { \
541 : static constexpr GDALDataType GDT = eDT; \
542 : }
543 :
544 : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
545 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
546 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
547 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
548 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
549 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
550 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
551 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
552 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
553 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
554 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
555 : // Not allowed by C++ standard
556 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
557 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
558 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
559 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
560 : } // namespace
561 :
562 : /************************************************************************/
563 : /* ReadRaster() */
564 : /************************************************************************/
565 :
566 : // clang-format off
567 : /** Read a region of image data for this band.
568 : *
569 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
570 : * for common use cases, like reading a whole band.
571 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
572 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
573 : * float, double, std::complex<float|double>.
574 : *
575 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
576 : * and can allocate memory automatically.
577 : *
578 : * To read a whole band (assuming it fits into memory), as an array of double:
579 : *
580 : \code{.cpp}
581 : double* myArray = static_cast<double*>(
582 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
583 : // TODO: check here that myArray != nullptr
584 : const size_t nArrayEltCount =
585 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
586 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
587 : {
588 : // do something
589 : }
590 : VSIFree(myArray)
591 : \endcode
592 : *
593 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
594 : *
595 : \code{.cpp}
596 : double* myArray = static_cast<double*>(
597 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
598 : // TODO: check here that myArray != nullptr
599 : const size_t nArrayEltCount = 128 * 128;
600 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
601 : {
602 : // do something
603 : }
604 : VSIFree(myArray)
605 : \endcode
606 : *
607 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
608 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
609 : * instance of this dataset) concurrently from several threads.
610 : *
611 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
612 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
613 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
614 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
615 : * Or use nLineSpace and a possibly shifted pData value.
616 : *
617 : * @param[out] pData The buffer into which the data should be written.
618 : * This buffer must contain at least nBufXSize *
619 : * nBufYSize words of type T. It is organized in left to right,
620 : * top to bottom pixel order, and fully packed.
621 : * The type of the buffer does not need to be the one of GetDataType(). The
622 : * method will perform data type translation (with potential rounding, clamping)
623 : * if needed.
624 : *
625 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
626 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
627 : * return in error if it is not. If set to zero, then pData is trusted to be
628 : * large enough.
629 : *
630 : * @param dfXOff The pixel offset to the top left corner of the region
631 : * of the band to be accessed. This would be zero to start from the left side.
632 : * Defaults to 0.
633 : *
634 : * @param dfYOff The line offset to the top left corner of the region
635 : * of the band to be accessed. This would be zero to start from the top.
636 : * Defaults to 0.
637 : *
638 : * @param dfXSize The width of the region of the band to be accessed in pixels.
639 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
640 : * dfXSize is set to the band width.
641 : *
642 : * @param dfYSize The height of the region of the band to be accessed in lines.
643 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
644 : * dfYSize is set to the band height.
645 : *
646 : * @param nBufXSize the width of the buffer image into which the desired region
647 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
648 : * then nBufXSize is initialized with dfXSize.
649 : *
650 : * @param nBufYSize the height of the buffer image into which the desired region
651 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
652 : * then nBufYSize is initialized with dfYSize.
653 : *
654 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
655 : *
656 : * @param pfnProgress Progress function. May be nullptr.
657 : *
658 : * @param pProgressData User data of pfnProgress. May be nullptr.
659 : *
660 : * @return CE_Failure if the access fails, otherwise CE_None.
661 : *
662 : * @see GDALRasterBand::RasterIO()
663 : * @since GDAL 3.10
664 : */
665 : // clang-format on
666 :
667 : template <class T>
668 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
669 : double dfXOff, double dfYOff, double dfXSize,
670 : double dfYSize, size_t nBufXSize,
671 : size_t nBufYSize,
672 : GDALRIOResampleAlg eResampleAlg,
673 : GDALProgressFunc pfnProgress,
674 : void *pProgressData) const
675 : {
676 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
677 : {
678 2 : return CE_Failure;
679 : }
680 :
681 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
682 : {
683 16 : dfXSize = nRasterXSize;
684 16 : dfYSize = nRasterYSize;
685 : }
686 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
687 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
688 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
689 2 : dfYOff + dfYSize > INT_MAX)
690 : {
691 0 : return CE_Failure;
692 : }
693 :
694 : GDALRasterIOExtraArg sExtraArg;
695 18 : sExtraArg.nVersion = 1;
696 18 : sExtraArg.eResampleAlg = eResampleAlg;
697 18 : sExtraArg.pfnProgress = pfnProgress;
698 18 : sExtraArg.pProgressData = pProgressData;
699 18 : sExtraArg.bFloatingPointWindowValidity = true;
700 18 : sExtraArg.dfXOff = dfXOff;
701 18 : sExtraArg.dfYOff = dfYOff;
702 18 : sExtraArg.dfXSize = dfXSize;
703 18 : sExtraArg.dfYSize = dfYSize;
704 18 : const int nXOff = static_cast<int>(dfXOff);
705 18 : const int nYOff = static_cast<int>(dfYOff);
706 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
707 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
708 18 : if (nBufXSize == 0 && nBufYSize == 0)
709 : {
710 17 : if (static_cast<int>(dfXSize) == dfXSize &&
711 17 : static_cast<int>(dfYSize) == dfYSize)
712 : {
713 17 : nBufXSize = static_cast<int>(dfXSize);
714 17 : nBufYSize = static_cast<int>(dfYSize);
715 : }
716 : else
717 : {
718 0 : CPLError(CE_Failure, CPLE_AppDefined,
719 : "nBufXSize and nBufYSize must be provided if dfXSize or "
720 : "dfYSize is not an integer value");
721 0 : return CE_Failure;
722 : }
723 : }
724 18 : if (nBufXSize == 0 || nBufYSize == 0)
725 : {
726 0 : CPLDebug("GDAL",
727 : "RasterIO() skipped for odd window or buffer size.\n"
728 : " Window = (%d,%d)x%dx%d\n"
729 : " Buffer = %dx%d\n",
730 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
731 : static_cast<int>(nBufYSize));
732 :
733 0 : return CE_None;
734 : }
735 :
736 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
737 : {
738 1 : CPLError(CE_Failure, CPLE_AppDefined,
739 : "Provided array is not large enough");
740 1 : return CE_Failure;
741 : }
742 :
743 17 : constexpr GSpacing nPixelSpace = sizeof(T);
744 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
745 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
746 :
747 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
748 :
749 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
750 : static_cast<int>(nBufXSize),
751 : static_cast<int>(nBufYSize), eBufType,
752 17 : nPixelSpace, nLineSpace, &sExtraArg);
753 : }
754 :
755 : //! @cond Doxygen_Suppress
756 :
757 : #define INSTANTIATE_READ_RASTER(T) \
758 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
759 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
760 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
761 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
762 : void *pProgressData) const;
763 :
764 : INSTANTIATE_READ_RASTER(uint8_t)
765 : INSTANTIATE_READ_RASTER(int8_t)
766 : INSTANTIATE_READ_RASTER(uint16_t)
767 : INSTANTIATE_READ_RASTER(int16_t)
768 : INSTANTIATE_READ_RASTER(uint32_t)
769 : INSTANTIATE_READ_RASTER(int32_t)
770 : INSTANTIATE_READ_RASTER(uint64_t)
771 : INSTANTIATE_READ_RASTER(int64_t)
772 : INSTANTIATE_READ_RASTER(GFloat16)
773 : INSTANTIATE_READ_RASTER(float)
774 : INSTANTIATE_READ_RASTER(double)
775 : // Not allowed by C++ standard
776 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
777 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
778 : INSTANTIATE_READ_RASTER(std::complex<float>)
779 : INSTANTIATE_READ_RASTER(std::complex<double>)
780 :
781 : //! @endcond
782 :
783 : /************************************************************************/
784 : /* ReadRaster() */
785 : /************************************************************************/
786 :
787 : /** Read a region of image data for this band.
788 : *
789 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
790 : * for common use cases, like reading a whole band.
791 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
792 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
793 : * float, double, std::complex<float|double>.
794 : *
795 : * To read a whole band (assuming it fits into memory), as a vector of double:
796 : *
797 : \code
798 : std::vector<double> myArray;
799 : if (poBand->ReadRaster(myArray) == CE_None)
800 : {
801 : // do something
802 : }
803 : \endcode
804 : *
805 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
806 : *
807 : \code{.cpp}
808 : std::vector<double> myArray;
809 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
810 : {
811 : // do something
812 : }
813 : \endcode
814 : *
815 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
816 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
817 : * instance of this dataset) concurrently from several threads.
818 : *
819 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
820 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
821 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
822 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
823 : * Or use nLineSpace and a possibly shifted pData value.
824 : *
825 : * @param[out] vData The vector into which the data should be written.
826 : * The vector will be resized, if needed, to contain at least nBufXSize *
827 : * nBufYSize values. The values in the vector are organized in left to right,
828 : * top to bottom pixel order, and fully packed.
829 : * The type of the vector does not need to be the one of GetDataType(). The
830 : * method will perform data type translation (with potential rounding, clamping)
831 : * if needed.
832 : *
833 : * @param dfXOff The pixel offset to the top left corner of the region
834 : * of the band to be accessed. This would be zero to start from the left side.
835 : * Defaults to 0.
836 : *
837 : * @param dfYOff The line offset to the top left corner of the region
838 : * of the band to be accessed. This would be zero to start from the top.
839 : * Defaults to 0.
840 : *
841 : * @param dfXSize The width of the region of the band to be accessed in pixels.
842 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
843 : * dfXSize is set to the band width.
844 : *
845 : * @param dfYSize The height of the region of the band to be accessed in lines.
846 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
847 : * dfYSize is set to the band height.
848 : *
849 : * @param nBufXSize the width of the buffer image into which the desired region
850 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
851 : * then nBufXSize is initialized with dfXSize.
852 : *
853 : * @param nBufYSize the height of the buffer image into which the desired region
854 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
855 : * then nBufYSize is initialized with dfYSize.
856 : *
857 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
858 : *
859 : * @param pfnProgress Progress function. May be nullptr.
860 : *
861 : * @param pProgressData User data of pfnProgress. May be nullptr.
862 : *
863 : * @return CE_Failure if the access fails, otherwise CE_None.
864 : *
865 : * @see GDALRasterBand::RasterIO()
866 : * @since GDAL 3.10
867 : */
868 : template <class T>
869 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
870 : double dfYOff, double dfXSize, double dfYSize,
871 : size_t nBufXSize, size_t nBufYSize,
872 : GDALRIOResampleAlg eResampleAlg,
873 : GDALProgressFunc pfnProgress,
874 : void *pProgressData) const
875 : {
876 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
877 : {
878 2 : return CE_Failure;
879 : }
880 :
881 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
882 : {
883 13 : dfXSize = nRasterXSize;
884 13 : dfYSize = nRasterYSize;
885 : }
886 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
887 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
888 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
889 7 : dfYOff + dfYSize > INT_MAX)
890 : {
891 0 : return CE_Failure;
892 : }
893 :
894 : GDALRasterIOExtraArg sExtraArg;
895 20 : sExtraArg.nVersion = 1;
896 20 : sExtraArg.eResampleAlg = eResampleAlg;
897 20 : sExtraArg.pfnProgress = pfnProgress;
898 20 : sExtraArg.pProgressData = pProgressData;
899 20 : sExtraArg.bFloatingPointWindowValidity = true;
900 20 : sExtraArg.dfXOff = dfXOff;
901 20 : sExtraArg.dfYOff = dfYOff;
902 20 : sExtraArg.dfXSize = dfXSize;
903 20 : sExtraArg.dfYSize = dfYSize;
904 20 : const int nXOff = static_cast<int>(dfXOff);
905 20 : const int nYOff = static_cast<int>(dfYOff);
906 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
907 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
908 20 : if (nBufXSize == 0 && nBufYSize == 0)
909 : {
910 16 : if (static_cast<int>(dfXSize) == dfXSize &&
911 15 : static_cast<int>(dfYSize) == dfYSize)
912 : {
913 15 : nBufXSize = static_cast<int>(dfXSize);
914 15 : nBufYSize = static_cast<int>(dfYSize);
915 : }
916 : else
917 : {
918 1 : CPLError(CE_Failure, CPLE_AppDefined,
919 : "nBufXSize and nBufYSize must be provided if "
920 : "dfXSize or dfYSize is not an integer value");
921 1 : return CE_Failure;
922 : }
923 : }
924 19 : if (nBufXSize == 0 || nBufYSize == 0)
925 : {
926 0 : CPLDebug("GDAL",
927 : "RasterIO() skipped for odd window or buffer size.\n"
928 : " Window = (%d,%d)x%dx%d\n"
929 : " Buffer = %dx%d\n",
930 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
931 : static_cast<int>(nBufYSize));
932 :
933 0 : return CE_None;
934 : }
935 :
936 : if constexpr (SIZEOF_VOIDP < 8)
937 : {
938 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
939 : {
940 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
941 : return CE_Failure;
942 : }
943 : }
944 :
945 19 : if (vData.size() < nBufXSize * nBufYSize)
946 : {
947 : try
948 : {
949 17 : vData.resize(nBufXSize * nBufYSize);
950 : }
951 1 : catch (const std::exception &)
952 : {
953 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
954 1 : return CE_Failure;
955 : }
956 : }
957 :
958 18 : constexpr GSpacing nPixelSpace = sizeof(T);
959 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
960 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
961 :
962 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
963 :
964 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
965 : vData.data(), static_cast<int>(nBufXSize),
966 : static_cast<int>(nBufYSize), eBufType,
967 18 : nPixelSpace, nLineSpace, &sExtraArg);
968 : }
969 :
970 : //! @cond Doxygen_Suppress
971 :
972 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
973 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
974 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
975 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
976 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
977 : void *pProgressData) const;
978 :
979 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
981 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
982 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
983 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
984 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
985 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
986 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
988 : INSTANTIATE_READ_RASTER_VECTOR(float)
989 : INSTANTIATE_READ_RASTER_VECTOR(double)
990 : // Not allowed by C++ standard
991 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
992 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
993 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
994 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
995 :
996 : //! @endcond
997 :
998 : /************************************************************************/
999 : /* ReadBlock() */
1000 : /************************************************************************/
1001 :
1002 : /**
1003 : * \brief Read a block of image data efficiently.
1004 : *
1005 : * This method accesses a "natural" block from the raster band without
1006 : * resampling, or data type conversion. For a more generalized, but
1007 : * potentially less efficient access use RasterIO().
1008 : *
1009 : * This method is the same as the C GDALReadBlock() function.
1010 : *
1011 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1012 : * block oriented data without an extra copy into an application buffer.
1013 : *
1014 : * The following code would efficiently compute a histogram of eight bit
1015 : * raster data. Note that the final block may be partial ... data beyond
1016 : * the edge of the underlying raster band in these edge blocks is of an
1017 : * undetermined value.
1018 : *
1019 : \code{.cpp}
1020 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1021 :
1022 : {
1023 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1024 :
1025 : CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1026 :
1027 : int nXBlockSize, nYBlockSize;
1028 :
1029 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1030 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1031 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1032 :
1033 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1034 :
1035 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1036 : {
1037 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1038 : {
1039 : int nXValid, nYValid;
1040 :
1041 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1042 :
1043 : // Compute the portion of the block that is valid
1044 : // for partial edge blocks.
1045 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1046 :
1047 : // Collect the histogram counts.
1048 : for( int iY = 0; iY < nYValid; iY++ )
1049 : {
1050 : for( int iX = 0; iX < nXValid; iX++ )
1051 : {
1052 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1053 : }
1054 : }
1055 : }
1056 : }
1057 : }
1058 : \endcode
1059 : *
1060 : * @param nXBlockOff the horizontal block offset, with zero indicating
1061 : * the left most block, 1 the next block and so forth.
1062 : *
1063 : * @param nYBlockOff the vertical block offset, with zero indicating
1064 : * the top most block, 1 the next block and so forth.
1065 : *
1066 : * @param pImage the buffer into which the data will be read. The buffer
1067 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1068 : * of type GetRasterDataType().
1069 : *
1070 : * @return CE_None on success or CE_Failure on an error.
1071 : */
1072 :
1073 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1074 :
1075 : {
1076 : /* -------------------------------------------------------------------- */
1077 : /* Validate arguments. */
1078 : /* -------------------------------------------------------------------- */
1079 894 : CPLAssert(pImage != nullptr);
1080 :
1081 894 : if (!InitBlockInfo())
1082 0 : return CE_Failure;
1083 :
1084 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1085 : {
1086 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1087 : "Illegal nXBlockOff value (%d) in "
1088 : "GDALRasterBand::ReadBlock()\n",
1089 : nXBlockOff);
1090 :
1091 0 : return (CE_Failure);
1092 : }
1093 :
1094 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1095 : {
1096 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1097 : "Illegal nYBlockOff value (%d) in "
1098 : "GDALRasterBand::ReadBlock()\n",
1099 : nYBlockOff);
1100 :
1101 0 : return (CE_Failure);
1102 : }
1103 :
1104 : /* -------------------------------------------------------------------- */
1105 : /* Invoke underlying implementation method. */
1106 : /* -------------------------------------------------------------------- */
1107 :
1108 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1109 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1110 894 : if (bCallLeaveReadWrite)
1111 4 : LeaveReadWrite();
1112 894 : return eErr;
1113 : }
1114 :
1115 : /************************************************************************/
1116 : /* GDALReadBlock() */
1117 : /************************************************************************/
1118 :
1119 : /**
1120 : * \brief Read a block of image data efficiently.
1121 : *
1122 : * @see GDALRasterBand::ReadBlock()
1123 : */
1124 :
1125 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1126 : void *pData)
1127 :
1128 : {
1129 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1130 :
1131 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1132 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1133 : }
1134 :
1135 : /************************************************************************/
1136 : /* IReadBlock() */
1137 : /************************************************************************/
1138 :
1139 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1140 : * ) \brief Read a block of data.
1141 : *
1142 : * Default internal implementation ... to be overridden by
1143 : * subclasses that support reading.
1144 : * @param nBlockXOff Block X Offset
1145 : * @param nBlockYOff Block Y Offset
1146 : * @param pData Pixel buffer into which to place read data.
1147 : * @return CE_None on success or CE_Failure on an error.
1148 : */
1149 :
1150 : /************************************************************************/
1151 : /* IWriteBlock() */
1152 : /************************************************************************/
1153 :
1154 : /**
1155 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1156 : * Write a block of data.
1157 : *
1158 : * Default internal implementation ... to be overridden by
1159 : * subclasses that support writing.
1160 : * @param nBlockXOff Block X Offset
1161 : * @param nBlockYOff Block Y Offset
1162 : * @param pData Pixel buffer to write
1163 : * @return CE_None on success or CE_Failure on an error.
1164 : */
1165 :
1166 : /**/
1167 : /**/
1168 :
1169 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1170 : void * /*pData*/)
1171 :
1172 : {
1173 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1174 0 : ReportError(CE_Failure, CPLE_NotSupported,
1175 : "WriteBlock() not supported for this dataset.");
1176 :
1177 0 : return (CE_Failure);
1178 : }
1179 :
1180 : /************************************************************************/
1181 : /* WriteBlock() */
1182 : /************************************************************************/
1183 :
1184 : /**
1185 : * \brief Write a block of image data efficiently.
1186 : *
1187 : * This method accesses a "natural" block from the raster band without
1188 : * resampling, or data type conversion. For a more generalized, but
1189 : * potentially less efficient access use RasterIO().
1190 : *
1191 : * This method is the same as the C GDALWriteBlock() function.
1192 : *
1193 : * See ReadBlock() for an example of block oriented data access.
1194 : *
1195 : * @param nXBlockOff the horizontal block offset, with zero indicating
1196 : * the left most block, 1 the next block and so forth.
1197 : *
1198 : * @param nYBlockOff the vertical block offset, with zero indicating
1199 : * the left most block, 1 the next block and so forth.
1200 : *
1201 : * @param pImage the buffer from which the data will be written. The buffer
1202 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1203 : * of type GetRasterDataType(). Note that the content of the buffer might be
1204 : * temporarily modified during the execution of this method (and eventually
1205 : * restored back to its original content), so it is not safe to use a buffer
1206 : * stored in a read-only section of the calling program.
1207 : *
1208 : * @return CE_None on success or CE_Failure on an error.
1209 : */
1210 :
1211 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1212 :
1213 : {
1214 : /* -------------------------------------------------------------------- */
1215 : /* Validate arguments. */
1216 : /* -------------------------------------------------------------------- */
1217 4883 : CPLAssert(pImage != nullptr);
1218 :
1219 4883 : if (!InitBlockInfo())
1220 0 : return CE_Failure;
1221 :
1222 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1223 : {
1224 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1225 : "Illegal nXBlockOff value (%d) in "
1226 : "GDALRasterBand::WriteBlock()\n",
1227 : nXBlockOff);
1228 :
1229 0 : return (CE_Failure);
1230 : }
1231 :
1232 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1233 : {
1234 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1235 : "Illegal nYBlockOff value (%d) in "
1236 : "GDALRasterBand::WriteBlock()\n",
1237 : nYBlockOff);
1238 :
1239 0 : return (CE_Failure);
1240 : }
1241 :
1242 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1243 : {
1244 0 : return CE_Failure;
1245 : }
1246 :
1247 4883 : if (eFlushBlockErr != CE_None)
1248 : {
1249 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1250 : "An error occurred while writing a dirty block "
1251 : "from GDALRasterBand::WriteBlock");
1252 0 : CPLErr eErr = eFlushBlockErr;
1253 0 : eFlushBlockErr = CE_None;
1254 0 : return eErr;
1255 : }
1256 :
1257 : /* -------------------------------------------------------------------- */
1258 : /* Invoke underlying implementation method. */
1259 : /* -------------------------------------------------------------------- */
1260 :
1261 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1262 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1263 4883 : if (bCallLeaveReadWrite)
1264 4883 : LeaveReadWrite();
1265 :
1266 4883 : return eErr;
1267 : }
1268 :
1269 : /************************************************************************/
1270 : /* GDALWriteBlock() */
1271 : /************************************************************************/
1272 :
1273 : /**
1274 : * \brief Write a block of image data efficiently.
1275 : *
1276 : * @see GDALRasterBand::WriteBlock()
1277 : */
1278 :
1279 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1280 : void *pData)
1281 :
1282 : {
1283 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1284 :
1285 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1286 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1287 : }
1288 :
1289 : /************************************************************************/
1290 : /* EmitErrorMessageIfWriteNotSupported() */
1291 : /************************************************************************/
1292 :
1293 : /**
1294 : * Emit an error message if a write operation to this band is not supported.
1295 : *
1296 : * The base implementation will emit an error message if the access mode is
1297 : * read-only. Derived classes may implement it to provide a custom message.
1298 : *
1299 : * @param pszCaller Calling function.
1300 : * @return true if an error message has been emitted.
1301 : */
1302 639890 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1303 : const char *pszCaller) const
1304 : {
1305 639890 : if (eAccess == GA_ReadOnly)
1306 : {
1307 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1308 : "%s: attempt to write to dataset opened in read-only mode.",
1309 : pszCaller);
1310 :
1311 4 : return true;
1312 : }
1313 639886 : return false;
1314 : }
1315 :
1316 : /************************************************************************/
1317 : /* GetActualBlockSize() */
1318 : /************************************************************************/
1319 : /**
1320 : * \brief Fetch the actual block size for a given block offset.
1321 : *
1322 : * Handles partial blocks at the edges of the raster and returns the true
1323 : * number of pixels
1324 : *
1325 : * @param nXBlockOff the horizontal block offset for which to calculate the
1326 : * number of valid pixels, with zero indicating the left most block, 1 the next
1327 : * block and so forth.
1328 : *
1329 : * @param nYBlockOff the vertical block offset, with zero indicating
1330 : * the top most block, 1 the next block and so forth.
1331 : *
1332 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1333 : * the x direction will be stored
1334 : *
1335 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1336 : * the y direction will be stored
1337 : *
1338 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1339 : *
1340 : */
1341 52169 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1342 : int *pnXValid, int *pnYValid) const
1343 : {
1344 104337 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1345 104335 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1346 104332 : nYBlockOff < 0 || nBlockYSize == 0 ||
1347 52166 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1348 : {
1349 4 : return CE_Failure;
1350 : }
1351 :
1352 52165 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1353 52165 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1354 :
1355 52165 : *pnXValid = nBlockXSize;
1356 52165 : *pnYValid = nBlockYSize;
1357 :
1358 52165 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1359 : {
1360 50523 : *pnXValid = nRasterXSize - nXPixelOff;
1361 : }
1362 :
1363 52165 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1364 : {
1365 3832 : *pnYValid = nRasterYSize - nYPixelOff;
1366 : }
1367 :
1368 52165 : return CE_None;
1369 : }
1370 :
1371 : /************************************************************************/
1372 : /* GDALGetActualBlockSize() */
1373 : /************************************************************************/
1374 :
1375 : /**
1376 : * \brief Retrieve the actual block size for a given block offset.
1377 : *
1378 : * @see GDALRasterBand::GetActualBlockSize()
1379 : */
1380 :
1381 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1382 : int nYBlockOff, int *pnXValid,
1383 : int *pnYValid)
1384 :
1385 : {
1386 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1387 :
1388 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1389 : return (
1390 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1391 : }
1392 :
1393 : /************************************************************************/
1394 : /* GetSuggestedBlockAccessPattern() */
1395 : /************************************************************************/
1396 :
1397 : /**
1398 : * \brief Return the suggested/most efficient access pattern to blocks
1399 : * (for read operations).
1400 : *
1401 : * While all GDAL drivers have to expose a block size, not all can guarantee
1402 : * efficient random access (GSBAP_RANDOM) to any block.
1403 : * Some drivers for example decompress sequentially a compressed stream from
1404 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1405 : * case best performance will be achieved while reading blocks in that order.
1406 : * (accessing blocks in random access in such rasters typically causes the
1407 : * decoding to be re-initialized from the start if accessing blocks in
1408 : * a non-sequential order)
1409 : *
1410 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1411 : * returned by drivers that expose a somewhat artificial block size, because
1412 : * they can extract any part of a raster, but in a rather inefficient way.
1413 : *
1414 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1415 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1416 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1417 : * most efficient strategy is to read as many pixels as possible in the less
1418 : * RasterIO() operations.
1419 : *
1420 : * The return of this method is for example used to determine the swath size
1421 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1422 : *
1423 : * @since GDAL 3.6
1424 : */
1425 :
1426 : GDALSuggestedBlockAccessPattern
1427 2429 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1428 : {
1429 2429 : return GSBAP_UNKNOWN;
1430 : }
1431 :
1432 : /************************************************************************/
1433 : /* GetRasterDataType() */
1434 : /************************************************************************/
1435 :
1436 : /**
1437 : * \brief Fetch the pixel data type for this band.
1438 : *
1439 : * This method is the same as the C function GDALGetRasterDataType().
1440 : *
1441 : * @return the data type of pixels for this band.
1442 : */
1443 :
1444 8978280 : GDALDataType GDALRasterBand::GetRasterDataType() const
1445 :
1446 : {
1447 8978280 : return eDataType;
1448 : }
1449 :
1450 : /************************************************************************/
1451 : /* GDALGetRasterDataType() */
1452 : /************************************************************************/
1453 :
1454 : /**
1455 : * \brief Fetch the pixel data type for this band.
1456 : *
1457 : * @see GDALRasterBand::GetRasterDataType()
1458 : */
1459 :
1460 906237 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1461 :
1462 : {
1463 906237 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1464 :
1465 906237 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1466 906237 : return poBand->GetRasterDataType();
1467 : }
1468 :
1469 : /************************************************************************/
1470 : /* GetBlockSize() */
1471 : /************************************************************************/
1472 :
1473 : /**
1474 : * \brief Fetch the "natural" block size of this band.
1475 : *
1476 : * GDAL contains a concept of the natural block size of rasters so that
1477 : * applications can organized data access efficiently for some file formats.
1478 : * The natural block size is the block size that is most efficient for
1479 : * accessing the format. For many formats this is simple a whole scanline
1480 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1481 : *
1482 : * However, for tiled images this will typically be the tile size.
1483 : *
1484 : * Note that the X and Y block sizes don't have to divide the image size
1485 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1486 : * See ReadBlock() for an example of code dealing with these issues.
1487 : *
1488 : * This method is the same as the C function GDALGetBlockSize().
1489 : *
1490 : * @param pnXSize integer to put the X block size into or NULL.
1491 : *
1492 : * @param pnYSize integer to put the Y block size into or NULL.
1493 : */
1494 :
1495 5557710 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1496 :
1497 : {
1498 5557710 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1499 : {
1500 4 : ReportError(CE_Failure, CPLE_AppDefined,
1501 4 : "Invalid block dimension : %d * %d", nBlockXSize,
1502 4 : nBlockYSize);
1503 4 : if (pnXSize != nullptr)
1504 4 : *pnXSize = 0;
1505 4 : if (pnYSize != nullptr)
1506 4 : *pnYSize = 0;
1507 : }
1508 : else
1509 : {
1510 5557700 : if (pnXSize != nullptr)
1511 5557700 : *pnXSize = nBlockXSize;
1512 5557700 : if (pnYSize != nullptr)
1513 5557700 : *pnYSize = nBlockYSize;
1514 : }
1515 5557710 : }
1516 :
1517 : /************************************************************************/
1518 : /* GDALGetBlockSize() */
1519 : /************************************************************************/
1520 :
1521 : /**
1522 : * \brief Fetch the "natural" block size of this band.
1523 : *
1524 : * @see GDALRasterBand::GetBlockSize()
1525 : */
1526 :
1527 41244 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1528 : int *pnYSize)
1529 :
1530 : {
1531 41244 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1532 :
1533 41244 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1534 41244 : poBand->GetBlockSize(pnXSize, pnYSize);
1535 : }
1536 :
1537 : /************************************************************************/
1538 : /* InitBlockInfo() */
1539 : /************************************************************************/
1540 :
1541 : //! @cond Doxygen_Suppress
1542 3654180 : int GDALRasterBand::InitBlockInfo()
1543 :
1544 : {
1545 3654180 : if (poBandBlockCache != nullptr)
1546 3414970 : return poBandBlockCache->IsInitOK();
1547 :
1548 : /* Do some validation of raster and block dimensions in case the driver */
1549 : /* would have neglected to do it itself */
1550 239208 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1551 : {
1552 0 : ReportError(CE_Failure, CPLE_AppDefined,
1553 : "Invalid block dimension : %d * %d", nBlockXSize,
1554 : nBlockYSize);
1555 0 : return FALSE;
1556 : }
1557 :
1558 239208 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1559 : {
1560 0 : ReportError(CE_Failure, CPLE_AppDefined,
1561 : "Invalid raster dimension : %d * %d", nRasterXSize,
1562 : nRasterYSize);
1563 0 : return FALSE;
1564 : }
1565 :
1566 239208 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1567 239208 : if (nDataTypeSize == 0)
1568 : {
1569 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1570 0 : return FALSE;
1571 : }
1572 :
1573 : #if SIZEOF_VOIDP == 4
1574 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1575 : {
1576 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1577 : * multiplication in other cases */
1578 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1579 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1580 : {
1581 : ReportError(CE_Failure, CPLE_NotSupported,
1582 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1583 : nBlockYSize);
1584 : return FALSE;
1585 : }
1586 : }
1587 : #endif
1588 :
1589 239208 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1590 239208 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1591 :
1592 : const char *pszBlockStrategy =
1593 239208 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1594 239208 : bool bUseArray = true;
1595 239208 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1596 : {
1597 239168 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1598 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1599 : {
1600 239149 : GUIntBig nBlockCount =
1601 239149 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1602 239149 : if (poDS != nullptr)
1603 238945 : nBlockCount *= poDS->GetRasterCount();
1604 239149 : bUseArray = (nBlockCount < 1024 * 1024);
1605 : }
1606 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1607 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1608 : {
1609 0 : bUseArray = false;
1610 239168 : }
1611 : }
1612 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1613 40 : bUseArray = false;
1614 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1615 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1616 : pszBlockStrategy);
1617 :
1618 239208 : if (bUseArray)
1619 239137 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1620 : else
1621 : {
1622 71 : if (nBand == 1)
1623 26 : CPLDebug("GDAL", "Use hashset band block cache");
1624 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1625 : }
1626 239208 : if (poBandBlockCache == nullptr)
1627 0 : return FALSE;
1628 239208 : return poBandBlockCache->Init();
1629 : }
1630 :
1631 : //! @endcond
1632 :
1633 : /************************************************************************/
1634 : /* FlushCache() */
1635 : /************************************************************************/
1636 :
1637 : /**
1638 : * \brief Flush raster data cache.
1639 : *
1640 : * This call will recover memory used to cache data blocks for this raster
1641 : * band, and ensure that new requests are referred to the underlying driver.
1642 : *
1643 : * This method is the same as the C function GDALFlushRasterCache().
1644 : *
1645 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1646 : * @return CE_None on success.
1647 : */
1648 :
1649 5661360 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1650 :
1651 : {
1652 5779860 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1653 118505 : poBandBlockCache)
1654 3423 : poBandBlockCache->DisableDirtyBlockWriting();
1655 :
1656 5661360 : CPLErr eGlobalErr = eFlushBlockErr;
1657 :
1658 5661360 : if (eFlushBlockErr != CE_None)
1659 : {
1660 0 : ReportError(
1661 : eFlushBlockErr, CPLE_AppDefined,
1662 : "An error occurred while writing a dirty block from FlushCache");
1663 0 : eFlushBlockErr = CE_None;
1664 : }
1665 :
1666 5661360 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1667 4899050 : return eGlobalErr;
1668 :
1669 762301 : return poBandBlockCache->FlushCache();
1670 : }
1671 :
1672 : /************************************************************************/
1673 : /* GDALFlushRasterCache() */
1674 : /************************************************************************/
1675 :
1676 : /**
1677 : * \brief Flush raster data cache.
1678 : *
1679 : * @see GDALRasterBand::FlushCache()
1680 : */
1681 :
1682 487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1683 :
1684 : {
1685 487 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1686 :
1687 487 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1688 : }
1689 :
1690 : /************************************************************************/
1691 : /* DropCache() */
1692 : /************************************************************************/
1693 :
1694 : /**
1695 : * \brief Drop raster data cache : data in cache will be lost.
1696 : *
1697 : * This call will recover memory used to cache data blocks for this raster
1698 : * band, and ensure that new requests are referred to the underlying driver.
1699 : *
1700 : * This method is the same as the C function GDALDropRasterCache().
1701 : *
1702 : * @return CE_None on success.
1703 : * @since 3.9
1704 : */
1705 :
1706 1 : CPLErr GDALRasterBand::DropCache()
1707 :
1708 : {
1709 1 : CPLErr result = CE_None;
1710 :
1711 1 : if (poBandBlockCache)
1712 1 : poBandBlockCache->DisableDirtyBlockWriting();
1713 :
1714 1 : CPLErr eGlobalErr = eFlushBlockErr;
1715 :
1716 1 : if (eFlushBlockErr != CE_None)
1717 : {
1718 0 : ReportError(
1719 : eFlushBlockErr, CPLE_AppDefined,
1720 : "An error occurred while writing a dirty block from DropCache");
1721 0 : eFlushBlockErr = CE_None;
1722 : }
1723 :
1724 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1725 0 : result = eGlobalErr;
1726 : else
1727 1 : result = poBandBlockCache->FlushCache();
1728 :
1729 1 : if (poBandBlockCache)
1730 1 : poBandBlockCache->EnableDirtyBlockWriting();
1731 :
1732 1 : return result;
1733 : }
1734 :
1735 : /************************************************************************/
1736 : /* GDALDropRasterCache() */
1737 : /************************************************************************/
1738 :
1739 : /**
1740 : * \brief Drop raster data cache.
1741 : *
1742 : * @see GDALRasterBand::DropCache()
1743 : * @since 3.9
1744 : */
1745 :
1746 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1747 :
1748 : {
1749 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1750 :
1751 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1752 : }
1753 :
1754 : /************************************************************************/
1755 : /* UnreferenceBlock() */
1756 : /* */
1757 : /* Unreference the block from our array of blocks */
1758 : /* This method should only be called by */
1759 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1760 : /* the block cache mutex) */
1761 : /************************************************************************/
1762 :
1763 29706 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1764 : {
1765 : #ifdef notdef
1766 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1767 : {
1768 : if (poBandBlockCache == nullptr)
1769 : printf("poBandBlockCache == NULL\n"); /*ok*/
1770 : else
1771 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1772 : printf("caller = %s\n", pszCaller); /*ok*/
1773 : printf("GDALRasterBand: %p\n", this); /*ok*/
1774 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1775 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1776 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1777 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1778 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1779 : poBlock->DumpBlock();
1780 : if (GetDataset() != nullptr)
1781 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1782 : GDALRasterBlock::Verify();
1783 : abort();
1784 : }
1785 : #endif
1786 29706 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1787 29706 : return poBandBlockCache->UnreferenceBlock(poBlock);
1788 : }
1789 :
1790 : /************************************************************************/
1791 : /* AddBlockToFreeList() */
1792 : /* */
1793 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1794 : /* finished with a block about to be free'd, they pass it to that */
1795 : /* method. */
1796 : /************************************************************************/
1797 :
1798 : //! @cond Doxygen_Suppress
1799 29706 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1800 : {
1801 29706 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1802 29706 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1803 : }
1804 :
1805 : //! @endcond
1806 :
1807 : /************************************************************************/
1808 : /* HasDirtyBlocks() */
1809 : /************************************************************************/
1810 :
1811 : //! @cond Doxygen_Suppress
1812 17 : bool GDALRasterBand::HasDirtyBlocks() const
1813 : {
1814 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1815 : }
1816 :
1817 : //! @endcond
1818 :
1819 : /************************************************************************/
1820 : /* FlushBlock() */
1821 : /************************************************************************/
1822 :
1823 : /** Flush a block out of the block cache.
1824 : * @param nXBlockOff block x offset
1825 : * @param nYBlockOff blocky offset
1826 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1827 : * @return CE_None in case of success, an error code otherwise.
1828 : */
1829 2312 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1830 : int bWriteDirtyBlock)
1831 :
1832 : {
1833 2312 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1834 0 : return (CE_Failure);
1835 :
1836 : /* -------------------------------------------------------------------- */
1837 : /* Validate the request */
1838 : /* -------------------------------------------------------------------- */
1839 2312 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1840 : {
1841 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1842 : "Illegal nBlockXOff value (%d) in "
1843 : "GDALRasterBand::FlushBlock()\n",
1844 : nXBlockOff);
1845 :
1846 0 : return (CE_Failure);
1847 : }
1848 :
1849 2312 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1850 : {
1851 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1852 : "Illegal nBlockYOff value (%d) in "
1853 : "GDALRasterBand::FlushBlock()\n",
1854 : nYBlockOff);
1855 :
1856 0 : return (CE_Failure);
1857 : }
1858 :
1859 2312 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1860 2312 : bWriteDirtyBlock);
1861 : }
1862 :
1863 : /************************************************************************/
1864 : /* TryGetLockedBlockRef() */
1865 : /************************************************************************/
1866 :
1867 : /**
1868 : * \brief Try fetching block ref.
1869 : *
1870 : * This method will returned the requested block (locked) if it is already
1871 : * in the block cache for the layer. If not, nullptr is returned.
1872 : *
1873 : * If a non-NULL value is returned, then a lock for the block will have been
1874 : * acquired on behalf of the caller. It is absolutely imperative that the
1875 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1876 : * severe problems may result.
1877 : *
1878 : * @param nXBlockOff the horizontal block offset, with zero indicating
1879 : * the left most block, 1 the next block and so forth.
1880 : *
1881 : * @param nYBlockOff the vertical block offset, with zero indicating
1882 : * the top most block, 1 the next block and so forth.
1883 : *
1884 : * @return NULL if block not available, or locked block pointer.
1885 : */
1886 :
1887 10649700 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1888 : int nYBlockOff)
1889 :
1890 : {
1891 10649700 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1892 173103 : return nullptr;
1893 :
1894 : /* -------------------------------------------------------------------- */
1895 : /* Validate the request */
1896 : /* -------------------------------------------------------------------- */
1897 10476600 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1898 : {
1899 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1900 : "Illegal nBlockXOff value (%d) in "
1901 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1902 : nXBlockOff);
1903 :
1904 0 : return (nullptr);
1905 : }
1906 :
1907 10476600 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1908 : {
1909 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1910 : "Illegal nBlockYOff value (%d) in "
1911 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1912 : nYBlockOff);
1913 :
1914 0 : return (nullptr);
1915 : }
1916 :
1917 10476600 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1918 : }
1919 :
1920 : /************************************************************************/
1921 : /* GetLockedBlockRef() */
1922 : /************************************************************************/
1923 :
1924 : /**
1925 : * \brief Fetch a pointer to an internally cached raster block.
1926 : *
1927 : * This method will returned the requested block (locked) if it is already
1928 : * in the block cache for the layer. If not, the block will be read from
1929 : * the driver, and placed in the layer block cached, then returned. If an
1930 : * error occurs reading the block from the driver, a NULL value will be
1931 : * returned.
1932 : *
1933 : * If a non-NULL value is returned, then a lock for the block will have been
1934 : * acquired on behalf of the caller. It is absolutely imperative that the
1935 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1936 : * severe problems may result.
1937 : *
1938 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1939 : * enable caching.
1940 : *
1941 : * @param nXBlockOff the horizontal block offset, with zero indicating
1942 : * the left most block, 1 the next block and so forth.
1943 : *
1944 : * @param nYBlockOff the vertical block offset, with zero indicating
1945 : * the top most block, 1 the next block and so forth.
1946 : *
1947 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1948 : * but not actually read from the source. This is useful when it will just
1949 : * be completely set and written back.
1950 : *
1951 : * @return pointer to the block object, or NULL on failure.
1952 : */
1953 :
1954 10339600 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1955 : int nYBlockOff,
1956 : int bJustInitialize)
1957 :
1958 : {
1959 : /* -------------------------------------------------------------------- */
1960 : /* Try and fetch from cache. */
1961 : /* -------------------------------------------------------------------- */
1962 10339600 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1963 :
1964 : /* -------------------------------------------------------------------- */
1965 : /* If we didn't find it in our memory cache, instantiate a */
1966 : /* block (potentially load from disk) and "adopt" it into the */
1967 : /* cache. */
1968 : /* -------------------------------------------------------------------- */
1969 10339600 : if (poBlock == nullptr)
1970 : {
1971 3377120 : if (!InitBlockInfo())
1972 0 : return (nullptr);
1973 :
1974 : /* --------------------------------------------------------------------
1975 : */
1976 : /* Validate the request */
1977 : /* --------------------------------------------------------------------
1978 : */
1979 3377120 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1980 : {
1981 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1982 : "Illegal nBlockXOff value (%d) in "
1983 : "GDALRasterBand::GetLockedBlockRef()\n",
1984 : nXBlockOff);
1985 :
1986 0 : return (nullptr);
1987 : }
1988 :
1989 3377120 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1990 : {
1991 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1992 : "Illegal nBlockYOff value (%d) in "
1993 : "GDALRasterBand::GetLockedBlockRef()\n",
1994 : nYBlockOff);
1995 :
1996 0 : return (nullptr);
1997 : }
1998 :
1999 3377120 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2000 3377120 : if (poBlock == nullptr)
2001 0 : return nullptr;
2002 :
2003 3377120 : poBlock->AddLock();
2004 :
2005 : /* We need to temporarily drop the read-write lock in the following */
2006 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
2007 : */
2008 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
2009 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
2010 : */
2011 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
2012 : */
2013 : /* called and attempt at taking the lock on T2 (already taken).
2014 : * Similarly */
2015 : /* for T2 with D1, hence a deadlock situation (#6163) */
2016 : /* But this may open the door to other problems... */
2017 3377120 : if (poDS)
2018 3376380 : poDS->TemporarilyDropReadWriteLock();
2019 : /* allocate data space */
2020 3377120 : CPLErr eErr = poBlock->Internalize();
2021 3377120 : if (poDS)
2022 3376380 : poDS->ReacquireReadWriteLock();
2023 3377120 : if (eErr != CE_None)
2024 : {
2025 0 : poBlock->DropLock();
2026 0 : delete poBlock;
2027 0 : return nullptr;
2028 : }
2029 :
2030 3377120 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2031 : {
2032 0 : poBlock->DropLock();
2033 0 : delete poBlock;
2034 0 : return nullptr;
2035 : }
2036 :
2037 3377120 : if (!bJustInitialize)
2038 : {
2039 2890700 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2040 2890700 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2041 2890700 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2042 2890700 : if (bCallLeaveReadWrite)
2043 132816 : LeaveReadWrite();
2044 2890700 : if (eErr != CE_None)
2045 : {
2046 1162 : poBlock->DropLock();
2047 1162 : FlushBlock(nXBlockOff, nYBlockOff);
2048 1162 : ReportError(CE_Failure, CPLE_AppDefined,
2049 : "IReadBlock failed at X offset %d, Y offset %d%s",
2050 : nXBlockOff, nYBlockOff,
2051 1162 : (nErrorCounter != CPLGetErrorCounter())
2052 1160 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2053 : : "");
2054 1162 : return nullptr;
2055 : }
2056 :
2057 2889540 : nBlockReads++;
2058 2889540 : if (static_cast<GIntBig>(nBlockReads) ==
2059 2889540 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2060 229 : 1 &&
2061 229 : nBand == 1 && poDS != nullptr)
2062 : {
2063 169 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2064 169 : poDS->GetDescription());
2065 : }
2066 : }
2067 : }
2068 :
2069 10338400 : return poBlock;
2070 : }
2071 :
2072 : /************************************************************************/
2073 : /* Fill() */
2074 : /************************************************************************/
2075 :
2076 : /**
2077 : * \brief Fill this band with a constant value.
2078 : *
2079 : * GDAL makes no guarantees
2080 : * about what values pixels in newly created files are set to, so this
2081 : * method can be used to clear a band to a specified "default" value.
2082 : * The fill value is passed in as a double but this will be converted
2083 : * to the underlying type before writing to the file. An optional
2084 : * second argument allows the imaginary component of a complex
2085 : * constant value to be specified.
2086 : *
2087 : * This method is the same as the C function GDALFillRaster().
2088 : *
2089 : * @param dfRealValue Real component of fill value
2090 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2091 : *
2092 : * @return CE_Failure if the write fails, otherwise CE_None
2093 : */
2094 268904 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2095 : {
2096 :
2097 : // General approach is to construct a source block of the file's
2098 : // native type containing the appropriate value and then copy this
2099 : // to each block in the image via the RasterBlock cache. Using
2100 : // the cache means we avoid file I/O if it is not necessary, at the
2101 : // expense of some extra memcpy's (since we write to the
2102 : // RasterBlock cache, which is then at some point written to the
2103 : // underlying file, rather than simply directly to the underlying
2104 : // file.)
2105 :
2106 : // Check we can write to the file.
2107 268904 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2108 : {
2109 6 : return CE_Failure;
2110 : }
2111 :
2112 : // Make sure block parameters are set.
2113 268898 : if (!InitBlockInfo())
2114 0 : return CE_Failure;
2115 :
2116 : // Allocate the source block.
2117 268898 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2118 268898 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2119 268898 : auto blockByteSize = blockSize * elementSize;
2120 : unsigned char *srcBlock =
2121 268898 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2122 268898 : if (srcBlock == nullptr)
2123 : {
2124 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2125 : "GDALRasterBand::Fill(): Out of memory "
2126 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2127 : static_cast<GUIntBig>(blockByteSize));
2128 0 : return CE_Failure;
2129 : }
2130 :
2131 : // Initialize the source block.
2132 268898 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2133 268898 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2134 : elementSize, blockSize);
2135 :
2136 268898 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2137 :
2138 : // Write block to block cache
2139 872479 : for (int j = 0; j < nBlocksPerColumn; ++j)
2140 : {
2141 1501510 : for (int i = 0; i < nBlocksPerRow; ++i)
2142 : {
2143 897928 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2144 897928 : if (destBlock == nullptr)
2145 : {
2146 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2147 : "GDALRasterBand::Fill(): Error "
2148 : "while retrieving cache block.");
2149 0 : VSIFree(srcBlock);
2150 0 : return CE_Failure;
2151 : }
2152 897928 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2153 897928 : destBlock->MarkDirty();
2154 897928 : destBlock->DropLock();
2155 : }
2156 : }
2157 :
2158 268898 : if (bCallLeaveReadWrite)
2159 267700 : LeaveReadWrite();
2160 :
2161 : // Free up the source block
2162 268898 : VSIFree(srcBlock);
2163 :
2164 268898 : return CE_None;
2165 : }
2166 :
2167 : /************************************************************************/
2168 : /* GDALFillRaster() */
2169 : /************************************************************************/
2170 :
2171 : /**
2172 : * \brief Fill this band with a constant value.
2173 : *
2174 : * @see GDALRasterBand::Fill()
2175 : */
2176 268684 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2177 : double dfImaginaryValue)
2178 : {
2179 268684 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2180 :
2181 268684 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2182 268684 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2183 : }
2184 :
2185 : /************************************************************************/
2186 : /* GetAccess() */
2187 : /************************************************************************/
2188 :
2189 : /**
2190 : * \brief Find out if we have update permission for this band.
2191 : *
2192 : * This method is the same as the C function GDALGetRasterAccess().
2193 : *
2194 : * @return Either GA_Update or GA_ReadOnly.
2195 : */
2196 :
2197 3047 : GDALAccess GDALRasterBand::GetAccess()
2198 :
2199 : {
2200 3047 : return eAccess;
2201 : }
2202 :
2203 : /************************************************************************/
2204 : /* GDALGetRasterAccess() */
2205 : /************************************************************************/
2206 :
2207 : /**
2208 : * \brief Find out if we have update permission for this band.
2209 : *
2210 : * @see GDALRasterBand::GetAccess()
2211 : */
2212 :
2213 2389 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2214 :
2215 : {
2216 2389 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2217 :
2218 2389 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2219 2389 : return poBand->GetAccess();
2220 : }
2221 :
2222 : /************************************************************************/
2223 : /* GetCategoryNames() */
2224 : /************************************************************************/
2225 :
2226 : /**
2227 : * \brief Fetch the list of category names for this raster.
2228 : *
2229 : * The return list is a "StringList" in the sense of the CPL functions.
2230 : * That is a NULL terminated array of strings. Raster values without
2231 : * associated names will have an empty string in the returned list. The
2232 : * first entry in the list is for raster values of zero, and so on.
2233 : *
2234 : * The returned stringlist should not be altered or freed by the application.
2235 : * It may change on the next GDAL call, so please copy it if it is needed
2236 : * for any period of time.
2237 : *
2238 : * This method is the same as the C function GDALGetRasterCategoryNames().
2239 : *
2240 : * @return list of names, or NULL if none.
2241 : */
2242 :
2243 262 : char **GDALRasterBand::GetCategoryNames()
2244 :
2245 : {
2246 262 : return nullptr;
2247 : }
2248 :
2249 : /************************************************************************/
2250 : /* GDALGetRasterCategoryNames() */
2251 : /************************************************************************/
2252 :
2253 : /**
2254 : * \brief Fetch the list of category names for this raster.
2255 : *
2256 : * @see GDALRasterBand::GetCategoryNames()
2257 : */
2258 :
2259 207 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2260 :
2261 : {
2262 207 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2263 :
2264 207 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2265 207 : return poBand->GetCategoryNames();
2266 : }
2267 :
2268 : /************************************************************************/
2269 : /* SetCategoryNames() */
2270 : /************************************************************************/
2271 :
2272 : /**
2273 : * \fn GDALRasterBand::SetCategoryNames(char**)
2274 : * \brief Set the category names for this band.
2275 : *
2276 : * See the GetCategoryNames() method for more on the interpretation of
2277 : * category names.
2278 : *
2279 : * This method is the same as the C function GDALSetRasterCategoryNames().
2280 : *
2281 : * @param papszNames the NULL terminated StringList of category names. May
2282 : * be NULL to just clear the existing list.
2283 : *
2284 : * @return CE_None on success of CE_Failure on failure. If unsupported
2285 : * by the driver CE_Failure is returned, but no error message is reported.
2286 : */
2287 :
2288 : /**/
2289 : /**/
2290 :
2291 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2292 : {
2293 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2294 0 : ReportError(CE_Failure, CPLE_NotSupported,
2295 : "SetCategoryNames() not supported for this dataset.");
2296 :
2297 0 : return CE_Failure;
2298 : }
2299 :
2300 : /************************************************************************/
2301 : /* GDALSetCategoryNames() */
2302 : /************************************************************************/
2303 :
2304 : /**
2305 : * \brief Set the category names for this band.
2306 : *
2307 : * @see GDALRasterBand::SetCategoryNames()
2308 : */
2309 :
2310 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2311 : CSLConstList papszNames)
2312 :
2313 : {
2314 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2315 :
2316 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2317 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2318 : }
2319 :
2320 : /************************************************************************/
2321 : /* GetNoDataValue() */
2322 : /************************************************************************/
2323 :
2324 : /**
2325 : * \brief Fetch the no data value for this band.
2326 : *
2327 : * If there is no out of data value, an out of range value will generally
2328 : * be returned. The no data value for a band is generally a special marker
2329 : * value used to mark pixels that are not valid data. Such pixels should
2330 : * generally not be displayed, nor contribute to analysis operations.
2331 : *
2332 : * The no data value returned is 'raw', meaning that it has no offset and
2333 : * scale applied.
2334 : *
2335 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2336 : * lossy if the nodata value cannot exactly been represented by a double.
2337 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2338 : *
2339 : * This method is the same as the C function GDALGetRasterNoDataValue().
2340 : *
2341 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2342 : * is actually associated with this layer. May be NULL (default).
2343 : *
2344 : * @return the nodata value for this band.
2345 : */
2346 :
2347 13125 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2348 :
2349 : {
2350 13125 : if (pbSuccess != nullptr)
2351 13125 : *pbSuccess = FALSE;
2352 :
2353 13125 : return -1e10;
2354 : }
2355 :
2356 : /************************************************************************/
2357 : /* GDALGetRasterNoDataValue() */
2358 : /************************************************************************/
2359 :
2360 : /**
2361 : * \brief Fetch the no data value for this band.
2362 : *
2363 : * @see GDALRasterBand::GetNoDataValue()
2364 : */
2365 :
2366 414487 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2367 : int *pbSuccess)
2368 :
2369 : {
2370 414487 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2371 :
2372 414487 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2373 414487 : return poBand->GetNoDataValue(pbSuccess);
2374 : }
2375 :
2376 : /************************************************************************/
2377 : /* GetNoDataValueAsInt64() */
2378 : /************************************************************************/
2379 :
2380 : /**
2381 : * \brief Fetch the no data value for this band.
2382 : *
2383 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2384 : *
2385 : * If there is no out of data value, an out of range value will generally
2386 : * be returned. The no data value for a band is generally a special marker
2387 : * value used to mark pixels that are not valid data. Such pixels should
2388 : * generally not be displayed, nor contribute to analysis operations.
2389 : *
2390 : * The no data value returned is 'raw', meaning that it has no offset and
2391 : * scale applied.
2392 : *
2393 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2394 : *
2395 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2396 : * is actually associated with this layer. May be NULL (default).
2397 : *
2398 : * @return the nodata value for this band.
2399 : *
2400 : * @since GDAL 3.5
2401 : */
2402 :
2403 3 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2404 :
2405 : {
2406 3 : if (pbSuccess != nullptr)
2407 3 : *pbSuccess = FALSE;
2408 :
2409 3 : return std::numeric_limits<int64_t>::min();
2410 : }
2411 :
2412 : /************************************************************************/
2413 : /* GDALGetRasterNoDataValueAsInt64() */
2414 : /************************************************************************/
2415 :
2416 : /**
2417 : * \brief Fetch the no data value for this band.
2418 : *
2419 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2420 : *
2421 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2422 : *
2423 : * @since GDAL 3.5
2424 : */
2425 :
2426 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2427 : int *pbSuccess)
2428 :
2429 : {
2430 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2431 : std::numeric_limits<int64_t>::min());
2432 :
2433 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2434 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2435 : }
2436 :
2437 : /************************************************************************/
2438 : /* GetNoDataValueAsUInt64() */
2439 : /************************************************************************/
2440 :
2441 : /**
2442 : * \brief Fetch the no data value for this band.
2443 : *
2444 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2445 : *
2446 : * If there is no out of data value, an out of range value will generally
2447 : * be returned. The no data value for a band is generally a special marker
2448 : * value used to mark pixels that are not valid data. Such pixels should
2449 : * generally not be displayed, nor contribute to analysis operations.
2450 : *
2451 : * The no data value returned is 'raw', meaning that it has no offset and
2452 : * scale applied.
2453 : *
2454 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2455 : *
2456 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2457 : * is actually associated with this layer. May be NULL (default).
2458 : *
2459 : * @return the nodata value for this band.
2460 : *
2461 : * @since GDAL 3.5
2462 : */
2463 :
2464 2 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2465 :
2466 : {
2467 2 : if (pbSuccess != nullptr)
2468 2 : *pbSuccess = FALSE;
2469 :
2470 2 : return std::numeric_limits<uint64_t>::max();
2471 : }
2472 :
2473 : /************************************************************************/
2474 : /* GDALGetRasterNoDataValueAsUInt64() */
2475 : /************************************************************************/
2476 :
2477 : /**
2478 : * \brief Fetch the no data value for this band.
2479 : *
2480 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2481 : *
2482 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2483 : *
2484 : * @since GDAL 3.5
2485 : */
2486 :
2487 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2488 : int *pbSuccess)
2489 :
2490 : {
2491 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2492 : std::numeric_limits<uint64_t>::max());
2493 :
2494 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2495 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2496 : }
2497 :
2498 : /************************************************************************/
2499 : /* SetNoDataValueAsString() */
2500 : /************************************************************************/
2501 :
2502 : /**
2503 : * \brief Set the no data value for this band.
2504 : *
2505 : * Depending on drivers, changing the no data value may or may not have an
2506 : * effect on the pixel values of a raster that has just been created. It is
2507 : * thus advised to explicitly called Fill() if the intent is to initialize
2508 : * the raster to the nodata value.
2509 : * In any case, changing an existing no data value, when one already exists and
2510 : * the dataset exists or has been initialized, has no effect on the pixel whose
2511 : * value matched the previous nodata value.
2512 : *
2513 : * To clear the nodata value, use DeleteNoDataValue().
2514 : *
2515 : * @param pszNoData the value to set.
2516 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2517 : * If the value cannot be exactly represented on the output data
2518 : * type, *pbCannotBeExactlyRepresented will be set to true.
2519 : *
2520 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2521 : * by the driver, CE_Failure is returned but no error message will have
2522 : * been emitted.
2523 : *
2524 : * @since 3.11
2525 : */
2526 :
2527 : CPLErr
2528 123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2529 : bool *pbCannotBeExactlyRepresented)
2530 : {
2531 123 : if (pbCannotBeExactlyRepresented)
2532 123 : *pbCannotBeExactlyRepresented = false;
2533 123 : if (eDataType == GDT_Int64)
2534 : {
2535 8 : if (strchr(pszNoData, '.') ||
2536 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2537 : {
2538 2 : char *endptr = nullptr;
2539 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2540 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2541 2 : GDALIsValueExactAs<int64_t>(dfVal))
2542 : {
2543 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2544 : }
2545 : }
2546 : else
2547 : {
2548 : try
2549 : {
2550 7 : const auto val = std::stoll(pszNoData);
2551 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2552 : }
2553 2 : catch (const std::exception &)
2554 : {
2555 : }
2556 : }
2557 : }
2558 118 : else if (eDataType == GDT_UInt64)
2559 : {
2560 2 : if (strchr(pszNoData, '.') ||
2561 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2562 : {
2563 0 : char *endptr = nullptr;
2564 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2565 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2566 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2567 : {
2568 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2569 : }
2570 : }
2571 : else
2572 : {
2573 : try
2574 : {
2575 1 : const auto val = std::stoull(pszNoData);
2576 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2577 : }
2578 0 : catch (const std::exception &)
2579 : {
2580 : }
2581 : }
2582 : }
2583 117 : else if (eDataType == GDT_Float32)
2584 : {
2585 10 : char *endptr = nullptr;
2586 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2587 10 : if (endptr == pszNoData + strlen(pszNoData))
2588 : {
2589 10 : return SetNoDataValue(double(fVal));
2590 : }
2591 : }
2592 : else
2593 : {
2594 107 : char *endptr = nullptr;
2595 107 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2596 214 : if (endptr == pszNoData + strlen(pszNoData) &&
2597 107 : GDALIsValueExactAs(dfVal, eDataType))
2598 : {
2599 106 : return SetNoDataValue(dfVal);
2600 : }
2601 : }
2602 5 : if (pbCannotBeExactlyRepresented)
2603 5 : *pbCannotBeExactlyRepresented = true;
2604 5 : return CE_Failure;
2605 : }
2606 :
2607 : /************************************************************************/
2608 : /* SetNoDataValue() */
2609 : /************************************************************************/
2610 :
2611 : /**
2612 : * \fn GDALRasterBand::SetNoDataValue(double)
2613 : * \brief Set the no data value for this band.
2614 : *
2615 : * Depending on drivers, changing the no data value may or may not have an
2616 : * effect on the pixel values of a raster that has just been created. It is
2617 : * thus advised to explicitly called Fill() if the intent is to initialize
2618 : * the raster to the nodata value.
2619 : * In any case, changing an existing no data value, when one already exists and
2620 : * the dataset exists or has been initialized, has no effect on the pixel whose
2621 : * value matched the previous nodata value.
2622 : *
2623 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2624 : * be represented by a double, use SetNoDataValueAsInt64() or
2625 : * SetNoDataValueAsUInt64() instead.
2626 : *
2627 : * To clear the nodata value, use DeleteNoDataValue().
2628 : *
2629 : * This method is the same as the C function GDALSetRasterNoDataValue().
2630 : *
2631 : * @param dfNoData the value to set.
2632 : *
2633 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2634 : * by the driver, CE_Failure is returned but no error message will have
2635 : * been emitted.
2636 : */
2637 :
2638 : /**/
2639 : /**/
2640 :
2641 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2642 :
2643 : {
2644 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2645 0 : ReportError(CE_Failure, CPLE_NotSupported,
2646 : "SetNoDataValue() not supported for this dataset.");
2647 :
2648 0 : return CE_Failure;
2649 : }
2650 :
2651 : /************************************************************************/
2652 : /* GDALSetRasterNoDataValue() */
2653 : /************************************************************************/
2654 :
2655 : /**
2656 : * \brief Set the no data value for this band.
2657 : *
2658 : * Depending on drivers, changing the no data value may or may not have an
2659 : * effect on the pixel values of a raster that has just been created. It is
2660 : * thus advised to explicitly called Fill() if the intent is to initialize
2661 : * the raster to the nodata value.
2662 : * In any case, changing an existing no data value, when one already exists and
2663 : * the dataset exists or has been initialized, has no effect on the pixel whose
2664 : * value matched the previous nodata value.
2665 : *
2666 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2667 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2668 : * GDALSetRasterNoDataValueAsUInt64() instead.
2669 : *
2670 : * @see GDALRasterBand::SetNoDataValue()
2671 : */
2672 :
2673 954 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2674 : double dfValue)
2675 :
2676 : {
2677 954 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2678 :
2679 954 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2680 954 : return poBand->SetNoDataValue(dfValue);
2681 : }
2682 :
2683 : /************************************************************************/
2684 : /* SetNoDataValueAsInt64() */
2685 : /************************************************************************/
2686 :
2687 : /**
2688 : * \brief Set the no data value for this band.
2689 : *
2690 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2691 : *
2692 : * Depending on drivers, changing the no data value may or may not have an
2693 : * effect on the pixel values of a raster that has just been created. It is
2694 : * thus advised to explicitly called Fill() if the intent is to initialize
2695 : * the raster to the nodata value.
2696 : * In ay case, changing an existing no data value, when one already exists and
2697 : * the dataset exists or has been initialized, has no effect on the pixel whose
2698 : * value matched the previous nodata value.
2699 : *
2700 : * To clear the nodata value, use DeleteNoDataValue().
2701 : *
2702 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2703 : *
2704 : * @param nNoDataValue the value to set.
2705 : *
2706 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2707 : * by the driver, CE_Failure is returned but no error message will have
2708 : * been emitted.
2709 : *
2710 : * @since GDAL 3.5
2711 : */
2712 :
2713 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2714 :
2715 : {
2716 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2717 0 : ReportError(CE_Failure, CPLE_NotSupported,
2718 : "SetNoDataValueAsInt64() not supported for this dataset.");
2719 :
2720 0 : return CE_Failure;
2721 : }
2722 :
2723 : /************************************************************************/
2724 : /* GDALSetRasterNoDataValueAsInt64() */
2725 : /************************************************************************/
2726 :
2727 : /**
2728 : * \brief Set the no data value for this band.
2729 : *
2730 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2731 : *
2732 : * Depending on drivers, changing the no data value may or may not have an
2733 : * effect on the pixel values of a raster that has just been created. It is
2734 : * thus advised to explicitly called Fill() if the intent is to initialize
2735 : * the raster to the nodata value.
2736 : * In ay case, changing an existing no data value, when one already exists and
2737 : * the dataset exists or has been initialized, has no effect on the pixel whose
2738 : * value matched the previous nodata value.
2739 : *
2740 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2741 : *
2742 : * @since GDAL 3.5
2743 : */
2744 :
2745 22 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2746 : int64_t nValue)
2747 :
2748 : {
2749 22 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2750 :
2751 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2752 22 : return poBand->SetNoDataValueAsInt64(nValue);
2753 : }
2754 :
2755 : /************************************************************************/
2756 : /* SetNoDataValueAsUInt64() */
2757 : /************************************************************************/
2758 :
2759 : /**
2760 : * \brief Set the no data value for this band.
2761 : *
2762 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2763 : *
2764 : * Depending on drivers, changing the no data value may or may not have an
2765 : * effect on the pixel values of a raster that has just been created. It is
2766 : * thus advised to explicitly called Fill() if the intent is to initialize
2767 : * the raster to the nodata value.
2768 : * In ay case, changing an existing no data value, when one already exists and
2769 : * the dataset exists or has been initialized, has no effect on the pixel whose
2770 : * value matched the previous nodata value.
2771 : *
2772 : * To clear the nodata value, use DeleteNoDataValue().
2773 : *
2774 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2775 : *
2776 : * @param nNoDataValue the value to set.
2777 : *
2778 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2779 : * by the driver, CE_Failure is returned but no error message will have
2780 : * been emitted.
2781 : *
2782 : * @since GDAL 3.5
2783 : */
2784 :
2785 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2786 :
2787 : {
2788 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2789 0 : ReportError(CE_Failure, CPLE_NotSupported,
2790 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2791 :
2792 0 : return CE_Failure;
2793 : }
2794 :
2795 : /************************************************************************/
2796 : /* GDALSetRasterNoDataValueAsUInt64() */
2797 : /************************************************************************/
2798 :
2799 : /**
2800 : * \brief Set the no data value for this band.
2801 : *
2802 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2803 : *
2804 : * Depending on drivers, changing the no data value may or may not have an
2805 : * effect on the pixel values of a raster that has just been created. It is
2806 : * thus advised to explicitly called Fill() if the intent is to initialize
2807 : * the raster to the nodata value.
2808 : * In ay case, changing an existing no data value, when one already exists and
2809 : * the dataset exists or has been initialized, has no effect on the pixel whose
2810 : * value matched the previous nodata value.
2811 : *
2812 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2813 : *
2814 : * @since GDAL 3.5
2815 : */
2816 :
2817 21 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2818 : uint64_t nValue)
2819 :
2820 : {
2821 21 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2822 :
2823 21 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2824 21 : return poBand->SetNoDataValueAsUInt64(nValue);
2825 : }
2826 :
2827 : /************************************************************************/
2828 : /* DeleteNoDataValue() */
2829 : /************************************************************************/
2830 :
2831 : /**
2832 : * \brief Remove the no data value for this band.
2833 : *
2834 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2835 : *
2836 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2837 : * by the driver, CE_Failure is returned but no error message will have
2838 : * been emitted.
2839 : *
2840 : */
2841 :
2842 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2843 :
2844 : {
2845 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2846 0 : ReportError(CE_Failure, CPLE_NotSupported,
2847 : "DeleteNoDataValue() not supported for this dataset.");
2848 :
2849 0 : return CE_Failure;
2850 : }
2851 :
2852 : /************************************************************************/
2853 : /* GDALDeleteRasterNoDataValue() */
2854 : /************************************************************************/
2855 :
2856 : /**
2857 : * \brief Remove the no data value for this band.
2858 : *
2859 : * @see GDALRasterBand::DeleteNoDataValue()
2860 : *
2861 : */
2862 :
2863 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2864 :
2865 : {
2866 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2867 :
2868 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2869 53 : return poBand->DeleteNoDataValue();
2870 : }
2871 :
2872 : /************************************************************************/
2873 : /* GetMaximum() */
2874 : /************************************************************************/
2875 :
2876 : /**
2877 : * \brief Fetch the maximum value for this band.
2878 : *
2879 : * For file formats that don't know this intrinsically, the maximum supported
2880 : * value for the data type will generally be returned.
2881 : *
2882 : * This method is the same as the C function GDALGetRasterMaximum().
2883 : *
2884 : * @param pbSuccess pointer to a boolean to use to indicate if the
2885 : * returned value is a tight maximum or not. May be NULL (default).
2886 : *
2887 : * @return the maximum raster value (excluding no data pixels)
2888 : */
2889 :
2890 543 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2891 :
2892 : {
2893 543 : const char *pszValue = nullptr;
2894 :
2895 543 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2896 : {
2897 47 : if (pbSuccess != nullptr)
2898 42 : *pbSuccess = TRUE;
2899 :
2900 47 : return CPLAtofM(pszValue);
2901 : }
2902 :
2903 496 : if (pbSuccess != nullptr)
2904 492 : *pbSuccess = FALSE;
2905 :
2906 496 : switch (eDataType)
2907 : {
2908 340 : case GDT_UInt8:
2909 : {
2910 340 : EnablePixelTypeSignedByteWarning(false);
2911 : const char *pszPixelType =
2912 340 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2913 340 : EnablePixelTypeSignedByteWarning(true);
2914 340 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2915 0 : return 127;
2916 :
2917 340 : return 255;
2918 : }
2919 :
2920 1 : case GDT_Int8:
2921 1 : return 127;
2922 :
2923 21 : case GDT_UInt16:
2924 21 : return 65535;
2925 :
2926 24 : case GDT_Int16:
2927 : case GDT_CInt16:
2928 24 : return 32767;
2929 :
2930 39 : case GDT_Int32:
2931 : case GDT_CInt32:
2932 39 : return 2147483647.0;
2933 :
2934 14 : case GDT_UInt32:
2935 14 : return 4294967295.0;
2936 :
2937 1 : case GDT_Int64:
2938 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2939 :
2940 1 : case GDT_UInt64:
2941 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2942 :
2943 0 : case GDT_Float16:
2944 : case GDT_CFloat16:
2945 0 : return 65504.0;
2946 :
2947 33 : case GDT_Float32:
2948 : case GDT_CFloat32:
2949 33 : return 4294967295.0; // Not actually accurate.
2950 :
2951 22 : case GDT_Float64:
2952 : case GDT_CFloat64:
2953 22 : return 4294967295.0; // Not actually accurate.
2954 :
2955 0 : case GDT_Unknown:
2956 : case GDT_TypeCount:
2957 0 : break;
2958 : }
2959 0 : return 4294967295.0; // Not actually accurate.
2960 : }
2961 :
2962 : /************************************************************************/
2963 : /* GDALGetRasterMaximum() */
2964 : /************************************************************************/
2965 :
2966 : /**
2967 : * \brief Fetch the maximum value for this band.
2968 : *
2969 : * @see GDALRasterBand::GetMaximum()
2970 : */
2971 :
2972 345 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2973 :
2974 : {
2975 345 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2976 :
2977 345 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2978 345 : return poBand->GetMaximum(pbSuccess);
2979 : }
2980 :
2981 : /************************************************************************/
2982 : /* GetMinimum() */
2983 : /************************************************************************/
2984 :
2985 : /**
2986 : * \brief Fetch the minimum value for this band.
2987 : *
2988 : * For file formats that don't know this intrinsically, the minimum supported
2989 : * value for the data type will generally be returned.
2990 : *
2991 : * This method is the same as the C function GDALGetRasterMinimum().
2992 : *
2993 : * @param pbSuccess pointer to a boolean to use to indicate if the
2994 : * returned value is a tight minimum or not. May be NULL (default).
2995 : *
2996 : * @return the minimum raster value (excluding no data pixels)
2997 : */
2998 :
2999 551 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3000 :
3001 : {
3002 551 : const char *pszValue = nullptr;
3003 :
3004 551 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
3005 : {
3006 52 : if (pbSuccess != nullptr)
3007 47 : *pbSuccess = TRUE;
3008 :
3009 52 : return CPLAtofM(pszValue);
3010 : }
3011 :
3012 499 : if (pbSuccess != nullptr)
3013 495 : *pbSuccess = FALSE;
3014 :
3015 499 : switch (eDataType)
3016 : {
3017 343 : case GDT_UInt8:
3018 : {
3019 343 : EnablePixelTypeSignedByteWarning(false);
3020 : const char *pszPixelType =
3021 343 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3022 343 : EnablePixelTypeSignedByteWarning(true);
3023 343 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3024 0 : return -128;
3025 :
3026 343 : return 0;
3027 : }
3028 :
3029 1 : case GDT_Int8:
3030 1 : return -128;
3031 :
3032 21 : case GDT_UInt16:
3033 21 : return 0;
3034 :
3035 24 : case GDT_Int16:
3036 : case GDT_CInt16:
3037 24 : return -32768;
3038 :
3039 39 : case GDT_Int32:
3040 : case GDT_CInt32:
3041 39 : return -2147483648.0;
3042 :
3043 14 : case GDT_UInt32:
3044 14 : return 0;
3045 :
3046 1 : case GDT_Int64:
3047 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3048 :
3049 1 : case GDT_UInt64:
3050 1 : return 0;
3051 :
3052 0 : case GDT_Float16:
3053 : case GDT_CFloat16:
3054 0 : return -65504.0;
3055 :
3056 33 : case GDT_Float32:
3057 : case GDT_CFloat32:
3058 33 : return -4294967295.0; // Not actually accurate.
3059 :
3060 22 : case GDT_Float64:
3061 : case GDT_CFloat64:
3062 22 : return -4294967295.0; // Not actually accurate.
3063 :
3064 0 : case GDT_Unknown:
3065 : case GDT_TypeCount:
3066 0 : break;
3067 : }
3068 0 : return -4294967295.0; // Not actually accurate.
3069 : }
3070 :
3071 : /************************************************************************/
3072 : /* GDALGetRasterMinimum() */
3073 : /************************************************************************/
3074 :
3075 : /**
3076 : * \brief Fetch the minimum value for this band.
3077 : *
3078 : * @see GDALRasterBand::GetMinimum()
3079 : */
3080 :
3081 355 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3082 :
3083 : {
3084 355 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3085 :
3086 355 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3087 355 : return poBand->GetMinimum(pbSuccess);
3088 : }
3089 :
3090 : /************************************************************************/
3091 : /* GetColorInterpretation() */
3092 : /************************************************************************/
3093 :
3094 : /**
3095 : * \brief How should this band be interpreted as color?
3096 : *
3097 : * GCI_Undefined is returned when the format doesn't know anything
3098 : * about the color interpretation.
3099 : *
3100 : * This method is the same as the C function
3101 : * GDALGetRasterColorInterpretation().
3102 : *
3103 : * @return color interpretation value for band.
3104 : */
3105 :
3106 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3107 :
3108 : {
3109 163 : return GCI_Undefined;
3110 : }
3111 :
3112 : /************************************************************************/
3113 : /* GDALGetRasterColorInterpretation() */
3114 : /************************************************************************/
3115 :
3116 : /**
3117 : * \brief How should this band be interpreted as color?
3118 : *
3119 : * @see GDALRasterBand::GetColorInterpretation()
3120 : */
3121 :
3122 : GDALColorInterp CPL_STDCALL
3123 5754 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3124 :
3125 : {
3126 5754 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3127 :
3128 5754 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3129 5754 : return poBand->GetColorInterpretation();
3130 : }
3131 :
3132 : /************************************************************************/
3133 : /* SetColorInterpretation() */
3134 : /************************************************************************/
3135 :
3136 : /**
3137 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3138 : * \brief Set color interpretation of a band.
3139 : *
3140 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3141 : *
3142 : * @param eColorInterp the new color interpretation to apply to this band.
3143 : *
3144 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3145 : */
3146 :
3147 : /**/
3148 : /**/
3149 :
3150 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3151 :
3152 : {
3153 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3154 3 : ReportError(CE_Failure, CPLE_NotSupported,
3155 : "SetColorInterpretation() not supported for this dataset.");
3156 3 : return CE_Failure;
3157 : }
3158 :
3159 : /************************************************************************/
3160 : /* GDALSetRasterColorInterpretation() */
3161 : /************************************************************************/
3162 :
3163 : /**
3164 : * \brief Set color interpretation of a band.
3165 : *
3166 : * @see GDALRasterBand::SetColorInterpretation()
3167 : */
3168 :
3169 1860 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3170 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3171 :
3172 : {
3173 1860 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3174 :
3175 1860 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3176 1860 : return poBand->SetColorInterpretation(eColorInterp);
3177 : }
3178 :
3179 : /************************************************************************/
3180 : /* GetColorTable() */
3181 : /************************************************************************/
3182 :
3183 : /**
3184 : * \brief Fetch the color table associated with band.
3185 : *
3186 : * If there is no associated color table, the return result is NULL. The
3187 : * returned color table remains owned by the GDALRasterBand, and can't
3188 : * be depended on for long, nor should it ever be modified by the caller.
3189 : *
3190 : * This method is the same as the C function GDALGetRasterColorTable().
3191 : *
3192 : * @return internal color table, or NULL.
3193 : */
3194 :
3195 213 : GDALColorTable *GDALRasterBand::GetColorTable()
3196 :
3197 : {
3198 213 : return nullptr;
3199 : }
3200 :
3201 : /************************************************************************/
3202 : /* GDALGetRasterColorTable() */
3203 : /************************************************************************/
3204 :
3205 : /**
3206 : * \brief Fetch the color table associated with band.
3207 : *
3208 : * @see GDALRasterBand::GetColorTable()
3209 : */
3210 :
3211 1993 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3212 :
3213 : {
3214 1993 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3215 :
3216 1993 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3217 1993 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3218 : }
3219 :
3220 : /************************************************************************/
3221 : /* SetColorTable() */
3222 : /************************************************************************/
3223 :
3224 : /**
3225 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3226 : * \brief Set the raster color table.
3227 : *
3228 : * The driver will make a copy of all desired data in the colortable. It
3229 : * remains owned by the caller after the call.
3230 : *
3231 : * This method is the same as the C function GDALSetRasterColorTable().
3232 : *
3233 : * @param poCT the color table to apply. This may be NULL to clear the color
3234 : * table (where supported).
3235 : *
3236 : * @return CE_None on success, or CE_Failure on failure. If the action is
3237 : * unsupported by the driver, a value of CE_Failure is returned, but no
3238 : * error is issued.
3239 : */
3240 :
3241 : /**/
3242 : /**/
3243 :
3244 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3245 :
3246 : {
3247 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3248 0 : ReportError(CE_Failure, CPLE_NotSupported,
3249 : "SetColorTable() not supported for this dataset.");
3250 0 : return CE_Failure;
3251 : }
3252 :
3253 : /************************************************************************/
3254 : /* GDALSetRasterColorTable() */
3255 : /************************************************************************/
3256 :
3257 : /**
3258 : * \brief Set the raster color table.
3259 : *
3260 : * @see GDALRasterBand::SetColorTable()
3261 : */
3262 :
3263 78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3264 : GDALColorTableH hCT)
3265 :
3266 : {
3267 78 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3268 :
3269 78 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3270 78 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3271 : }
3272 :
3273 : /************************************************************************/
3274 : /* HasArbitraryOverviews() */
3275 : /************************************************************************/
3276 :
3277 : /**
3278 : * \brief Check for arbitrary overviews.
3279 : *
3280 : * This returns TRUE if the underlying datastore can compute arbitrary
3281 : * overviews efficiently, such as is the case with OGDI over a network.
3282 : * Datastores with arbitrary overviews don't generally have any fixed
3283 : * overviews, but the RasterIO() method can be used in downsampling mode
3284 : * to get overview data efficiently.
3285 : *
3286 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3287 : *
3288 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3289 : * FALSE.
3290 : */
3291 :
3292 276 : int GDALRasterBand::HasArbitraryOverviews()
3293 :
3294 : {
3295 276 : return FALSE;
3296 : }
3297 :
3298 : /************************************************************************/
3299 : /* GDALHasArbitraryOverviews() */
3300 : /************************************************************************/
3301 :
3302 : /**
3303 : * \brief Check for arbitrary overviews.
3304 : *
3305 : * @see GDALRasterBand::HasArbitraryOverviews()
3306 : */
3307 :
3308 197 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3309 :
3310 : {
3311 197 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3312 :
3313 197 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3314 197 : return poBand->HasArbitraryOverviews();
3315 : }
3316 :
3317 : /************************************************************************/
3318 : /* GetOverviewCount() */
3319 : /************************************************************************/
3320 :
3321 : /**
3322 : * \brief Return the number of overview layers available.
3323 : *
3324 : * This method is the same as the C function GDALGetOverviewCount().
3325 : *
3326 : * @return overview count, zero if none.
3327 : */
3328 :
3329 1066600 : int GDALRasterBand::GetOverviewCount()
3330 :
3331 : {
3332 1723460 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3333 656861 : poDS->AreOverviewsEnabled())
3334 656861 : return poDS->oOvManager.GetOverviewCount(nBand);
3335 :
3336 409738 : return 0;
3337 : }
3338 :
3339 : /************************************************************************/
3340 : /* GDALGetOverviewCount() */
3341 : /************************************************************************/
3342 :
3343 : /**
3344 : * \brief Return the number of overview layers available.
3345 : *
3346 : * @see GDALRasterBand::GetOverviewCount()
3347 : */
3348 :
3349 3308 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3350 :
3351 : {
3352 3308 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3353 :
3354 3308 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3355 3308 : return poBand->GetOverviewCount();
3356 : }
3357 :
3358 : /************************************************************************/
3359 : /* GetOverview() */
3360 : /************************************************************************/
3361 :
3362 : /**
3363 : * \brief Fetch overview raster band object.
3364 : *
3365 : * This method is the same as the C function GDALGetOverview().
3366 : *
3367 : * @param i overview index between 0 and GetOverviewCount()-1.
3368 : *
3369 : * @return overview GDALRasterBand.
3370 : */
3371 :
3372 942 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3373 :
3374 : {
3375 1732 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3376 790 : poDS->AreOverviewsEnabled())
3377 790 : return poDS->oOvManager.GetOverview(nBand, i);
3378 :
3379 152 : return nullptr;
3380 : }
3381 :
3382 : /************************************************************************/
3383 : /* GDALGetOverview() */
3384 : /************************************************************************/
3385 :
3386 : /**
3387 : * \brief Fetch overview raster band object.
3388 : *
3389 : * @see GDALRasterBand::GetOverview()
3390 : */
3391 :
3392 5641 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3393 :
3394 : {
3395 5641 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3396 :
3397 5641 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3398 5641 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3399 : }
3400 :
3401 : /************************************************************************/
3402 : /* GetRasterSampleOverview() */
3403 : /************************************************************************/
3404 :
3405 : /**
3406 : * \brief Fetch best sampling overview.
3407 : *
3408 : * Returns the most reduced overview of the given band that still satisfies
3409 : * the desired number of samples. This function can be used with zero
3410 : * as the number of desired samples to fetch the most reduced overview.
3411 : * The same band as was passed in will be returned if it has not overviews,
3412 : * or if none of the overviews have enough samples.
3413 : *
3414 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3415 : * and GDALGetRasterSampleOverviewEx().
3416 : *
3417 : * @param nDesiredSamples the returned band will have at least this many
3418 : * pixels.
3419 : *
3420 : * @return optimal overview or the band itself.
3421 : */
3422 :
3423 : GDALRasterBand *
3424 2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3425 :
3426 : {
3427 2009 : GDALRasterBand *poBestBand = this;
3428 :
3429 2009 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3430 :
3431 4029 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3432 : {
3433 2020 : GDALRasterBand *poOBand = GetOverview(iOverview);
3434 :
3435 2020 : if (poOBand == nullptr)
3436 0 : continue;
3437 :
3438 : const double dfOSamples =
3439 2020 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3440 :
3441 2020 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3442 : {
3443 2017 : dfBestSamples = dfOSamples;
3444 2017 : poBestBand = poOBand;
3445 : }
3446 : }
3447 :
3448 2009 : return poBestBand;
3449 : }
3450 :
3451 : /************************************************************************/
3452 : /* GDALGetRasterSampleOverview() */
3453 : /************************************************************************/
3454 :
3455 : /**
3456 : * \brief Fetch best sampling overview.
3457 : *
3458 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3459 : * billion samples.
3460 : *
3461 : * @see GDALRasterBand::GetRasterSampleOverview()
3462 : * @see GDALGetRasterSampleOverviewEx()
3463 : */
3464 :
3465 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3466 : int nDesiredSamples)
3467 :
3468 : {
3469 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3470 :
3471 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3472 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3473 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3474 : }
3475 :
3476 : /************************************************************************/
3477 : /* GDALGetRasterSampleOverviewEx() */
3478 : /************************************************************************/
3479 :
3480 : /**
3481 : * \brief Fetch best sampling overview.
3482 : *
3483 : * @see GDALRasterBand::GetRasterSampleOverview()
3484 : */
3485 :
3486 : GDALRasterBandH CPL_STDCALL
3487 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3488 :
3489 : {
3490 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3491 :
3492 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3493 2000 : return GDALRasterBand::ToHandle(
3494 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3495 : }
3496 :
3497 : /************************************************************************/
3498 : /* BuildOverviews() */
3499 : /************************************************************************/
3500 :
3501 : /**
3502 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3503 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3504 : *
3505 : * If the operation is unsupported for the indicated dataset, then
3506 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3507 : * CPLE_NotSupported.
3508 : *
3509 : * WARNING: Most formats don't support per-band overview computation, but
3510 : * require that overviews are computed for all bands of a dataset, using
3511 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3512 : * is the HFA driver which supports this method.
3513 : *
3514 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3515 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3516 : * applied.
3517 : * @param nOverviews number of overviews to build.
3518 : * @param panOverviewList the list of overview decimation factors to build.
3519 : * @param pfnProgress a function to call to report progress, or NULL.
3520 : * @param pProgressData application data to pass to the progress function.
3521 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3522 : * key=value pairs, or NULL
3523 : *
3524 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3525 : */
3526 :
3527 : /**/
3528 : /**/
3529 :
3530 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3531 : int /*nOverviews*/,
3532 : const int * /*panOverviewList*/,
3533 : GDALProgressFunc /*pfnProgress*/,
3534 : void * /*pProgressData*/,
3535 : CSLConstList /* papszOptions */)
3536 :
3537 : {
3538 0 : ReportError(CE_Failure, CPLE_NotSupported,
3539 : "BuildOverviews() not supported for this dataset.");
3540 :
3541 0 : return (CE_Failure);
3542 : }
3543 :
3544 : /************************************************************************/
3545 : /* GetOffset() */
3546 : /************************************************************************/
3547 :
3548 : /**
3549 : * \brief Fetch the raster value offset.
3550 : *
3551 : * This value (in combination with the GetScale() value) can be used to
3552 : * transform raw pixel values into the units returned by GetUnitType().
3553 : * For example this might be used to store elevations in GUInt16 bands
3554 : * with a precision of 0.1, and starting from -100.
3555 : *
3556 : * Units value = (raw value * scale) + offset
3557 : *
3558 : * Note that applying scale and offset is of the responsibility of the user,
3559 : * and is not done by methods such as RasterIO() or ReadBlock().
3560 : *
3561 : * For file formats that don't know this intrinsically a value of zero
3562 : * is returned.
3563 : *
3564 : * This method is the same as the C function GDALGetRasterOffset().
3565 : *
3566 : * @param pbSuccess pointer to a boolean to use to indicate if the
3567 : * returned value is meaningful or not. May be NULL (default).
3568 : *
3569 : * @return the raster offset.
3570 : */
3571 :
3572 445 : double GDALRasterBand::GetOffset(int *pbSuccess)
3573 :
3574 : {
3575 445 : if (pbSuccess != nullptr)
3576 336 : *pbSuccess = FALSE;
3577 :
3578 445 : return 0.0;
3579 : }
3580 :
3581 : /************************************************************************/
3582 : /* GDALGetRasterOffset() */
3583 : /************************************************************************/
3584 :
3585 : /**
3586 : * \brief Fetch the raster value offset.
3587 : *
3588 : * @see GDALRasterBand::GetOffset()
3589 : */
3590 :
3591 402 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3592 :
3593 : {
3594 402 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3595 :
3596 402 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3597 402 : return poBand->GetOffset(pbSuccess);
3598 : }
3599 :
3600 : /************************************************************************/
3601 : /* SetOffset() */
3602 : /************************************************************************/
3603 :
3604 : /**
3605 : * \fn GDALRasterBand::SetOffset(double)
3606 : * \brief Set scaling offset.
3607 : *
3608 : * Very few formats implement this method. When not implemented it will
3609 : * issue a CPLE_NotSupported error and return CE_Failure.
3610 : *
3611 : * This method is the same as the C function GDALSetRasterOffset().
3612 : *
3613 : * @param dfNewOffset the new offset.
3614 : *
3615 : * @return CE_None or success or CE_Failure on failure.
3616 : */
3617 :
3618 : /**/
3619 : /**/
3620 :
3621 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3622 : {
3623 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3624 0 : ReportError(CE_Failure, CPLE_NotSupported,
3625 : "SetOffset() not supported on this raster band.");
3626 :
3627 0 : return CE_Failure;
3628 : }
3629 :
3630 : /************************************************************************/
3631 : /* GDALSetRasterOffset() */
3632 : /************************************************************************/
3633 :
3634 : /**
3635 : * \brief Set scaling offset.
3636 : *
3637 : * @see GDALRasterBand::SetOffset()
3638 : */
3639 :
3640 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3641 : double dfNewOffset)
3642 :
3643 : {
3644 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3645 :
3646 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3647 86 : return poBand->SetOffset(dfNewOffset);
3648 : }
3649 :
3650 : /************************************************************************/
3651 : /* GetScale() */
3652 : /************************************************************************/
3653 :
3654 : /**
3655 : * \brief Fetch the raster value scale.
3656 : *
3657 : * This value (in combination with the GetOffset() value) can be used to
3658 : * transform raw pixel values into the units returned by GetUnitType().
3659 : * For example this might be used to store elevations in GUInt16 bands
3660 : * with a precision of 0.1, and starting from -100.
3661 : *
3662 : * Units value = (raw value * scale) + offset
3663 : *
3664 : * Note that applying scale and offset is of the responsibility of the user,
3665 : * and is not done by methods such as RasterIO() or ReadBlock().
3666 : *
3667 : * For file formats that don't know this intrinsically a value of one
3668 : * is returned.
3669 : *
3670 : * This method is the same as the C function GDALGetRasterScale().
3671 : *
3672 : * @param pbSuccess pointer to a boolean to use to indicate if the
3673 : * returned value is meaningful or not. May be NULL (default).
3674 : *
3675 : * @return the raster scale.
3676 : */
3677 :
3678 445 : double GDALRasterBand::GetScale(int *pbSuccess)
3679 :
3680 : {
3681 445 : if (pbSuccess != nullptr)
3682 336 : *pbSuccess = FALSE;
3683 :
3684 445 : return 1.0;
3685 : }
3686 :
3687 : /************************************************************************/
3688 : /* GDALGetRasterScale() */
3689 : /************************************************************************/
3690 :
3691 : /**
3692 : * \brief Fetch the raster value scale.
3693 : *
3694 : * @see GDALRasterBand::GetScale()
3695 : */
3696 :
3697 400 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3698 :
3699 : {
3700 400 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3701 :
3702 400 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3703 400 : return poBand->GetScale(pbSuccess);
3704 : }
3705 :
3706 : /************************************************************************/
3707 : /* SetScale() */
3708 : /************************************************************************/
3709 :
3710 : /**
3711 : * \fn GDALRasterBand::SetScale(double)
3712 : * \brief Set scaling ratio.
3713 : *
3714 : * Very few formats implement this method. When not implemented it will
3715 : * issue a CPLE_NotSupported error and return CE_Failure.
3716 : *
3717 : * This method is the same as the C function GDALSetRasterScale().
3718 : *
3719 : * @param dfNewScale the new scale.
3720 : *
3721 : * @return CE_None or success or CE_Failure on failure.
3722 : */
3723 :
3724 : /**/
3725 : /**/
3726 :
3727 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3728 :
3729 : {
3730 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3731 0 : ReportError(CE_Failure, CPLE_NotSupported,
3732 : "SetScale() not supported on this raster band.");
3733 :
3734 0 : return CE_Failure;
3735 : }
3736 :
3737 : /************************************************************************/
3738 : /* GDALSetRasterScale() */
3739 : /************************************************************************/
3740 :
3741 : /**
3742 : * \brief Set scaling ratio.
3743 : *
3744 : * @see GDALRasterBand::SetScale()
3745 : */
3746 :
3747 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3748 :
3749 : {
3750 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3751 :
3752 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3753 87 : return poBand->SetScale(dfNewOffset);
3754 : }
3755 :
3756 : /************************************************************************/
3757 : /* GetUnitType() */
3758 : /************************************************************************/
3759 :
3760 : /**
3761 : * \brief Return raster unit type.
3762 : *
3763 : * Return a name for the units of this raster's values. For instance, it
3764 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3765 : * units are available, a value of "" will be returned. The returned string
3766 : * should not be modified, nor freed by the calling application.
3767 : *
3768 : * This method is the same as the C function GDALGetRasterUnitType().
3769 : *
3770 : * @return unit name string.
3771 : */
3772 :
3773 165 : const char *GDALRasterBand::GetUnitType()
3774 :
3775 : {
3776 165 : return "";
3777 : }
3778 :
3779 : /************************************************************************/
3780 : /* GDALGetRasterUnitType() */
3781 : /************************************************************************/
3782 :
3783 : /**
3784 : * \brief Return raster unit type.
3785 : *
3786 : * @see GDALRasterBand::GetUnitType()
3787 : */
3788 :
3789 1498 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3790 :
3791 : {
3792 1498 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3793 :
3794 1498 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3795 1498 : return poBand->GetUnitType();
3796 : }
3797 :
3798 : /************************************************************************/
3799 : /* SetUnitType() */
3800 : /************************************************************************/
3801 :
3802 : /**
3803 : * \fn GDALRasterBand::SetUnitType(const char*)
3804 : * \brief Set unit type.
3805 : *
3806 : * Set the unit type for a raster band. Values should be one of
3807 : * "" (the default indicating it is unknown), "m" indicating meters,
3808 : * or "ft" indicating feet, though other nonstandard values are allowed.
3809 : *
3810 : * This method is the same as the C function GDALSetRasterUnitType().
3811 : *
3812 : * @param pszNewValue the new unit type value.
3813 : *
3814 : * @return CE_None on success or CE_Failure if not successful, or
3815 : * unsupported.
3816 : */
3817 :
3818 : /**/
3819 : /**/
3820 :
3821 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3822 :
3823 : {
3824 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3825 0 : ReportError(CE_Failure, CPLE_NotSupported,
3826 : "SetUnitType() not supported on this raster band.");
3827 0 : return CE_Failure;
3828 : }
3829 :
3830 : /************************************************************************/
3831 : /* GDALSetRasterUnitType() */
3832 : /************************************************************************/
3833 :
3834 : /**
3835 : * \brief Set unit type.
3836 : *
3837 : * @see GDALRasterBand::SetUnitType()
3838 : *
3839 : */
3840 :
3841 98 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842 : const char *pszNewValue)
3843 :
3844 : {
3845 98 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846 :
3847 98 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848 98 : return poBand->SetUnitType(pszNewValue);
3849 : }
3850 :
3851 : /************************************************************************/
3852 : /* GetXSize() */
3853 : /************************************************************************/
3854 :
3855 : /**
3856 : * \brief Fetch XSize of raster.
3857 : *
3858 : * This method is the same as the C function GDALGetRasterBandXSize().
3859 : *
3860 : * @return the width in pixels of this band.
3861 : */
3862 :
3863 8468010 : int GDALRasterBand::GetXSize() const
3864 :
3865 : {
3866 8468010 : return nRasterXSize;
3867 : }
3868 :
3869 : /************************************************************************/
3870 : /* GDALGetRasterBandXSize() */
3871 : /************************************************************************/
3872 :
3873 : /**
3874 : * \brief Fetch XSize of raster.
3875 : *
3876 : * @see GDALRasterBand::GetXSize()
3877 : */
3878 :
3879 58000 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880 :
3881 : {
3882 58000 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883 :
3884 58000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885 58000 : return poBand->GetXSize();
3886 : }
3887 :
3888 : /************************************************************************/
3889 : /* GetYSize() */
3890 : /************************************************************************/
3891 :
3892 : /**
3893 : * \brief Fetch YSize of raster.
3894 : *
3895 : * This method is the same as the C function GDALGetRasterBandYSize().
3896 : *
3897 : * @return the height in pixels of this band.
3898 : */
3899 :
3900 4703740 : int GDALRasterBand::GetYSize() const
3901 :
3902 : {
3903 4703740 : return nRasterYSize;
3904 : }
3905 :
3906 : /************************************************************************/
3907 : /* GDALGetRasterBandYSize() */
3908 : /************************************************************************/
3909 :
3910 : /**
3911 : * \brief Fetch YSize of raster.
3912 : *
3913 : * @see GDALRasterBand::GetYSize()
3914 : */
3915 :
3916 56863 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917 :
3918 : {
3919 56863 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920 :
3921 56863 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922 56863 : return poBand->GetYSize();
3923 : }
3924 :
3925 : /************************************************************************/
3926 : /* GetBand() */
3927 : /************************************************************************/
3928 :
3929 : /**
3930 : * \brief Fetch the band number.
3931 : *
3932 : * This method returns the band that this GDALRasterBand objects represents
3933 : * within its dataset. This method may return a value of 0 to indicate
3934 : * GDALRasterBand objects without an apparently relationship to a dataset,
3935 : * such as GDALRasterBands serving as overviews.
3936 : *
3937 : * This method is the same as the C function GDALGetBandNumber().
3938 : *
3939 : * @return band number (1+) or 0 if the band number isn't known.
3940 : */
3941 :
3942 150875 : int GDALRasterBand::GetBand() const
3943 :
3944 : {
3945 150875 : return nBand;
3946 : }
3947 :
3948 : /************************************************************************/
3949 : /* GDALGetBandNumber() */
3950 : /************************************************************************/
3951 :
3952 : /**
3953 : * \brief Fetch the band number.
3954 : *
3955 : * @see GDALRasterBand::GetBand()
3956 : */
3957 :
3958 208 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3959 :
3960 : {
3961 208 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3962 :
3963 208 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3964 208 : return poBand->GetBand();
3965 : }
3966 :
3967 : /************************************************************************/
3968 : /* GetDataset() */
3969 : /************************************************************************/
3970 :
3971 : /**
3972 : * \brief Fetch the owning dataset handle.
3973 : *
3974 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3975 : * such as overviews or other "freestanding" bands.
3976 : *
3977 : * This method is the same as the C function GDALGetBandDataset().
3978 : *
3979 : * @return the pointer to the GDALDataset to which this band belongs, or
3980 : * NULL if this cannot be determined.
3981 : */
3982 :
3983 5294720 : GDALDataset *GDALRasterBand::GetDataset() const
3984 :
3985 : {
3986 5294720 : return poDS;
3987 : }
3988 :
3989 : /************************************************************************/
3990 : /* GDALGetBandDataset() */
3991 : /************************************************************************/
3992 :
3993 : /**
3994 : * \brief Fetch the owning dataset handle.
3995 : *
3996 : * @see GDALRasterBand::GetDataset()
3997 : */
3998 :
3999 358 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000 :
4001 : {
4002 358 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003 :
4004 358 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005 358 : return GDALDataset::ToHandle(poBand->GetDataset());
4006 : }
4007 :
4008 : /************************************************************************/
4009 : /* ComputeFloat16NoDataValue() */
4010 : /************************************************************************/
4011 :
4012 3025 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013 : double dfNoDataValue,
4014 : int &bGotNoDataValue,
4015 : GFloat16 &fNoDataValue,
4016 : bool &bGotFloat16NoDataValue)
4017 : {
4018 3025 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4019 : {
4020 1 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4021 1 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4022 : {
4023 1 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4024 1 : bGotFloat16NoDataValue = true;
4025 1 : bGotNoDataValue = false;
4026 : }
4027 : }
4028 3025 : }
4029 :
4030 : /************************************************************************/
4031 : /* ComputeFloatNoDataValue() */
4032 : /************************************************************************/
4033 :
4034 3025 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035 : double dfNoDataValue,
4036 : int &bGotNoDataValue,
4037 : float &fNoDataValue,
4038 : bool &bGotFloatNoDataValue)
4039 : {
4040 3025 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4041 : {
4042 91 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4043 91 : if (GDALIsValueInRange<float>(dfNoDataValue))
4044 : {
4045 91 : fNoDataValue = static_cast<float>(dfNoDataValue);
4046 91 : bGotFloatNoDataValue = true;
4047 91 : bGotNoDataValue = false;
4048 : }
4049 : }
4050 3025 : }
4051 :
4052 : /************************************************************************/
4053 : /* struct GDALNoDataValues */
4054 : /************************************************************************/
4055 :
4056 : /**
4057 : * \brief No-data-values for all types
4058 : *
4059 : * The functions below pass various no-data-values around. To avoid
4060 : * long argument lists, this struct collects the no-data-values for
4061 : * all types into a single, convenient place.
4062 : **/
4063 :
4064 : struct GDALNoDataValues
4065 : {
4066 : int bGotNoDataValue;
4067 : double dfNoDataValue;
4068 :
4069 : bool bGotInt64NoDataValue;
4070 : int64_t nInt64NoDataValue;
4071 :
4072 : bool bGotUInt64NoDataValue;
4073 : uint64_t nUInt64NoDataValue;
4074 :
4075 : bool bGotFloatNoDataValue;
4076 : float fNoDataValue;
4077 :
4078 : bool bGotFloat16NoDataValue;
4079 : GFloat16 hfNoDataValue;
4080 :
4081 3117 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4082 3117 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4083 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4084 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4085 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4086 3117 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4087 : {
4088 3117 : if (eDataType == GDT_Int64)
4089 : {
4090 58 : int nGot = false;
4091 58 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4092 58 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4093 58 : if (bGotInt64NoDataValue)
4094 : {
4095 6 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4096 6 : bGotNoDataValue =
4097 6 : nInt64NoDataValue <=
4098 12 : std::numeric_limits<int64_t>::max() - 1024 &&
4099 6 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4100 : }
4101 : else
4102 52 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4103 : }
4104 3059 : else if (eDataType == GDT_UInt64)
4105 : {
4106 34 : int nGot = false;
4107 34 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4108 34 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4109 34 : if (bGotUInt64NoDataValue)
4110 : {
4111 6 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4112 6 : bGotNoDataValue =
4113 6 : nUInt64NoDataValue <=
4114 12 : std::numeric_limits<uint64_t>::max() - 2048 &&
4115 6 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4116 : }
4117 : else
4118 28 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4119 : }
4120 : else
4121 : {
4122 3025 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4123 3025 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4124 :
4125 3025 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4126 3025 : fNoDataValue, bGotFloatNoDataValue);
4127 :
4128 3025 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4129 3025 : hfNoDataValue, bGotFloat16NoDataValue);
4130 : }
4131 3117 : }
4132 : };
4133 :
4134 : /************************************************************************/
4135 : /* ARE_REAL_EQUAL() */
4136 : /************************************************************************/
4137 :
4138 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4139 : {
4140 : using std::abs;
4141 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4142 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4143 0 : abs(dfVal1 + dfVal2) * ulp;
4144 : }
4145 :
4146 : /************************************************************************/
4147 : /* GetHistogram() */
4148 : /************************************************************************/
4149 :
4150 : /**
4151 : * \brief Compute raster histogram.
4152 : *
4153 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4154 : *
4155 : * For example to compute a simple 256 entry histogram of eight bit data,
4156 : * the following would be suitable. The unusual bounds are to ensure that
4157 : * bucket boundaries don't fall right on integer values causing possible errors
4158 : * due to rounding after scaling.
4159 : \code{.cpp}
4160 : GUIntBig anHistogram[256];
4161 :
4162 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4163 : GDALDummyProgress, nullptr );
4164 : \endcode
4165 : *
4166 : * Note that setting bApproxOK will generally result in a subsampling of the
4167 : * file, and will utilize overviews if available. It should generally
4168 : * produce a representative histogram for the data that is suitable for use
4169 : * in generating histogram based luts for instance. Generally bApproxOK is
4170 : * much faster than an exactly computed histogram.
4171 : *
4172 : * This method is the same as the C functions GDALGetRasterHistogram() and
4173 : * GDALGetRasterHistogramEx().
4174 : *
4175 : * @param dfMin the lower bound of the histogram.
4176 : * @param dfMax the upper bound of the histogram.
4177 : * @param nBuckets the number of buckets in panHistogram.
4178 : * @param panHistogram array into which the histogram totals are placed.
4179 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4180 : * mapped into panHistogram[0], and values above will be mapped into
4181 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4182 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4183 : * @param pfnProgress function to report progress to completion.
4184 : * @param pProgressData application data to pass to pfnProgress.
4185 : *
4186 : * @return CE_None on success, or CE_Failure if something goes wrong.
4187 : */
4188 :
4189 45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4190 : GUIntBig *panHistogram,
4191 : int bIncludeOutOfRange, int bApproxOK,
4192 : GDALProgressFunc pfnProgress,
4193 : void *pProgressData)
4194 :
4195 : {
4196 45 : CPLAssert(nullptr != panHistogram);
4197 :
4198 45 : if (pfnProgress == nullptr)
4199 29 : pfnProgress = GDALDummyProgress;
4200 :
4201 : /* -------------------------------------------------------------------- */
4202 : /* If we have overviews, use them for the histogram. */
4203 : /* -------------------------------------------------------------------- */
4204 45 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4205 : {
4206 : // FIXME: should we use the most reduced overview here or use some
4207 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4208 : // does?
4209 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4210 :
4211 0 : if (poBestOverview != this)
4212 : {
4213 0 : return poBestOverview->GetHistogram(
4214 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4215 0 : bApproxOK, pfnProgress, pProgressData);
4216 : }
4217 : }
4218 :
4219 : /* -------------------------------------------------------------------- */
4220 : /* Read actual data and build histogram. */
4221 : /* -------------------------------------------------------------------- */
4222 45 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4223 : {
4224 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4225 0 : return CE_Failure;
4226 : }
4227 :
4228 : // Written this way to deal with NaN
4229 45 : if (!(dfMax > dfMin))
4230 : {
4231 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4232 : "dfMax should be strictly greater than dfMin");
4233 5 : return CE_Failure;
4234 : }
4235 :
4236 : GDALRasterIOExtraArg sExtraArg;
4237 40 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4238 :
4239 40 : const double dfScale = nBuckets / (dfMax - dfMin);
4240 40 : if (dfScale == 0 || !std::isfinite(dfScale))
4241 : {
4242 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4243 : "dfMin and dfMax should be finite values such that "
4244 : "nBuckets / (dfMax - dfMin) is non-zero");
4245 5 : return CE_Failure;
4246 : }
4247 35 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4248 :
4249 35 : GDALNoDataValues sNoDataValues(this, eDataType);
4250 35 : GDALRasterBand *poMaskBand = nullptr;
4251 35 : if (!sNoDataValues.bGotNoDataValue)
4252 : {
4253 34 : const int l_nMaskFlags = GetMaskFlags();
4254 36 : if (l_nMaskFlags != GMF_ALL_VALID &&
4255 2 : GetColorInterpretation() != GCI_AlphaBand)
4256 : {
4257 2 : poMaskBand = GetMaskBand();
4258 : }
4259 : }
4260 :
4261 35 : bool bSignedByte = false;
4262 35 : if (eDataType == GDT_UInt8)
4263 : {
4264 26 : EnablePixelTypeSignedByteWarning(false);
4265 : const char *pszPixelType =
4266 26 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4267 26 : EnablePixelTypeSignedByteWarning(true);
4268 26 : bSignedByte =
4269 26 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4270 : }
4271 :
4272 35 : if (bApproxOK && HasArbitraryOverviews())
4273 : {
4274 : /* --------------------------------------------------------------------
4275 : */
4276 : /* Figure out how much the image should be reduced to get an */
4277 : /* approximate value. */
4278 : /* --------------------------------------------------------------------
4279 : */
4280 : const double dfReduction =
4281 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4282 : GDALSTAT_APPROX_NUMSAMPLES);
4283 :
4284 0 : int nXReduced = nRasterXSize;
4285 0 : int nYReduced = nRasterYSize;
4286 0 : if (dfReduction > 1.0)
4287 : {
4288 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4289 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4290 :
4291 : // Catch the case of huge resizing ratios here
4292 0 : if (nXReduced == 0)
4293 0 : nXReduced = 1;
4294 0 : if (nYReduced == 0)
4295 0 : nYReduced = 1;
4296 : }
4297 :
4298 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4299 : nXReduced, nYReduced);
4300 0 : if (!pData)
4301 0 : return CE_Failure;
4302 :
4303 : const CPLErr eErr =
4304 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4305 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4306 0 : if (eErr != CE_None)
4307 : {
4308 0 : CPLFree(pData);
4309 0 : return eErr;
4310 : }
4311 :
4312 0 : GByte *pabyMaskData = nullptr;
4313 0 : if (poMaskBand)
4314 : {
4315 : pabyMaskData =
4316 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4317 0 : if (!pabyMaskData)
4318 : {
4319 0 : CPLFree(pData);
4320 0 : return CE_Failure;
4321 : }
4322 :
4323 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4324 : pabyMaskData, nXReduced, nYReduced,
4325 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
4326 : {
4327 0 : CPLFree(pData);
4328 0 : CPLFree(pabyMaskData);
4329 0 : return CE_Failure;
4330 : }
4331 : }
4332 :
4333 : // This isn't the fastest way to do this, but is easier for now.
4334 0 : for (int iY = 0; iY < nYReduced; iY++)
4335 : {
4336 0 : for (int iX = 0; iX < nXReduced; iX++)
4337 : {
4338 0 : const int iOffset = iX + iY * nXReduced;
4339 0 : double dfValue = 0.0;
4340 :
4341 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4342 0 : continue;
4343 :
4344 0 : switch (eDataType)
4345 : {
4346 0 : case GDT_UInt8:
4347 : {
4348 0 : if (bSignedByte)
4349 0 : dfValue =
4350 0 : static_cast<signed char *>(pData)[iOffset];
4351 : else
4352 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4353 0 : break;
4354 : }
4355 0 : case GDT_Int8:
4356 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357 0 : break;
4358 0 : case GDT_UInt16:
4359 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360 0 : break;
4361 0 : case GDT_Int16:
4362 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363 0 : break;
4364 0 : case GDT_UInt32:
4365 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366 0 : break;
4367 0 : case GDT_Int32:
4368 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369 0 : break;
4370 0 : case GDT_UInt64:
4371 0 : dfValue = static_cast<double>(
4372 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4373 0 : break;
4374 0 : case GDT_Int64:
4375 0 : dfValue = static_cast<double>(
4376 0 : static_cast<GInt64 *>(pData)[iOffset]);
4377 0 : break;
4378 0 : case GDT_Float16:
4379 : {
4380 : using namespace std;
4381 0 : const GFloat16 hfValue =
4382 0 : static_cast<GFloat16 *>(pData)[iOffset];
4383 0 : if (isnan(hfValue) ||
4384 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4385 0 : ARE_REAL_EQUAL(hfValue,
4386 : sNoDataValues.hfNoDataValue)))
4387 0 : continue;
4388 0 : dfValue = hfValue;
4389 0 : break;
4390 : }
4391 0 : case GDT_Float32:
4392 : {
4393 0 : const float fValue =
4394 0 : static_cast<float *>(pData)[iOffset];
4395 0 : if (std::isnan(fValue) ||
4396 0 : (sNoDataValues.bGotFloatNoDataValue &&
4397 0 : ARE_REAL_EQUAL(fValue,
4398 : sNoDataValues.fNoDataValue)))
4399 0 : continue;
4400 0 : dfValue = double(fValue);
4401 0 : break;
4402 : }
4403 0 : case GDT_Float64:
4404 0 : dfValue = static_cast<double *>(pData)[iOffset];
4405 0 : if (std::isnan(dfValue))
4406 0 : continue;
4407 0 : break;
4408 0 : case GDT_CInt16:
4409 : {
4410 0 : const double dfReal =
4411 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4412 0 : const double dfImag =
4413 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4414 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4415 0 : continue;
4416 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4417 : }
4418 0 : break;
4419 0 : case GDT_CInt32:
4420 : {
4421 0 : const double dfReal =
4422 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4423 0 : const double dfImag =
4424 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4425 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4426 0 : continue;
4427 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4428 : }
4429 0 : break;
4430 0 : case GDT_CFloat16:
4431 : {
4432 : const double dfReal =
4433 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4434 : const double dfImag =
4435 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4436 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4437 0 : continue;
4438 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4439 0 : break;
4440 : }
4441 0 : case GDT_CFloat32:
4442 : {
4443 0 : const double dfReal =
4444 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4445 0 : const double dfImag = double(
4446 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4447 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4448 0 : continue;
4449 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4450 0 : break;
4451 : }
4452 0 : case GDT_CFloat64:
4453 : {
4454 0 : const double dfReal =
4455 0 : static_cast<double *>(pData)[iOffset * 2];
4456 0 : const double dfImag =
4457 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4458 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4459 0 : continue;
4460 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4461 0 : break;
4462 : }
4463 0 : case GDT_Unknown:
4464 : case GDT_TypeCount:
4465 0 : CPLAssert(false);
4466 : }
4467 :
4468 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4469 0 : sNoDataValues.bGotNoDataValue &&
4470 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4471 0 : continue;
4472 :
4473 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4474 : // finite, the result of the multiplication cannot be NaN
4475 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4476 :
4477 0 : if (dfIndex < 0)
4478 : {
4479 0 : if (bIncludeOutOfRange)
4480 0 : panHistogram[0]++;
4481 : }
4482 0 : else if (dfIndex >= nBuckets)
4483 : {
4484 0 : if (bIncludeOutOfRange)
4485 0 : ++panHistogram[nBuckets - 1];
4486 : }
4487 : else
4488 : {
4489 0 : ++panHistogram[static_cast<int>(dfIndex)];
4490 : }
4491 : }
4492 : }
4493 :
4494 0 : CPLFree(pData);
4495 0 : CPLFree(pabyMaskData);
4496 : }
4497 : else // No arbitrary overviews.
4498 : {
4499 35 : if (!InitBlockInfo())
4500 0 : return CE_Failure;
4501 :
4502 : /* --------------------------------------------------------------------
4503 : */
4504 : /* Figure out the ratio of blocks we will read to get an */
4505 : /* approximate value. */
4506 : /* --------------------------------------------------------------------
4507 : */
4508 :
4509 35 : int nSampleRate = 1;
4510 35 : if (bApproxOK)
4511 : {
4512 8 : nSampleRate = static_cast<int>(std::max(
4513 16 : 1.0,
4514 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4515 : // We want to avoid probing only the first column of blocks for
4516 : // a square shaped raster, because it is not unlikely that it may
4517 : // be padding only (#6378).
4518 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4519 1 : nSampleRate += 1;
4520 : }
4521 :
4522 35 : GByte *pabyMaskData = nullptr;
4523 35 : if (poMaskBand)
4524 : {
4525 : pabyMaskData = static_cast<GByte *>(
4526 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4527 2 : if (!pabyMaskData)
4528 : {
4529 0 : return CE_Failure;
4530 : }
4531 : }
4532 :
4533 : /* --------------------------------------------------------------------
4534 : */
4535 : /* Read the blocks, and add to histogram. */
4536 : /* --------------------------------------------------------------------
4537 : */
4538 35 : for (GIntBig iSampleBlock = 0;
4539 160 : iSampleBlock <
4540 160 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4541 125 : iSampleBlock += nSampleRate)
4542 : {
4543 125 : if (!pfnProgress(
4544 125 : static_cast<double>(iSampleBlock) /
4545 125 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4546 : "Compute Histogram", pProgressData))
4547 : {
4548 0 : CPLFree(pabyMaskData);
4549 0 : return CE_Failure;
4550 : }
4551 :
4552 125 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4553 125 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4554 :
4555 125 : int nXCheck = 0, nYCheck = 0;
4556 125 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4557 :
4558 127 : if (poMaskBand &&
4559 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4560 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4561 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4562 2 : 0, nBlockXSize, nullptr) != CE_None)
4563 : {
4564 0 : CPLFree(pabyMaskData);
4565 0 : return CE_Failure;
4566 : }
4567 :
4568 125 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4569 125 : if (poBlock == nullptr)
4570 : {
4571 0 : CPLFree(pabyMaskData);
4572 0 : return CE_Failure;
4573 : }
4574 :
4575 125 : void *pData = poBlock->GetDataRef();
4576 :
4577 : // this is a special case for a common situation.
4578 125 : if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4579 89 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4580 86 : nXCheck == nBlockXSize && nBuckets == 256)
4581 : {
4582 86 : const GPtrDiff_t nPixels =
4583 86 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4584 86 : GByte *pabyData = static_cast<GByte *>(pData);
4585 :
4586 79640 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4587 : {
4588 79554 : if (pabyMaskData && pabyMaskData[i] == 0)
4589 0 : continue;
4590 79554 : if (!(sNoDataValues.bGotNoDataValue &&
4591 512 : (pabyData[i] ==
4592 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4593 : {
4594 79298 : panHistogram[pabyData[i]]++;
4595 : }
4596 : }
4597 :
4598 86 : poBlock->DropLock();
4599 86 : continue; // To next sample block.
4600 : }
4601 :
4602 : // This isn't the fastest way to do this, but is easier for now.
4603 257 : for (int iY = 0; iY < nYCheck; iY++)
4604 : {
4605 36389 : for (int iX = 0; iX < nXCheck; iX++)
4606 : {
4607 36171 : const GPtrDiff_t iOffset =
4608 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4609 :
4610 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4611 2 : continue;
4612 :
4613 36169 : double dfValue = 0.0;
4614 :
4615 36169 : switch (eDataType)
4616 : {
4617 19716 : case GDT_UInt8:
4618 : {
4619 19716 : if (bSignedByte)
4620 0 : dfValue =
4621 0 : static_cast<signed char *>(pData)[iOffset];
4622 : else
4623 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4624 19716 : break;
4625 : }
4626 1 : case GDT_Int8:
4627 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4628 1 : break;
4629 16384 : case GDT_UInt16:
4630 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4631 16384 : break;
4632 3 : case GDT_Int16:
4633 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4634 3 : break;
4635 0 : case GDT_UInt32:
4636 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4637 0 : break;
4638 60 : case GDT_Int32:
4639 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4640 60 : break;
4641 0 : case GDT_UInt64:
4642 0 : dfValue = static_cast<double>(
4643 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4644 0 : break;
4645 0 : case GDT_Int64:
4646 0 : dfValue = static_cast<double>(
4647 0 : static_cast<GInt64 *>(pData)[iOffset]);
4648 0 : break;
4649 0 : case GDT_Float16:
4650 : {
4651 : using namespace std;
4652 0 : const GFloat16 hfValue =
4653 0 : static_cast<GFloat16 *>(pData)[iOffset];
4654 0 : if (isnan(hfValue) ||
4655 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4656 0 : ARE_REAL_EQUAL(hfValue,
4657 : sNoDataValues.hfNoDataValue)))
4658 0 : continue;
4659 0 : dfValue = hfValue;
4660 0 : break;
4661 : }
4662 3 : case GDT_Float32:
4663 : {
4664 3 : const float fValue =
4665 3 : static_cast<float *>(pData)[iOffset];
4666 6 : if (std::isnan(fValue) ||
4667 6 : (sNoDataValues.bGotFloatNoDataValue &&
4668 3 : ARE_REAL_EQUAL(fValue,
4669 : sNoDataValues.fNoDataValue)))
4670 0 : continue;
4671 3 : dfValue = double(fValue);
4672 3 : break;
4673 : }
4674 2 : case GDT_Float64:
4675 2 : dfValue = static_cast<double *>(pData)[iOffset];
4676 2 : if (std::isnan(dfValue))
4677 0 : continue;
4678 2 : break;
4679 0 : case GDT_CInt16:
4680 : {
4681 0 : double dfReal =
4682 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4683 0 : double dfImag =
4684 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4685 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686 0 : break;
4687 : }
4688 0 : case GDT_CInt32:
4689 : {
4690 0 : double dfReal =
4691 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4692 0 : double dfImag =
4693 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4694 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4695 0 : break;
4696 : }
4697 0 : case GDT_CFloat16:
4698 : {
4699 : double dfReal =
4700 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4701 : double dfImag =
4702 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4703 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4704 0 : continue;
4705 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4706 0 : break;
4707 : }
4708 0 : case GDT_CFloat32:
4709 : {
4710 0 : double dfReal = double(
4711 0 : static_cast<float *>(pData)[iOffset * 2]);
4712 0 : double dfImag = double(
4713 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4714 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4715 0 : continue;
4716 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4717 0 : break;
4718 : }
4719 0 : case GDT_CFloat64:
4720 : {
4721 0 : double dfReal =
4722 0 : static_cast<double *>(pData)[iOffset * 2];
4723 0 : double dfImag =
4724 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4725 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4726 0 : continue;
4727 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4728 0 : break;
4729 : }
4730 0 : case GDT_Unknown:
4731 : case GDT_TypeCount:
4732 0 : CPLAssert(false);
4733 : CPLFree(pabyMaskData);
4734 : return CE_Failure;
4735 : }
4736 :
4737 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4738 72338 : sNoDataValues.bGotNoDataValue &&
4739 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4740 0 : continue;
4741 :
4742 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4743 : // and finite, the result of the multiplication cannot be
4744 : // NaN
4745 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4746 :
4747 36169 : if (dfIndex < 0)
4748 : {
4749 1 : if (bIncludeOutOfRange)
4750 1 : panHistogram[0]++;
4751 : }
4752 36168 : else if (dfIndex >= nBuckets)
4753 : {
4754 7 : if (bIncludeOutOfRange)
4755 4 : ++panHistogram[nBuckets - 1];
4756 : }
4757 : else
4758 : {
4759 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4760 : }
4761 : }
4762 : }
4763 :
4764 39 : poBlock->DropLock();
4765 : }
4766 :
4767 35 : CPLFree(pabyMaskData);
4768 : }
4769 :
4770 35 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4771 :
4772 35 : return CE_None;
4773 : }
4774 :
4775 : /************************************************************************/
4776 : /* GDALGetRasterHistogram() */
4777 : /************************************************************************/
4778 :
4779 : /**
4780 : * \brief Compute raster histogram.
4781 : *
4782 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4783 : * exceeding 2 billion.
4784 : *
4785 : * @see GDALRasterBand::GetHistogram()
4786 : * @see GDALGetRasterHistogramEx()
4787 : */
4788 :
4789 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4790 : double dfMax, int nBuckets,
4791 : int *panHistogram,
4792 : int bIncludeOutOfRange, int bApproxOK,
4793 : GDALProgressFunc pfnProgress,
4794 : void *pProgressData)
4795 :
4796 : {
4797 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4798 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4799 :
4800 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4801 :
4802 : GUIntBig *panHistogramTemp =
4803 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4804 0 : if (panHistogramTemp == nullptr)
4805 : {
4806 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4807 : "Out of memory in GDALGetRasterHistogram().");
4808 0 : return CE_Failure;
4809 : }
4810 :
4811 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4812 : bIncludeOutOfRange, bApproxOK,
4813 0 : pfnProgress, pProgressData);
4814 :
4815 0 : if (eErr == CE_None)
4816 : {
4817 0 : for (int i = 0; i < nBuckets; i++)
4818 : {
4819 0 : if (panHistogramTemp[i] > INT_MAX)
4820 : {
4821 0 : CPLError(CE_Warning, CPLE_AppDefined,
4822 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4823 : " exceeds maximum 32 bit value",
4824 0 : i, panHistogramTemp[i]);
4825 0 : panHistogram[i] = INT_MAX;
4826 : }
4827 : else
4828 : {
4829 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4830 : }
4831 : }
4832 : }
4833 :
4834 0 : CPLFree(panHistogramTemp);
4835 :
4836 0 : return eErr;
4837 : }
4838 :
4839 : /************************************************************************/
4840 : /* GDALGetRasterHistogramEx() */
4841 : /************************************************************************/
4842 :
4843 : /**
4844 : * \brief Compute raster histogram.
4845 : *
4846 : * @see GDALRasterBand::GetHistogram()
4847 : *
4848 : */
4849 :
4850 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4851 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4852 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4853 : GDALProgressFunc pfnProgress, void *pProgressData)
4854 :
4855 : {
4856 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4857 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4858 :
4859 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4860 :
4861 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4862 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4863 26 : pProgressData);
4864 : }
4865 :
4866 : /************************************************************************/
4867 : /* GetDefaultHistogram() */
4868 : /************************************************************************/
4869 :
4870 : /**
4871 : * \brief Fetch default raster histogram.
4872 : *
4873 : * The default method in GDALRasterBand will compute a default histogram. This
4874 : * method is overridden by derived classes (such as GDALPamRasterBand,
4875 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4876 : * stored histogram.
4877 : *
4878 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4879 : * GDALGetDefaultHistogramEx().
4880 : *
4881 : * @param pdfMin pointer to double value that will contain the lower bound of
4882 : * the histogram.
4883 : * @param pdfMax pointer to double value that will contain the upper bound of
4884 : * the histogram.
4885 : * @param pnBuckets pointer to int value that will contain the number of buckets
4886 : * in *ppanHistogram.
4887 : * @param ppanHistogram pointer to array into which the histogram totals are
4888 : * placed. To be freed with VSIFree
4889 : * @param bForce TRUE to force the computation. If FALSE and no default
4890 : * histogram is available, the method will return CE_Warning
4891 : * @param pfnProgress function to report progress to completion.
4892 : * @param pProgressData application data to pass to pfnProgress.
4893 : *
4894 : * @return CE_None on success, CE_Failure if something goes wrong, or
4895 : * CE_Warning if no default histogram is available.
4896 : */
4897 :
4898 27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4899 : int *pnBuckets,
4900 : GUIntBig **ppanHistogram, int bForce,
4901 : GDALProgressFunc pfnProgress,
4902 : void *pProgressData)
4903 :
4904 : {
4905 27 : CPLAssert(nullptr != pnBuckets);
4906 27 : CPLAssert(nullptr != ppanHistogram);
4907 27 : CPLAssert(nullptr != pdfMin);
4908 27 : CPLAssert(nullptr != pdfMax);
4909 :
4910 27 : *pnBuckets = 0;
4911 27 : *ppanHistogram = nullptr;
4912 :
4913 27 : if (!bForce)
4914 5 : return CE_Warning;
4915 :
4916 22 : int nBuckets = 256;
4917 :
4918 22 : bool bSignedByte = false;
4919 22 : if (eDataType == GDT_UInt8)
4920 : {
4921 20 : EnablePixelTypeSignedByteWarning(false);
4922 : const char *pszPixelType =
4923 20 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4924 20 : EnablePixelTypeSignedByteWarning(true);
4925 20 : bSignedByte =
4926 20 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4927 : }
4928 :
4929 22 : if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4930 : {
4931 20 : *pdfMin = -0.5;
4932 20 : *pdfMax = 255.5;
4933 : }
4934 2 : else if (GetRasterDataType() == GDT_Int8)
4935 : {
4936 1 : *pdfMin = -128 - 0.5;
4937 1 : *pdfMax = 127 + 0.5;
4938 : }
4939 : else
4940 : {
4941 :
4942 : const CPLErr eErr =
4943 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4944 1 : if (eErr != CE_None)
4945 0 : return eErr;
4946 1 : if (*pdfMin == *pdfMax)
4947 : {
4948 1 : nBuckets = 1;
4949 1 : *pdfMin -= 0.5;
4950 1 : *pdfMax += 0.5;
4951 : }
4952 : else
4953 : {
4954 0 : const double dfHalfBucket =
4955 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4956 0 : *pdfMin -= dfHalfBucket;
4957 0 : *pdfMax += dfHalfBucket;
4958 : }
4959 : }
4960 :
4961 22 : *ppanHistogram =
4962 22 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4963 22 : if (*ppanHistogram == nullptr)
4964 : {
4965 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4966 : "Out of memory in GetDefaultHistogram().");
4967 0 : return CE_Failure;
4968 : }
4969 :
4970 22 : *pnBuckets = nBuckets;
4971 44 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4972 22 : TRUE, FALSE, pfnProgress, pProgressData);
4973 22 : if (eErr != CE_None)
4974 : {
4975 0 : *pnBuckets = 0;
4976 : }
4977 22 : return eErr;
4978 : }
4979 :
4980 : /************************************************************************/
4981 : /* GDALGetDefaultHistogram() */
4982 : /************************************************************************/
4983 :
4984 : /**
4985 : * \brief Fetch default raster histogram.
4986 : *
4987 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4988 : * exceeding 2 billion.
4989 : *
4990 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4991 : * @see GDALGetRasterHistogramEx()
4992 : */
4993 :
4994 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4995 : double *pdfMin, double *pdfMax,
4996 : int *pnBuckets, int **ppanHistogram,
4997 : int bForce,
4998 : GDALProgressFunc pfnProgress,
4999 : void *pProgressData)
5000 :
5001 : {
5002 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5003 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5004 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5005 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5006 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5007 :
5008 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
5009 0 : GUIntBig *panHistogramTemp = nullptr;
5010 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5011 : &panHistogramTemp, bForce,
5012 0 : pfnProgress, pProgressData);
5013 0 : if (eErr == CE_None)
5014 : {
5015 0 : const int nBuckets = *pnBuckets;
5016 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5017 0 : if (*ppanHistogram == nullptr)
5018 : {
5019 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5020 : "Out of memory in GDALGetDefaultHistogram().");
5021 0 : VSIFree(panHistogramTemp);
5022 0 : return CE_Failure;
5023 : }
5024 :
5025 0 : for (int i = 0; i < nBuckets; ++i)
5026 : {
5027 0 : if (panHistogramTemp[i] > INT_MAX)
5028 : {
5029 0 : CPLError(CE_Warning, CPLE_AppDefined,
5030 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5031 : " exceeds maximum 32 bit value",
5032 0 : i, panHistogramTemp[i]);
5033 0 : (*ppanHistogram)[i] = INT_MAX;
5034 : }
5035 : else
5036 : {
5037 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5038 : }
5039 : }
5040 :
5041 0 : CPLFree(panHistogramTemp);
5042 : }
5043 : else
5044 : {
5045 0 : *ppanHistogram = nullptr;
5046 : }
5047 :
5048 0 : return eErr;
5049 : }
5050 :
5051 : /************************************************************************/
5052 : /* GDALGetDefaultHistogramEx() */
5053 : /************************************************************************/
5054 :
5055 : /**
5056 : * \brief Fetch default raster histogram.
5057 : *
5058 : * @see GDALRasterBand::GetDefaultHistogram()
5059 : *
5060 : */
5061 :
5062 : CPLErr CPL_STDCALL
5063 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5064 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5065 : GDALProgressFunc pfnProgress, void *pProgressData)
5066 :
5067 : {
5068 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5069 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5070 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5071 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5072 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5073 :
5074 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5075 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5076 30 : bForce, pfnProgress, pProgressData);
5077 : }
5078 :
5079 : /************************************************************************/
5080 : /* AdviseRead() */
5081 : /************************************************************************/
5082 :
5083 : /**
5084 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5085 : * \brief Advise driver of upcoming read requests.
5086 : *
5087 : * Some GDAL drivers operate more efficiently if they know in advance what
5088 : * set of upcoming read requests will be made. The AdviseRead() method allows
5089 : * an application to notify the driver of the region of interest,
5090 : * and at what resolution the region will be read.
5091 : *
5092 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5093 : * accelerate access via some drivers.
5094 : *
5095 : * Depending on call paths, drivers might receive several calls to
5096 : * AdviseRead() with the same parameters.
5097 : *
5098 : * @param nXOff The pixel offset to the top left corner of the region
5099 : * of the band to be accessed. This would be zero to start from the left side.
5100 : *
5101 : * @param nYOff The line offset to the top left corner of the region
5102 : * of the band to be accessed. This would be zero to start from the top.
5103 : *
5104 : * @param nXSize The width of the region of the band to be accessed in pixels.
5105 : *
5106 : * @param nYSize The height of the region of the band to be accessed in lines.
5107 : *
5108 : * @param nBufXSize the width of the buffer image into which the desired region
5109 : * is to be read, or from which it is to be written.
5110 : *
5111 : * @param nBufYSize the height of the buffer image into which the desired
5112 : * region is to be read, or from which it is to be written.
5113 : *
5114 : * @param eBufType the type of the pixel values in the pData data buffer. The
5115 : * pixel values will automatically be translated to/from the GDALRasterBand
5116 : * data type as needed.
5117 : *
5118 : * @param papszOptions a list of name=value strings with special control
5119 : * options. Normally this is NULL.
5120 : *
5121 : * @return CE_Failure if the request is invalid and CE_None if it works or
5122 : * is ignored.
5123 : */
5124 :
5125 : /**/
5126 : /**/
5127 :
5128 114272 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5129 : int /*nYSize*/, int /*nBufXSize*/,
5130 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5131 : char ** /*papszOptions*/)
5132 : {
5133 114272 : return CE_None;
5134 : }
5135 :
5136 : /************************************************************************/
5137 : /* GDALRasterAdviseRead() */
5138 : /************************************************************************/
5139 :
5140 : /**
5141 : * \brief Advise driver of upcoming read requests.
5142 : *
5143 : * @see GDALRasterBand::AdviseRead()
5144 : */
5145 :
5146 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5147 : int nYOff, int nXSize, int nYSize,
5148 : int nBufXSize, int nBufYSize,
5149 : GDALDataType eDT,
5150 : CSLConstList papszOptions)
5151 :
5152 : {
5153 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5154 :
5155 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5156 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5157 : nBufYSize, eDT,
5158 2 : const_cast<char **>(papszOptions));
5159 : }
5160 :
5161 : /************************************************************************/
5162 : /* GetStatistics() */
5163 : /************************************************************************/
5164 :
5165 : /**
5166 : * \brief Fetch image statistics.
5167 : *
5168 : * Returns the minimum, maximum, mean and standard deviation of all
5169 : * pixel values in this band. If approximate statistics are sufficient,
5170 : * the bApproxOK flag can be set to true in which case overviews, or a
5171 : * subset of image tiles may be used in computing the statistics.
5172 : *
5173 : * If bForce is FALSE results will only be returned if it can be done
5174 : * quickly (i.e. without scanning the image, typically by using pre-existing
5175 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5176 : * returned efficiently, the method will return CE_Warning but no warning will
5177 : * be issued. This is a non-standard use of the CE_Warning return value
5178 : * to indicate "nothing done".
5179 : *
5180 : * If bForce is TRUE, and results are quickly available without scanning the
5181 : * image, they will be used. If bForce is TRUE and results are not quickly
5182 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5183 : * which will scan the image.
5184 : *
5185 : * To always force recomputation of statistics, use ComputeStatistics() instead
5186 : * of this method.
5187 : *
5188 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5189 : * will generally cache statistics in the .pam file allowing fast fetch
5190 : * after the first request.
5191 : *
5192 : * This method is the same as the C function GDALGetRasterStatistics().
5193 : *
5194 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5195 : * or a subset of all tiles.
5196 : *
5197 : * @param bForce If FALSE statistics will only be returned if it can
5198 : * be done without rescanning the image. If TRUE, statistics computation will
5199 : * be forced if pre-existing values are not quickly available.
5200 : *
5201 : * @param pdfMin Location into which to load image minimum (may be NULL).
5202 : *
5203 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5204 : *
5205 : * @param pdfMean Location into which to load image mean (may be NULL).
5206 : *
5207 : * @param pdfStdDev Location into which to load image standard deviation
5208 : * (may be NULL).
5209 : *
5210 : * @return CE_None on success, CE_Warning if no values returned,
5211 : * CE_Failure if an error occurs.
5212 : */
5213 :
5214 672 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5215 : double *pdfMax, double *pdfMean,
5216 : double *pdfStdDev)
5217 :
5218 : {
5219 : /* -------------------------------------------------------------------- */
5220 : /* Do we already have metadata items for the requested values? */
5221 : /* -------------------------------------------------------------------- */
5222 1344 : if ((pdfMin == nullptr ||
5223 672 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5224 205 : (pdfMax == nullptr ||
5225 205 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5226 1549 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5227 205 : (pdfStdDev == nullptr ||
5228 205 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5229 : {
5230 205 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5231 : {
5232 198 : if (pdfMin != nullptr)
5233 198 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5234 198 : if (pdfMax != nullptr)
5235 198 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5236 198 : if (pdfMean != nullptr)
5237 198 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5238 198 : if (pdfStdDev != nullptr)
5239 198 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5240 :
5241 198 : return CE_None;
5242 : }
5243 : }
5244 :
5245 : /* -------------------------------------------------------------------- */
5246 : /* Does the driver already know the min/max? */
5247 : /* -------------------------------------------------------------------- */
5248 474 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5249 : {
5250 1 : int bSuccessMin = FALSE;
5251 1 : int bSuccessMax = FALSE;
5252 :
5253 1 : const double dfMin = GetMinimum(&bSuccessMin);
5254 1 : const double dfMax = GetMaximum(&bSuccessMax);
5255 :
5256 1 : if (bSuccessMin && bSuccessMax)
5257 : {
5258 0 : if (pdfMin != nullptr)
5259 0 : *pdfMin = dfMin;
5260 0 : if (pdfMax != nullptr)
5261 0 : *pdfMax = dfMax;
5262 0 : return CE_None;
5263 : }
5264 : }
5265 :
5266 : /* -------------------------------------------------------------------- */
5267 : /* Either return without results, or force computation. */
5268 : /* -------------------------------------------------------------------- */
5269 474 : if (!bForce)
5270 191 : return CE_Warning;
5271 : else
5272 283 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5273 283 : GDALDummyProgress, nullptr);
5274 : }
5275 :
5276 : /************************************************************************/
5277 : /* GDALGetRasterStatistics() */
5278 : /************************************************************************/
5279 :
5280 : /**
5281 : * \brief Fetch image statistics.
5282 : *
5283 : * @see GDALRasterBand::GetStatistics()
5284 : */
5285 :
5286 320 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5287 : int bForce, double *pdfMin,
5288 : double *pdfMax, double *pdfMean,
5289 : double *pdfStdDev)
5290 :
5291 : {
5292 320 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5293 :
5294 320 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5295 320 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5296 320 : pdfStdDev);
5297 : }
5298 :
5299 : /************************************************************************/
5300 : /* GDALUInt128 */
5301 : /************************************************************************/
5302 :
5303 : #ifdef HAVE_UINT128_T
5304 : class GDALUInt128
5305 : {
5306 : __uint128_t val;
5307 :
5308 1164 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5309 : {
5310 1164 : }
5311 :
5312 : public:
5313 776 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5314 : {
5315 : // Evaluates to just a single mul on x86_64
5316 776 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5317 : }
5318 :
5319 388 : GDALUInt128 operator-(const GDALUInt128 &other) const
5320 : {
5321 388 : return GDALUInt128(val - other.val);
5322 : }
5323 :
5324 379 : operator double() const
5325 : {
5326 379 : return static_cast<double>(val);
5327 : }
5328 : };
5329 : #else
5330 :
5331 : #if defined(_MSC_VER) && defined(_M_X64)
5332 : #include <intrin.h>
5333 : #endif
5334 :
5335 : class GDALUInt128
5336 : {
5337 : GUIntBig low, high;
5338 :
5339 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5340 : {
5341 : }
5342 :
5343 : public:
5344 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5345 : {
5346 : #if defined(_MSC_VER) && defined(_M_X64)
5347 : GUIntBig highRes;
5348 : GUIntBig lowRes = _umul128(first, second, &highRes);
5349 : return GDALUInt128(lowRes, highRes);
5350 : #else
5351 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5352 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5353 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5354 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5355 : GUIntBig highRes = 0;
5356 : const GUIntBig firstLowSecondHigh =
5357 : static_cast<GUIntBig>(firstLow) * secondHigh;
5358 : const GUIntBig firstHighSecondLow =
5359 : static_cast<GUIntBig>(firstHigh) * secondLow;
5360 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5361 : if (middleTerm < firstLowSecondHigh) // check for overflow
5362 : highRes += static_cast<GUIntBig>(1) << 32;
5363 : const GUIntBig firstLowSecondLow =
5364 : static_cast<GUIntBig>(firstLow) * secondLow;
5365 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5366 : if (lowRes < firstLowSecondLow) // check for overflow
5367 : highRes++;
5368 : highRes +=
5369 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5370 : return GDALUInt128(lowRes, highRes);
5371 : #endif
5372 : }
5373 :
5374 : GDALUInt128 operator-(const GDALUInt128 &other) const
5375 : {
5376 : GUIntBig highRes = high - other.high;
5377 : GUIntBig lowRes = low - other.low;
5378 : if (lowRes > low) // check for underflow
5379 : --highRes;
5380 : return GDALUInt128(lowRes, highRes);
5381 : }
5382 :
5383 : operator double() const
5384 : {
5385 : const double twoPow64 = 18446744073709551616.0;
5386 : return high * twoPow64 + low;
5387 : }
5388 : };
5389 : #endif
5390 :
5391 : /************************************************************************/
5392 : /* ComputeStatisticsInternal() */
5393 : /************************************************************************/
5394 :
5395 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5396 : // not needed.
5397 : #define static_cast_for_coverity_scan static_cast
5398 :
5399 : // The rationale for below optimizations is detailed in statistics.txt
5400 :
5401 : // Use with T = GByte or GUInt16 only !
5402 : template <class T, bool COMPUTE_OTHER_STATS>
5403 : struct ComputeStatisticsInternalGeneric
5404 : {
5405 251 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5406 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5407 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5408 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5409 : {
5410 : static_assert(std::is_same<T, GByte>::value ||
5411 : std::is_same<T, GUInt16>::value,
5412 : "bad type for T");
5413 251 : if (bHasNoData)
5414 : {
5415 : // General case
5416 608 : for (int iY = 0; iY < nYCheck; iY++)
5417 : {
5418 161753 : for (int iX = 0; iX < nXCheck; iX++)
5419 : {
5420 161269 : const GPtrDiff_t iOffset =
5421 161269 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5422 161269 : const GUInt32 nValue = pData[iOffset];
5423 161269 : if (nValue == nNoDataValue)
5424 319 : continue;
5425 160950 : if (nValue < nMin)
5426 34 : nMin = nValue;
5427 160950 : if (nValue > nMax)
5428 71 : nMax = nValue;
5429 : if constexpr (COMPUTE_OTHER_STATS)
5430 : {
5431 159314 : nValidCount++;
5432 159314 : nSum += nValue;
5433 159314 : nSumSquare +=
5434 159314 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5435 159314 : nValue;
5436 : }
5437 : }
5438 : }
5439 : if constexpr (COMPUTE_OTHER_STATS)
5440 : {
5441 40 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5442 : }
5443 : }
5444 145 : else if (nMin == std::numeric_limits<T>::lowest() &&
5445 18 : nMax == std::numeric_limits<T>::max())
5446 : {
5447 : if constexpr (COMPUTE_OTHER_STATS)
5448 : {
5449 : // Optimization when there is no nodata and we know we have already
5450 : // reached the min and max
5451 416 : for (int iY = 0; iY < nYCheck; iY++)
5452 : {
5453 : int iX;
5454 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5455 : {
5456 1600 : const GPtrDiff_t iOffset =
5457 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458 1600 : const GUIntBig nValue = pData[iOffset];
5459 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5460 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5461 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5462 1600 : nSum += nValue;
5463 1600 : nSumSquare += nValue * nValue;
5464 1600 : nSum += nValue2;
5465 1600 : nSumSquare += nValue2 * nValue2;
5466 1600 : nSum += nValue3;
5467 1600 : nSumSquare += nValue3 * nValue3;
5468 1600 : nSum += nValue4;
5469 1600 : nSumSquare += nValue4 * nValue4;
5470 : }
5471 414 : for (; iX < nXCheck; ++iX)
5472 : {
5473 10 : const GPtrDiff_t iOffset =
5474 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5475 10 : const GUIntBig nValue = pData[iOffset];
5476 10 : nSum += nValue;
5477 10 : nSumSquare += nValue * nValue;
5478 : }
5479 : }
5480 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5481 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5482 : }
5483 : }
5484 : else
5485 : {
5486 6021 : for (int iY = 0; iY < nYCheck; iY++)
5487 : {
5488 : int iX;
5489 1270512 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5490 : {
5491 1264612 : const GPtrDiff_t iOffset =
5492 1264612 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493 1264612 : const GUInt32 nValue = pData[iOffset];
5494 1264612 : const GUInt32 nValue2 = pData[iOffset + 1];
5495 1264612 : if (nValue < nValue2)
5496 : {
5497 2325 : if (nValue < nMin)
5498 51 : nMin = nValue;
5499 2325 : if (nValue2 > nMax)
5500 119 : nMax = nValue2;
5501 : }
5502 : else
5503 : {
5504 1262285 : if (nValue2 < nMin)
5505 67 : nMin = nValue2;
5506 1262285 : if (nValue > nMax)
5507 216 : nMax = nValue;
5508 : }
5509 : if constexpr (COMPUTE_OTHER_STATS)
5510 : {
5511 1257560 : nSum += nValue;
5512 1257560 : nSumSquare +=
5513 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5514 1257560 : nValue;
5515 1257560 : nSum += nValue2;
5516 1257560 : nSumSquare +=
5517 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5518 1257560 : nValue2;
5519 : }
5520 : }
5521 5906 : if (iX < nXCheck)
5522 : {
5523 27 : const GPtrDiff_t iOffset =
5524 27 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5525 27 : const GUInt32 nValue = pData[iOffset];
5526 27 : if (nValue < nMin)
5527 19 : nMin = nValue;
5528 27 : if (nValue > nMax)
5529 20 : nMax = nValue;
5530 : if (COMPUTE_OTHER_STATS)
5531 : {
5532 19 : nSum += nValue;
5533 19 : nSumSquare +=
5534 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5535 19 : nValue;
5536 : }
5537 : }
5538 : }
5539 : if constexpr (COMPUTE_OTHER_STATS)
5540 : {
5541 60 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5542 60 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5543 : }
5544 : }
5545 251 : }
5546 : };
5547 :
5548 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5549 : // using 64bit accumulators in internal loops. This also slightly helps in
5550 : // 64bit mode.
5551 : template <bool COMPUTE_OTHER_STATS>
5552 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5553 : {
5554 13767 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5555 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5556 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5557 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5558 : {
5559 13767 : int nOuterLoops = nXCheck / 65536;
5560 13767 : if (nXCheck % 65536)
5561 13767 : nOuterLoops++;
5562 :
5563 13767 : if (bHasNoData)
5564 : {
5565 : // General case
5566 23769 : for (int iY = 0; iY < nYCheck; iY++)
5567 : {
5568 13187 : int iX = 0;
5569 26374 : for (int k = 0; k < nOuterLoops; k++)
5570 : {
5571 13187 : int iMax = iX + 65536;
5572 13187 : if (iMax > nXCheck)
5573 13187 : iMax = nXCheck;
5574 13187 : GUInt32 nSum32bit = 0;
5575 13187 : GUInt32 nSumSquare32bit = 0;
5576 13187 : GUInt32 nValidCount32bit = 0;
5577 13187 : GUInt32 nSampleCount32bit = 0;
5578 20722800 : for (; iX < iMax; iX++)
5579 : {
5580 20709663 : const GPtrDiff_t iOffset =
5581 20709663 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5582 20709663 : const GUInt32 nValue = pData[iOffset];
5583 :
5584 20709663 : nSampleCount32bit++;
5585 20709663 : if (nValue == nNoDataValue)
5586 20353516 : continue;
5587 356092 : if (nValue < nMin)
5588 371 : nMin = nValue;
5589 356092 : if (nValue > nMax)
5590 834 : nMax = nValue;
5591 : if constexpr (COMPUTE_OTHER_STATS)
5592 : {
5593 32347 : nValidCount32bit++;
5594 32347 : nSum32bit += nValue;
5595 32347 : nSumSquare32bit += nValue * nValue;
5596 : }
5597 : }
5598 : if constexpr (COMPUTE_OTHER_STATS)
5599 : {
5600 937 : nSampleCount += nSampleCount32bit;
5601 937 : nValidCount += nValidCount32bit;
5602 937 : nSum += nSum32bit;
5603 937 : nSumSquare += nSumSquare32bit;
5604 : }
5605 : }
5606 : }
5607 : }
5608 3185 : else if (nMin == 0 && nMax == 255)
5609 : {
5610 : if constexpr (COMPUTE_OTHER_STATS)
5611 : {
5612 : // Optimization when there is no nodata and we know we have already
5613 : // reached the min and max
5614 2850 : for (int iY = 0; iY < nYCheck; iY++)
5615 : {
5616 2818 : int iX = 0;
5617 5636 : for (int k = 0; k < nOuterLoops; k++)
5618 : {
5619 2818 : int iMax = iX + 65536;
5620 2818 : if (iMax > nXCheck)
5621 2818 : iMax = nXCheck;
5622 2818 : GUInt32 nSum32bit = 0;
5623 2818 : GUInt32 nSumSquare32bit = 0;
5624 177298 : for (; iX + 3 < iMax; iX += 4)
5625 : {
5626 174480 : const GPtrDiff_t iOffset =
5627 174480 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5628 174480 : const GUInt32 nValue = pData[iOffset];
5629 174480 : const GUInt32 nValue2 = pData[iOffset + 1];
5630 174480 : const GUInt32 nValue3 = pData[iOffset + 2];
5631 174480 : const GUInt32 nValue4 = pData[iOffset + 3];
5632 174480 : nSum32bit += nValue;
5633 174480 : nSumSquare32bit += nValue * nValue;
5634 174480 : nSum32bit += nValue2;
5635 174480 : nSumSquare32bit += nValue2 * nValue2;
5636 174480 : nSum32bit += nValue3;
5637 174480 : nSumSquare32bit += nValue3 * nValue3;
5638 174480 : nSum32bit += nValue4;
5639 174480 : nSumSquare32bit += nValue4 * nValue4;
5640 : }
5641 2818 : nSum += nSum32bit;
5642 2818 : nSumSquare += nSumSquare32bit;
5643 : }
5644 2824 : for (; iX < nXCheck; ++iX)
5645 : {
5646 6 : const GPtrDiff_t iOffset =
5647 6 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5648 6 : const GUIntBig nValue = pData[iOffset];
5649 6 : nSum += nValue;
5650 6 : nSumSquare += nValue * nValue;
5651 : }
5652 : }
5653 32 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5654 32 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5655 32 : }
5656 : }
5657 : else
5658 : {
5659 8510 : for (int iY = 0; iY < nYCheck; iY++)
5660 : {
5661 5357 : int iX = 0;
5662 10714 : for (int k = 0; k < nOuterLoops; k++)
5663 : {
5664 5357 : int iMax = iX + 65536;
5665 5357 : if (iMax > nXCheck)
5666 5357 : iMax = nXCheck;
5667 5357 : GUInt32 nSum32bit = 0;
5668 5357 : GUInt32 nSumSquare32bit = 0;
5669 285241 : for (; iX + 1 < iMax; iX += 2)
5670 : {
5671 279884 : const GPtrDiff_t iOffset =
5672 279884 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673 279884 : const GUInt32 nValue = pData[iOffset];
5674 279884 : const GUInt32 nValue2 = pData[iOffset + 1];
5675 279884 : if (nValue < nValue2)
5676 : {
5677 8111 : if (nValue < nMin)
5678 234 : nMin = nValue;
5679 8111 : if (nValue2 > nMax)
5680 222 : nMax = nValue2;
5681 : }
5682 : else
5683 : {
5684 271773 : if (nValue2 < nMin)
5685 365 : nMin = nValue2;
5686 271773 : if (nValue > nMax)
5687 834 : nMax = nValue;
5688 : }
5689 : if constexpr (COMPUTE_OTHER_STATS)
5690 : {
5691 257546 : nSum32bit += nValue;
5692 257546 : nSumSquare32bit += nValue * nValue;
5693 257546 : nSum32bit += nValue2;
5694 257546 : nSumSquare32bit += nValue2 * nValue2;
5695 : }
5696 : }
5697 : if constexpr (COMPUTE_OTHER_STATS)
5698 : {
5699 2150 : nSum += nSum32bit;
5700 2150 : nSumSquare += nSumSquare32bit;
5701 : }
5702 : }
5703 5357 : if (iX < nXCheck)
5704 : {
5705 1532 : const GPtrDiff_t iOffset =
5706 1532 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5707 1532 : const GUInt32 nValue = pData[iOffset];
5708 1532 : if (nValue < nMin)
5709 117 : nMin = nValue;
5710 1532 : if (nValue > nMax)
5711 101 : nMax = nValue;
5712 : if constexpr (COMPUTE_OTHER_STATS)
5713 : {
5714 321 : nSum += nValue;
5715 321 : nSumSquare +=
5716 321 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5717 321 : nValue;
5718 : }
5719 : }
5720 : }
5721 : if constexpr (COMPUTE_OTHER_STATS)
5722 : {
5723 936 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5724 936 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5725 : }
5726 : }
5727 13767 : }
5728 : };
5729 :
5730 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5731 : {
5732 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5733 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5734 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5735 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5736 : {
5737 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5738 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5739 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5740 : }
5741 : };
5742 :
5743 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5744 : (defined(__GNUC__) || defined(_MSC_VER))
5745 :
5746 : #include "gdal_avx2_emulation.hpp"
5747 :
5748 : #define ZERO256 GDALmm256_setzero_si256()
5749 :
5750 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5751 : static void
5752 21346 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5753 : // assumed to be aligned on 256 bits
5754 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5755 : GUIntBig &nSum, GUIntBig &nSumSquare,
5756 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5757 : {
5758 : // 32-byte alignment may not be enforced by linker, so do it at hand
5759 : GByte
5760 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5761 21346 : GByte *paby32ByteAligned =
5762 : aby32ByteUnaligned +
5763 21346 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5764 21346 : GByte *pabyMin = paby32ByteAligned;
5765 21346 : GByte *pabyMax = paby32ByteAligned + 32;
5766 21346 : GUInt32 *panSum =
5767 : COMPUTE_OTHER_STATS
5768 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5769 : : nullptr;
5770 21346 : GUInt32 *panSumSquare =
5771 : COMPUTE_OTHER_STATS
5772 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5773 : : nullptr;
5774 :
5775 21346 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5776 :
5777 21346 : GPtrDiff_t i = 0;
5778 : // Make sure that sumSquare can fit on uint32
5779 : // * 8 since we can hold 8 sums per vector register
5780 21346 : const int nMaxIterationsPerInnerLoop =
5781 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5782 21346 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5783 21346 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5784 21346 : nOuterLoops++;
5785 :
5786 : GDALm256i ymm_min =
5787 21346 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5788 21346 : GDALm256i ymm_max = ymm_min;
5789 21346 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5790 :
5791 42692 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5792 : {
5793 21346 : const auto iMax =
5794 21346 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5795 :
5796 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5797 21346 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5798 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5799 21346 : ZERO256; // holds 8 uint32 sums
5800 724785 : for (; i + 31 < iMax; i += 32)
5801 : {
5802 703439 : const GDALm256i ymm = GDALmm256_load_si256(
5803 703439 : reinterpret_cast<const GDALm256i *>(pData + i));
5804 : if (COMPUTE_MIN)
5805 : {
5806 243330 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5807 : }
5808 : if (COMPUTE_MAX)
5809 : {
5810 612140 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5811 : }
5812 :
5813 : if constexpr (COMPUTE_OTHER_STATS)
5814 : {
5815 : // Extract even-8bit values
5816 : const GDALm256i ymm_even =
5817 504167 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5818 : // Compute square of those 16 values as 32 bit result
5819 : // and add adjacent pairs
5820 : const GDALm256i ymm_even_square =
5821 504167 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5822 : // Add to the sumsquare accumulator
5823 : ymm_sumsquare =
5824 504167 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5825 :
5826 : // Extract odd-8bit values
5827 504167 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5828 : const GDALm256i ymm_odd_square =
5829 504167 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5830 : ymm_sumsquare =
5831 504167 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5832 :
5833 : // Now compute the sums
5834 504167 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5835 : GDALmm256_sad_epu8(ymm, ZERO256));
5836 : }
5837 : }
5838 :
5839 : if constexpr (COMPUTE_OTHER_STATS)
5840 : {
5841 10677 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5842 : ymm_sum);
5843 10677 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5844 : ymm_sumsquare);
5845 :
5846 10677 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5847 10677 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5848 10677 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5849 10677 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5850 : panSumSquare[7];
5851 : }
5852 : }
5853 :
5854 : if constexpr (COMPUTE_MIN)
5855 : {
5856 8449 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5857 : }
5858 : if constexpr (COMPUTE_MAX)
5859 : {
5860 17334 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5861 : }
5862 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5863 : {
5864 589281 : for (int j = 0; j < 32; j++)
5865 : {
5866 : if constexpr (COMPUTE_MIN)
5867 : {
5868 270368 : if (pabyMin[j] < nMin)
5869 1236 : nMin = pabyMin[j];
5870 : }
5871 : if constexpr (COMPUTE_MAX)
5872 : {
5873 554688 : if (pabyMax[j] > nMax)
5874 1799 : nMax = pabyMax[j];
5875 : }
5876 : }
5877 : }
5878 :
5879 234348 : for (; i < nBlockPixels; i++)
5880 : {
5881 213002 : const GUInt32 nValue = pData[i];
5882 : if constexpr (COMPUTE_MIN)
5883 : {
5884 88326 : if (nValue < nMin)
5885 2 : nMin = nValue;
5886 : }
5887 : if constexpr (COMPUTE_MAX)
5888 : {
5889 210227 : if (nValue > nMax)
5890 1150 : nMax = nValue;
5891 : }
5892 : if constexpr (COMPUTE_OTHER_STATS)
5893 : {
5894 77203 : nSum += nValue;
5895 77203 : nSumSquare +=
5896 77203 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5897 : }
5898 : }
5899 :
5900 : if constexpr (COMPUTE_OTHER_STATS)
5901 : {
5902 10677 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5903 10677 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5904 : }
5905 21346 : }
5906 :
5907 : // SSE2/AVX2 optimization for GByte case
5908 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5909 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5910 : // there are strictly equivalent to 2 parallel SSE2 streams.
5911 : template <bool COMPUTE_OTHER_STATS>
5912 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5913 : {
5914 30282 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5915 : // assumed to be aligned on 256 bits
5916 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5917 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5918 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5919 : GUIntBig &nValidCount)
5920 : {
5921 30282 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5922 30282 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5923 11610 : nMin <= nMax)
5924 : {
5925 : // 32-byte alignment may not be enforced by linker, so do it at hand
5926 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5927 1492 : GByte *paby32ByteAligned =
5928 : aby32ByteUnaligned +
5929 1492 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5930 1492 : GByte *pabyMin = paby32ByteAligned;
5931 1492 : GByte *pabyMax = paby32ByteAligned + 32;
5932 1492 : GUInt32 *panSum =
5933 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5934 1492 : GUInt32 *panSumSquare =
5935 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5936 :
5937 1492 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5938 :
5939 1492 : GPtrDiff_t i = 0;
5940 : // Make sure that sumSquare can fit on uint32
5941 : // * 8 since we can hold 8 sums per vector register
5942 1492 : const int nMaxIterationsPerInnerLoop =
5943 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5944 1492 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5945 1492 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5946 1492 : nOuterLoops++;
5947 :
5948 : const GDALm256i ymm_nodata =
5949 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5950 : // any non noData value in [min,max] would do.
5951 : const GDALm256i ymm_neutral =
5952 1492 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5953 1492 : GDALm256i ymm_min = ymm_neutral;
5954 1492 : GDALm256i ymm_max = ymm_neutral;
5955 : [[maybe_unused]] const auto ymm_mask_8bits =
5956 1492 : GDALmm256_set1_epi16(0xFF);
5957 :
5958 1492 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5959 1492 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5960 1492 : const bool bComputeMinMax =
5961 1492 : nMin > nMinThreshold || nMax < nMaxThreshold;
5962 :
5963 2984 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5964 : {
5965 1492 : const auto iMax =
5966 1492 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5967 :
5968 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5969 1492 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5970 : // holds 8 uint32 sums
5971 1492 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5972 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5973 1492 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5974 1492 : const auto iInit = i;
5975 18982 : for (; i + 31 < iMax; i += 32)
5976 : {
5977 17490 : const GDALm256i ymm = GDALmm256_load_si256(
5978 17490 : reinterpret_cast<const GDALm256i *>(pData + i));
5979 :
5980 : // Check which values are nodata
5981 : const GDALm256i ymm_eq_nodata =
5982 17490 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5983 : if constexpr (COMPUTE_OTHER_STATS)
5984 : {
5985 : // Count how many values are nodata (due to cmpeq
5986 : // putting 255 when condition is met, this will actually
5987 : // be 255 times the number of nodata value, spread in 4
5988 : // 64 bits words). We can use add_epi32 as the counter
5989 : // will not overflow uint32
5990 9148 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5991 : ymm_count_nodata_mul_255,
5992 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5993 : }
5994 : // Replace all nodata values by zero for the purpose of sum
5995 : // and sumquare.
5996 : const GDALm256i ymm_nodata_by_zero =
5997 17490 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5998 17490 : if (bComputeMinMax)
5999 : {
6000 : // Replace all nodata values by a neutral value for the
6001 : // purpose of min and max.
6002 : const GDALm256i ymm_nodata_by_neutral =
6003 8720 : GDALmm256_or_si256(
6004 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
6005 : ymm_nodata_by_zero);
6006 :
6007 : ymm_min =
6008 8720 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
6009 : ymm_max =
6010 8720 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6011 : }
6012 :
6013 : if constexpr (COMPUTE_OTHER_STATS)
6014 : {
6015 : // Extract even-8bit values
6016 9148 : const GDALm256i ymm_even = GDALmm256_and_si256(
6017 : ymm_nodata_by_zero, ymm_mask_8bits);
6018 : // Compute square of those 16 values as 32 bit result
6019 : // and add adjacent pairs
6020 : const GDALm256i ymm_even_square =
6021 9148 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6022 : // Add to the sumsquare accumulator
6023 : ymm_sumsquare =
6024 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6025 :
6026 : // Extract odd-8bit values
6027 : const GDALm256i ymm_odd =
6028 9148 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6029 : const GDALm256i ymm_odd_square =
6030 9148 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6031 : ymm_sumsquare =
6032 9148 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6033 :
6034 : // Now compute the sums
6035 9148 : ymm_sum = GDALmm256_add_epi32(
6036 : ymm_sum,
6037 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6038 : }
6039 : }
6040 :
6041 : if constexpr (COMPUTE_OTHER_STATS)
6042 : {
6043 186 : GUInt32 *panCoutNoDataMul255 = panSum;
6044 186 : GDALmm256_store_si256(
6045 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6046 : ymm_count_nodata_mul_255);
6047 :
6048 186 : nSampleCount += (i - iInit);
6049 :
6050 186 : nValidCount +=
6051 186 : (i - iInit) -
6052 186 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6053 186 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6054 : 255;
6055 :
6056 186 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6057 : ymm_sum);
6058 186 : GDALmm256_store_si256(
6059 : reinterpret_cast<GDALm256i *>(panSumSquare),
6060 : ymm_sumsquare);
6061 186 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6062 186 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6063 186 : panSumSquare[1] + panSumSquare[2] +
6064 186 : panSumSquare[3] + panSumSquare[4] +
6065 186 : panSumSquare[5] + panSumSquare[6] +
6066 : panSumSquare[7];
6067 : }
6068 : }
6069 :
6070 1492 : if (bComputeMinMax)
6071 : {
6072 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6073 : ymm_min);
6074 1430 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6075 : ymm_max);
6076 47190 : for (int j = 0; j < 32; j++)
6077 : {
6078 45760 : if (pabyMin[j] < nMin)
6079 40 : nMin = pabyMin[j];
6080 45760 : if (pabyMax[j] > nMax)
6081 161 : nMax = pabyMax[j];
6082 : }
6083 : }
6084 :
6085 : if constexpr (COMPUTE_OTHER_STATS)
6086 : {
6087 186 : nSampleCount += nBlockPixels - i;
6088 : }
6089 34048 : for (; i < nBlockPixels; i++)
6090 : {
6091 32556 : const GUInt32 nValue = pData[i];
6092 32556 : if (nValue == nNoDataValue)
6093 24923 : continue;
6094 7633 : if (nValue < nMin)
6095 2 : nMin = nValue;
6096 7633 : if (nValue > nMax)
6097 14 : nMax = nValue;
6098 : if constexpr (COMPUTE_OTHER_STATS)
6099 : {
6100 3700 : nValidCount++;
6101 3700 : nSum += nValue;
6102 3700 : nSumSquare +=
6103 3700 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6104 3700 : nValue;
6105 : }
6106 1492 : }
6107 : }
6108 28790 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6109 : {
6110 14990 : if (nMin > 0)
6111 : {
6112 2093 : if (nMax < 255)
6113 : {
6114 : ComputeStatisticsByteNoNodata<true, true,
6115 1570 : COMPUTE_OTHER_STATS>(
6116 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6117 : nSampleCount, nValidCount);
6118 : }
6119 : else
6120 : {
6121 : ComputeStatisticsByteNoNodata<true, false,
6122 523 : COMPUTE_OTHER_STATS>(
6123 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6124 : nSampleCount, nValidCount);
6125 : }
6126 : }
6127 : else
6128 : {
6129 12897 : if (nMax < 255)
6130 : {
6131 : ComputeStatisticsByteNoNodata<false, true,
6132 9408 : COMPUTE_OTHER_STATS>(
6133 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6134 : nSampleCount, nValidCount);
6135 : }
6136 : else
6137 : {
6138 : ComputeStatisticsByteNoNodata<false, false,
6139 3489 : COMPUTE_OTHER_STATS>(
6140 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6141 : nSampleCount, nValidCount);
6142 : }
6143 : }
6144 : }
6145 12506 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6146 33 : (nBlockXSize % 32) == 0)
6147 : {
6148 6389 : for (int iY = 0; iY < nYCheck; iY++)
6149 : {
6150 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6151 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6152 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6153 33 : }
6154 : }
6155 : else
6156 : {
6157 13767 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6158 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6159 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6160 : }
6161 30282 : }
6162 : };
6163 :
6164 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6165 570 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6166 : GUIntBig i)
6167 : {
6168 570 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6169 570 : }
6170 :
6171 : // AVX2/SSE2 optimization for GUInt16 case
6172 : template <bool COMPUTE_OTHER_STATS>
6173 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6174 : {
6175 2095 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6176 : // assumed to be aligned on 128 bits
6177 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6178 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6179 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6180 : GUIntBig &nValidCount)
6181 : {
6182 2095 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6183 2095 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6184 : {
6185 1844 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6186 :
6187 1844 : GPtrDiff_t i = 0;
6188 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6189 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6190 : // Furthermore the shift is also needed to use madd_epi16
6191 1844 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6192 1844 : GDALm256i ymm_min = GDALmm256_load_si256(
6193 1844 : reinterpret_cast<const GDALm256i *>(pData + i));
6194 1844 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6195 1844 : GDALm256i ymm_max = ymm_min;
6196 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6197 1844 : ZERO256; // holds 4 uint64 sums
6198 :
6199 : // Make sure that sum can fit on uint32
6200 : // * 8 since we can hold 8 sums per vector register
6201 1844 : const int nMaxIterationsPerInnerLoop =
6202 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6203 1844 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6204 1844 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6205 1844 : nOuterLoops++;
6206 :
6207 1844 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6208 : [[maybe_unused]] const auto ymm_mask_16bits =
6209 1844 : GDALmm256_set1_epi32(0xFFFF);
6210 : [[maybe_unused]] const auto ymm_mask_32bits =
6211 1844 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6212 :
6213 1844 : GUIntBig nSumThis = 0;
6214 3712 : for (int k = 0; k < nOuterLoops; k++)
6215 : {
6216 1868 : const auto iMax =
6217 1868 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6218 :
6219 : [[maybe_unused]] GDALm256i ymm_sum =
6220 1868 : ZERO256; // holds 8 uint32 sums
6221 1057198 : for (; i + 15 < iMax; i += 16)
6222 : {
6223 1055330 : const GDALm256i ymm = GDALmm256_load_si256(
6224 1055330 : reinterpret_cast<const GDALm256i *>(pData + i));
6225 : const GDALm256i ymm_shifted =
6226 1055330 : GDALmm256_add_epi16(ymm, ymm_m32768);
6227 1055330 : if (bComputeMinMax)
6228 : {
6229 1037292 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6230 1037292 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6231 : }
6232 :
6233 : if constexpr (COMPUTE_OTHER_STATS)
6234 : {
6235 : // Note: the int32 range can overflow for (0-32768)^2 +
6236 : // (0-32768)^2 = 0x80000000, but as we know the result
6237 : // is positive, this is OK as we interpret is a uint32.
6238 : const GDALm256i ymm_square =
6239 188312 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6240 188312 : ymm_sumsquare = GDALmm256_add_epi64(
6241 : ymm_sumsquare,
6242 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6243 188312 : ymm_sumsquare = GDALmm256_add_epi64(
6244 : ymm_sumsquare,
6245 : GDALmm256_srli_epi64(ymm_square, 32));
6246 :
6247 : // Now compute the sums
6248 188312 : ymm_sum = GDALmm256_add_epi32(
6249 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6250 188312 : ymm_sum = GDALmm256_add_epi32(
6251 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6252 : }
6253 : }
6254 :
6255 : if constexpr (COMPUTE_OTHER_STATS)
6256 : {
6257 : GUInt32 anSum[8];
6258 570 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6259 : ymm_sum);
6260 570 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6261 570 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6262 570 : anSum[6] + anSum[7];
6263 : }
6264 : }
6265 :
6266 1844 : if (bComputeMinMax)
6267 : {
6268 : GUInt16 anMin[16];
6269 : GUInt16 anMax[16];
6270 :
6271 : // Unshift the result
6272 1762 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6273 1762 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6274 1762 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6275 : ymm_min);
6276 1762 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6277 : ymm_max);
6278 29954 : for (int j = 0; j < 16; j++)
6279 : {
6280 28192 : if (anMin[j] < nMin)
6281 389 : nMin = anMin[j];
6282 28192 : if (anMax[j] > nMax)
6283 567 : nMax = anMax[j];
6284 : }
6285 : }
6286 :
6287 : if constexpr (COMPUTE_OTHER_STATS)
6288 : {
6289 : GUIntBig anSumSquare[4];
6290 570 : GDALmm256_storeu_si256(
6291 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6292 570 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6293 : anSumSquare[3];
6294 :
6295 : // Unshift the sum of squares
6296 570 : UnshiftSumSquare(nSumSquare, nSumThis,
6297 : static_cast<GUIntBig>(i));
6298 :
6299 570 : nSum += nSumThis;
6300 :
6301 1014 : for (; i < nBlockPixels; i++)
6302 : {
6303 444 : const GUInt32 nValue = pData[i];
6304 444 : if (nValue < nMin)
6305 2 : nMin = nValue;
6306 444 : if (nValue > nMax)
6307 2 : nMax = nValue;
6308 444 : nSum += nValue;
6309 444 : nSumSquare +=
6310 444 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6311 444 : nValue;
6312 : }
6313 :
6314 570 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6315 570 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6316 1844 : }
6317 : }
6318 : else
6319 : {
6320 251 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6321 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6322 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6323 : }
6324 2095 : }
6325 : };
6326 :
6327 : #endif
6328 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6329 : // defined(_MSC_VER))
6330 :
6331 : /************************************************************************/
6332 : /* GetPixelValue() */
6333 : /************************************************************************/
6334 :
6335 15932100 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6336 : const void *pData, GPtrDiff_t iOffset,
6337 : const GDALNoDataValues &sNoDataValues,
6338 : bool &bValid)
6339 : {
6340 15932100 : bValid = true;
6341 15932100 : double dfValue = 0;
6342 15932100 : switch (eDataType)
6343 : {
6344 1400770 : case GDT_UInt8:
6345 : {
6346 1400770 : if (bSignedByte)
6347 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6348 : else
6349 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6350 1400770 : break;
6351 : }
6352 617 : case GDT_Int8:
6353 617 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6354 617 : break;
6355 200608 : case GDT_UInt16:
6356 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6357 200608 : break;
6358 114437 : case GDT_Int16:
6359 114437 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6360 114437 : break;
6361 10454 : case GDT_UInt32:
6362 10454 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6363 10454 : break;
6364 140108 : case GDT_Int32:
6365 140108 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6366 140108 : break;
6367 36 : case GDT_UInt64:
6368 36 : dfValue = static_cast<double>(
6369 36 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6370 36 : break;
6371 3244 : case GDT_Int64:
6372 3244 : dfValue = static_cast<double>(
6373 3244 : static_cast<const std::int64_t *>(pData)[iOffset]);
6374 3244 : break;
6375 8 : case GDT_Float16:
6376 : {
6377 : using namespace std;
6378 8 : const GFloat16 hfValue =
6379 8 : static_cast<const GFloat16 *>(pData)[iOffset];
6380 14 : if (isnan(hfValue) ||
6381 6 : (sNoDataValues.bGotFloat16NoDataValue &&
6382 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6383 : {
6384 2 : bValid = false;
6385 2 : return 0.0;
6386 : }
6387 6 : dfValue = hfValue;
6388 6 : return dfValue;
6389 : }
6390 13643900 : case GDT_Float32:
6391 : {
6392 13643900 : const float fValue = static_cast<const float *>(pData)[iOffset];
6393 27260800 : if (std::isnan(fValue) ||
6394 26885800 : (sNoDataValues.bGotFloatNoDataValue &&
6395 13268800 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6396 : {
6397 26879 : bValid = false;
6398 26879 : return 0.0;
6399 : }
6400 13617000 : dfValue = double(fValue);
6401 13617000 : return dfValue;
6402 : }
6403 400868 : case GDT_Float64:
6404 400868 : dfValue = static_cast<const double *>(pData)[iOffset];
6405 400868 : if (std::isnan(dfValue))
6406 : {
6407 6 : bValid = false;
6408 6 : return 0.0;
6409 : }
6410 400862 : break;
6411 2692 : case GDT_CInt16:
6412 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6413 2692 : break;
6414 2692 : case GDT_CInt32:
6415 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6416 2692 : break;
6417 0 : case GDT_CFloat16:
6418 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6419 0 : if (std::isnan(dfValue))
6420 : {
6421 0 : bValid = false;
6422 0 : return 0.0;
6423 : }
6424 0 : break;
6425 5812 : case GDT_CFloat32:
6426 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6427 5812 : if (std::isnan(dfValue))
6428 : {
6429 0 : bValid = false;
6430 0 : return 0.0;
6431 : }
6432 5812 : break;
6433 5892 : case GDT_CFloat64:
6434 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6435 5892 : if (std::isnan(dfValue))
6436 : {
6437 0 : bValid = false;
6438 0 : return 0.0;
6439 : }
6440 5892 : break;
6441 0 : case GDT_Unknown:
6442 : case GDT_TypeCount:
6443 0 : CPLAssert(false);
6444 : break;
6445 : }
6446 :
6447 2543270 : if (sNoDataValues.bGotNoDataValue &&
6448 255049 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6449 : {
6450 4203 : bValid = false;
6451 4203 : return 0.0;
6452 : }
6453 2284020 : return dfValue;
6454 : }
6455 :
6456 : /************************************************************************/
6457 : /* SetValidPercent() */
6458 : /************************************************************************/
6459 :
6460 : //! @cond Doxygen_Suppress
6461 : /**
6462 : * \brief Set percentage of valid (not nodata) pixels.
6463 : *
6464 : * Stores the percentage of valid pixels in the metadata item
6465 : * STATISTICS_VALID_PERCENT
6466 : *
6467 : * @param nSampleCount Number of sampled pixels.
6468 : *
6469 : * @param nValidCount Number of valid pixels.
6470 : */
6471 :
6472 539 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6473 : GUIntBig nValidCount)
6474 : {
6475 539 : if (nValidCount == 0)
6476 : {
6477 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6478 : }
6479 527 : else if (nValidCount == nSampleCount)
6480 : {
6481 469 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6482 : }
6483 : else /* nValidCount < nSampleCount */
6484 : {
6485 58 : char szValue[128] = {0};
6486 :
6487 : /* percentage is only an indicator: limit precision */
6488 58 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6489 58 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6490 :
6491 58 : if (EQUAL(szValue, "100"))
6492 : {
6493 : /* don't set 100 percent valid
6494 : * because some of the sampled pixels were nodata */
6495 4 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6496 : }
6497 : else
6498 : {
6499 54 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6500 : }
6501 : }
6502 539 : }
6503 :
6504 : //! @endcond
6505 :
6506 : #if (defined(__x86_64__) || defined(_M_X64))
6507 :
6508 : #ifdef __AVX2__
6509 :
6510 : #define set1_ps _mm256_set1_ps
6511 : #define loadu_ps _mm256_loadu_ps
6512 : #define or_ps _mm256_or_ps
6513 : #define min_ps _mm256_min_ps
6514 : #define max_ps _mm256_max_ps
6515 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6516 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6517 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6518 : #define movemask_ps _mm256_movemask_ps
6519 : #define storeu_ps _mm256_storeu_ps
6520 : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
6521 : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
6522 :
6523 : #define unpacklo_ps _mm256_unpacklo_ps
6524 : #define castps_pd _mm256_castps_pd
6525 :
6526 : inline __m256 dup_hi_ps(__m256 x)
6527 : {
6528 : const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
6529 : return _mm256_permutevar8x32_ps(x, idx);
6530 : }
6531 :
6532 : #define setzero_pd _mm256_setzero_pd
6533 : #define set1_pd _mm256_set1_pd
6534 : #define loadu_pd _mm256_loadu_pd
6535 : #define or_pd _mm256_or_pd
6536 : #define min_pd _mm256_min_pd
6537 : #define max_pd _mm256_max_pd
6538 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6539 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6540 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6541 : #define movemask_pd _mm256_movemask_pd
6542 : #define add_pd _mm256_add_pd
6543 : #define sub_pd _mm256_sub_pd
6544 : #define mul_pd _mm256_mul_pd
6545 : #define div_pd _mm256_div_pd
6546 : #define storeu_pd _mm256_storeu_pd
6547 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6548 : #define blendv_pd _mm256_blendv_pd
6549 : #ifdef __FMA__
6550 : #define fmadd_pd _mm256_fmadd_pd
6551 : #else
6552 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6553 : #endif
6554 :
6555 : #else
6556 :
6557 : #define set1_ps _mm_set1_ps
6558 : #define loadu_ps _mm_loadu_ps
6559 : #define or_ps _mm_or_ps
6560 : #define min_ps _mm_min_ps
6561 : #define max_ps _mm_max_ps
6562 : #define cmpeq_ps _mm_cmpeq_ps
6563 : #define cmpneq_ps _mm_cmpneq_ps
6564 : #define cmpunord_ps _mm_cmpunord_ps
6565 : #define movemask_ps _mm_movemask_ps
6566 : #define storeu_ps _mm_storeu_ps
6567 : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
6568 : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
6569 : #define unpacklo_ps _mm_unpacklo_ps
6570 : #define castps_pd _mm_castps_pd
6571 : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
6572 :
6573 : #define setzero_pd _mm_setzero_pd
6574 : #define set1_pd _mm_set1_pd
6575 : #define loadu_pd _mm_loadu_pd
6576 : #define or_pd _mm_or_pd
6577 : #define min_pd _mm_min_pd
6578 : #define max_pd _mm_max_pd
6579 : #define cmpeq_pd _mm_cmpeq_pd
6580 : #define cmpneq_pd _mm_cmpneq_pd
6581 : #define cmpunord_pd _mm_cmpunord_pd
6582 : #define movemask_pd _mm_movemask_pd
6583 : #define add_pd _mm_add_pd
6584 : #define sub_pd _mm_sub_pd
6585 : #define mul_pd _mm_mul_pd
6586 : #define div_pd _mm_div_pd
6587 : #define storeu_pd _mm_storeu_pd
6588 : #define cvtsd_f64 _mm_cvtsd_f64
6589 : #ifdef __FMA__
6590 : #define fmadd_pd _mm_fmadd_pd
6591 : #else
6592 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6593 : #endif
6594 :
6595 4245550 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6596 : {
6597 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6598 : return _mm_blendv_pd(a, b, mask);
6599 : #else
6600 12736700 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6601 : #endif
6602 : }
6603 : #endif
6604 :
6605 : #define dup_lo_ps(x) unpacklo_ps((x), (x))
6606 :
6607 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6608 : #if defined(__GNUC__)
6609 : __attribute__((noinline))
6610 : #endif
6611 : static int
6612 5889 : ComputeStatisticsFloat32_SSE2(const float *pafData,
6613 : [[maybe_unused]] float fNoDataValue, int iX,
6614 : int nCount, float &fMin, float &fMax,
6615 : double &dfBlockMean, double &dfBlockM2,
6616 : double &dfBlockValidCount)
6617 : {
6618 5889 : auto vValidCount = setzero_pd();
6619 5889 : const auto vOne = set1_pd(1);
6620 5889 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6621 :
6622 5889 : auto vMin = set1_ps(fMin);
6623 11778 : auto vMax = set1_ps(fMax);
6624 :
6625 5889 : auto vMean_lo = setzero_pd();
6626 5889 : auto vM2_lo = setzero_pd();
6627 :
6628 5889 : auto vMean_hi = setzero_pd();
6629 5889 : auto vM2_hi = setzero_pd();
6630 :
6631 5889 : constexpr int VALS_PER_LOOP =
6632 : static_cast<int>(sizeof(vOne) / sizeof(float));
6633 1242004 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6634 : {
6635 2472234 : const auto vValues = loadu_ps(pafData + iX);
6636 :
6637 1236117 : auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
6638 : if constexpr (HAS_NODATA)
6639 : {
6640 0 : isNaNOrNoData = or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
6641 : }
6642 1236117 : if (movemask_ps(isNaNOrNoData))
6643 : {
6644 1 : break;
6645 : }
6646 :
6647 1236116 : vMin = min_ps(vMin, vValues);
6648 1236116 : vMax = max_ps(vMax, vValues);
6649 :
6650 1236116 : const auto vValues_lo = cvtps_lo_pd(vValues);
6651 2472232 : const auto vValues_hi = cvtps_hi_pd(vValues);
6652 1236116 : [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
6653 :
6654 1236116 : vValidCount = add_pd(vValidCount, vOne);
6655 1236116 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6656 :
6657 1236116 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6658 2271276 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6659 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6660 : {
6661 : const auto vMinNotSameAsMax_lo =
6662 1035160 : castps_pd(dup_lo_ps(vMinNotSameAsMax));
6663 1035160 : vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6664 : const auto vNewM2_lo =
6665 2070320 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6666 1035160 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6667 : }
6668 : else
6669 : {
6670 200956 : vMean_lo = vNewMean_lo;
6671 602868 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6672 : }
6673 :
6674 1236116 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6675 2271276 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6676 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6677 : {
6678 : const auto vMinNotSameAsMax_hi =
6679 1035160 : castps_pd(dup_hi_ps(vMinNotSameAsMax));
6680 1035160 : vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6681 : const auto vNewM2_hi =
6682 2070320 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6683 1035160 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6684 : }
6685 : else
6686 : {
6687 200956 : vMean_hi = vNewMean_hi;
6688 602868 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6689 : }
6690 : }
6691 5889 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6692 5889 : if (dfValidVectorCount > 0)
6693 : {
6694 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
6695 : storeu_ps(afMin, vMin);
6696 : storeu_ps(afMax, vMax);
6697 28155 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6698 : {
6699 22524 : fMin = std::min(fMin, afMin[i]);
6700 22524 : fMax = std::max(fMax, afMax[i]);
6701 : }
6702 :
6703 : double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6704 : storeu_pd(adfMean, vMean_lo);
6705 : storeu_pd(adfM2, vM2_lo);
6706 5631 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6707 5631 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6708 28155 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6709 : {
6710 22524 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6711 22524 : dfBlockM2 += adfM2[i];
6712 22524 : if (adfMean[i] != dfBlockMean)
6713 : {
6714 12932 : const double dfDelta = adfMean[i] - dfBlockMean;
6715 12932 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6716 12932 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6717 12932 : dfValidVectorCount / dfNewValidCount;
6718 : }
6719 22524 : dfBlockValidCount = dfNewValidCount;
6720 : }
6721 : }
6722 :
6723 5889 : return iX;
6724 : }
6725 :
6726 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6727 : #if defined(__GNUC__)
6728 : __attribute__((noinline))
6729 : #endif
6730 : static int
6731 2351 : ComputeStatisticsFloat64_SSE2(const double *padfData,
6732 : [[maybe_unused]] double dfNoDataValue, int iX,
6733 : int nCount, double &dfMin, double &dfMax,
6734 : double &dfBlockMean, double &dfBlockM2,
6735 : double &dfBlockValidCount)
6736 : {
6737 2351 : auto vValidCount = setzero_pd();
6738 2351 : const auto vOne = set1_pd(1);
6739 2351 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6740 :
6741 2351 : auto vMin_lo = set1_pd(dfMin);
6742 4702 : auto vMax_lo = set1_pd(dfMax);
6743 2351 : auto vMean_lo = setzero_pd();
6744 2351 : auto vM2_lo = setzero_pd();
6745 :
6746 2351 : auto vMin_hi = vMin_lo;
6747 2351 : auto vMax_hi = vMax_lo;
6748 2351 : auto vMean_hi = setzero_pd();
6749 2351 : auto vM2_hi = setzero_pd();
6750 :
6751 2351 : constexpr int VALS_PER_LOOP =
6752 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6753 107183 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6754 : {
6755 104875 : const auto vValues_lo = loadu_pd(padfData + iX);
6756 209750 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6757 : // Check if there's at least one NaN in both vectors
6758 104875 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6759 : if constexpr (HAS_NODATA)
6760 : {
6761 : isNaNOrNoData =
6762 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6763 : cmpeq_pd(vValues_hi, vNoData)));
6764 : }
6765 104875 : if (movemask_pd(isNaNOrNoData))
6766 : {
6767 43 : break;
6768 : }
6769 :
6770 104832 : vValidCount = add_pd(vValidCount, vOne);
6771 104832 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6772 :
6773 104832 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6774 104832 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6775 104832 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6776 131060 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6777 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6778 : {
6779 26228 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6780 26228 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6781 : const auto vNewM2_lo =
6782 52456 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6783 26228 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6784 : }
6785 : else
6786 : {
6787 78604 : vMean_lo = vNewMean_lo;
6788 235812 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6789 : }
6790 :
6791 104832 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6792 104832 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6793 104832 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6794 131060 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6795 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6796 : {
6797 26228 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6798 26228 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6799 : const auto vNewM2_hi =
6800 52456 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6801 26228 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6802 : }
6803 : else
6804 : {
6805 78604 : vMean_hi = vNewMean_hi;
6806 235812 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6807 : }
6808 : }
6809 2351 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6810 2351 : if (dfValidVectorCount > 0)
6811 : {
6812 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6813 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6814 : storeu_pd(adfMin, vMin_lo);
6815 : storeu_pd(adfMax, vMax_lo);
6816 : storeu_pd(adfMean, vMean_lo);
6817 : storeu_pd(adfM2, vM2_lo);
6818 1801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6819 1801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6820 1801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6821 1801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6822 :
6823 9005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6824 : {
6825 7204 : dfMin = std::min(dfMin, adfMin[i]);
6826 7204 : dfMax = std::max(dfMax, adfMax[i]);
6827 7204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6828 7204 : dfBlockM2 += adfM2[i];
6829 7204 : if (adfMean[i] != dfBlockMean)
6830 : {
6831 5871 : const double dfDelta = adfMean[i] - dfBlockMean;
6832 5871 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6833 5871 : dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
6834 5871 : dfValidVectorCount / dfNewValidCount;
6835 : }
6836 7204 : dfBlockValidCount = dfNewValidCount;
6837 : }
6838 : }
6839 :
6840 2351 : return iX;
6841 : }
6842 :
6843 : #endif
6844 :
6845 : /************************************************************************/
6846 : /* ComputeStatistics() */
6847 : /************************************************************************/
6848 :
6849 : /**
6850 : * \brief Compute image statistics.
6851 : *
6852 : * Returns the minimum, maximum, mean and standard deviation of all
6853 : * pixel values in this band. If approximate statistics are sufficient,
6854 : * the bApproxOK flag can be set to true in which case overviews, or a
6855 : * subset of image tiles may be used in computing the statistics.
6856 : *
6857 : * Once computed, the statistics will generally be "set" back on the
6858 : * raster band using SetStatistics().
6859 : *
6860 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6861 : *
6862 : * This method is the same as the C function GDALComputeRasterStatistics().
6863 : *
6864 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6865 : * or a subset of all tiles.
6866 : *
6867 : * @param pdfMin Location into which to load image minimum (may be NULL).
6868 : *
6869 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6870 : *
6871 : * @param pdfMean Location into which to load image mean (may be NULL).
6872 : *
6873 : * @param pdfStdDev Location into which to load image standard deviation
6874 : * (may be NULL).
6875 : *
6876 : * @param pfnProgress a function to call to report progress, or NULL.
6877 : *
6878 : * @param pProgressData application data to pass to the progress function.
6879 : *
6880 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6881 : * is terminated by the user.
6882 : */
6883 :
6884 517 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6885 : double *pdfMax, double *pdfMean,
6886 : double *pdfStdDev,
6887 : GDALProgressFunc pfnProgress,
6888 : void *pProgressData)
6889 :
6890 : {
6891 517 : if (pfnProgress == nullptr)
6892 187 : pfnProgress = GDALDummyProgress;
6893 :
6894 : /* -------------------------------------------------------------------- */
6895 : /* If we have overview bands, use them for statistics. */
6896 : /* -------------------------------------------------------------------- */
6897 517 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6898 : {
6899 : GDALRasterBand *poBand =
6900 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6901 :
6902 3 : if (poBand != this)
6903 : {
6904 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6905 : pdfMean, pdfStdDev,
6906 3 : pfnProgress, pProgressData);
6907 3 : if (eErr == CE_None)
6908 : {
6909 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6910 : {
6911 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6912 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6913 : }
6914 :
6915 : /* transfer metadata from overview band to this */
6916 : const char *pszPercentValid =
6917 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6918 :
6919 3 : if (pszPercentValid != nullptr)
6920 : {
6921 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6922 3 : pszPercentValid);
6923 : }
6924 : }
6925 3 : return eErr;
6926 : }
6927 : }
6928 :
6929 514 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6930 : {
6931 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6932 0 : return CE_Failure;
6933 : }
6934 :
6935 : /* -------------------------------------------------------------------- */
6936 : /* Read actual data and compute statistics. */
6937 : /* -------------------------------------------------------------------- */
6938 : // Using Welford algorithm:
6939 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6940 : // to compute standard deviation in a more numerically robust way than
6941 : // the difference of the sum of square values with the square of the sum.
6942 : // dfMean and dfM2 are updated at each sample.
6943 : // dfM2 is the sum of square of differences to the current mean.
6944 514 : double dfMin = std::numeric_limits<double>::infinity();
6945 514 : double dfMax = -std::numeric_limits<double>::infinity();
6946 514 : double dfMean = 0.0;
6947 514 : double dfM2 = 0.0;
6948 :
6949 : GDALRasterIOExtraArg sExtraArg;
6950 514 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6951 :
6952 514 : GDALNoDataValues sNoDataValues(this, eDataType);
6953 514 : GDALRasterBand *poMaskBand = nullptr;
6954 514 : if (!sNoDataValues.bGotNoDataValue)
6955 : {
6956 481 : const int l_nMaskFlags = GetMaskFlags();
6957 527 : if (l_nMaskFlags != GMF_ALL_VALID &&
6958 46 : GetColorInterpretation() != GCI_AlphaBand)
6959 : {
6960 46 : poMaskBand = GetMaskBand();
6961 : }
6962 : }
6963 :
6964 514 : bool bSignedByte = false;
6965 514 : if (eDataType == GDT_UInt8)
6966 : {
6967 213 : EnablePixelTypeSignedByteWarning(false);
6968 : const char *pszPixelType =
6969 213 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6970 213 : EnablePixelTypeSignedByteWarning(true);
6971 213 : bSignedByte =
6972 213 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6973 : }
6974 :
6975 514 : GUIntBig nSampleCount = 0;
6976 514 : GUIntBig nValidCount = 0;
6977 :
6978 514 : if (bApproxOK && HasArbitraryOverviews())
6979 : {
6980 : /* --------------------------------------------------------------------
6981 : */
6982 : /* Figure out how much the image should be reduced to get an */
6983 : /* approximate value. */
6984 : /* --------------------------------------------------------------------
6985 : */
6986 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6987 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6988 :
6989 0 : int nXReduced = nRasterXSize;
6990 0 : int nYReduced = nRasterYSize;
6991 0 : if (dfReduction > 1.0)
6992 : {
6993 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6994 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6995 :
6996 : // Catch the case of huge resizing ratios here
6997 0 : if (nXReduced == 0)
6998 0 : nXReduced = 1;
6999 0 : if (nYReduced == 0)
7000 0 : nYReduced = 1;
7001 : }
7002 :
7003 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7004 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7005 :
7006 : const CPLErr eErr =
7007 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7008 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7009 0 : if (eErr != CE_None)
7010 : {
7011 0 : CPLFree(pData);
7012 0 : return eErr;
7013 : }
7014 :
7015 0 : GByte *pabyMaskData = nullptr;
7016 0 : if (poMaskBand)
7017 : {
7018 : pabyMaskData =
7019 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7020 0 : if (!pabyMaskData)
7021 : {
7022 0 : CPLFree(pData);
7023 0 : return CE_Failure;
7024 : }
7025 :
7026 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7027 : pabyMaskData, nXReduced, nYReduced,
7028 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
7029 : {
7030 0 : CPLFree(pData);
7031 0 : CPLFree(pabyMaskData);
7032 0 : return CE_Failure;
7033 : }
7034 : }
7035 :
7036 : /* this isn't the fastest way to do this, but is easier for now */
7037 0 : for (int iY = 0; iY < nYReduced; iY++)
7038 : {
7039 0 : for (int iX = 0; iX < nXReduced; iX++)
7040 : {
7041 0 : const int iOffset = iX + iY * nXReduced;
7042 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7043 0 : continue;
7044 :
7045 0 : bool bValid = true;
7046 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7047 0 : iOffset, sNoDataValues, bValid);
7048 0 : if (!bValid)
7049 0 : continue;
7050 :
7051 0 : dfMin = std::min(dfMin, dfValue);
7052 0 : dfMax = std::max(dfMax, dfValue);
7053 :
7054 0 : nValidCount++;
7055 0 : if (dfMin == dfMax)
7056 : {
7057 0 : if (nValidCount == 1)
7058 0 : dfMean = dfMin;
7059 : }
7060 : else
7061 : {
7062 0 : const double dfDelta = dfValue - dfMean;
7063 0 : dfMean += dfDelta / nValidCount;
7064 0 : dfM2 += dfDelta * (dfValue - dfMean);
7065 : }
7066 : }
7067 : }
7068 :
7069 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7070 :
7071 0 : CPLFree(pData);
7072 0 : CPLFree(pabyMaskData);
7073 : }
7074 :
7075 : else // No arbitrary overviews.
7076 : {
7077 514 : if (!InitBlockInfo())
7078 243 : return CE_Failure;
7079 :
7080 : /* --------------------------------------------------------------------
7081 : */
7082 : /* Figure out the ratio of blocks we will read to get an */
7083 : /* approximate value. */
7084 : /* --------------------------------------------------------------------
7085 : */
7086 514 : int nSampleRate = 1;
7087 514 : if (bApproxOK)
7088 : {
7089 43 : nSampleRate = static_cast<int>(std::max(
7090 86 : 1.0,
7091 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7092 : // We want to avoid probing only the first column of blocks for
7093 : // a square shaped raster, because it is not unlikely that it may
7094 : // be padding only (#6378)
7095 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7096 1 : nSampleRate += 1;
7097 : }
7098 514 : if (nSampleRate == 1)
7099 480 : bApproxOK = false;
7100 :
7101 : // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7102 : // for each block, and possibly for the whole raster.
7103 514 : if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
7104 272 : eDataType == GDT_UInt16))
7105 : {
7106 : // We can do integer computation on the whole raster in the Byte case
7107 : // only if the number of pixels explored is lower than
7108 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7109 : // Should be 99.99999% of cases.
7110 : // For GUInt16, this limits to raster of 4 giga pixels
7111 :
7112 : const bool bIntegerStats =
7113 439 : ((eDataType == GDT_UInt8 &&
7114 196 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7115 196 : nSampleRate <
7116 196 : GUINTBIG_MAX / (255U * 255U) /
7117 196 : (static_cast<GUInt64>(nBlockXSize) *
7118 196 : static_cast<GUInt64>(nBlockYSize))) ||
7119 47 : (eDataType == GDT_UInt16 &&
7120 47 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7121 47 : nSampleRate <
7122 47 : GUINTBIG_MAX / (65535U * 65535U) /
7123 47 : (static_cast<GUInt64>(nBlockXSize) *
7124 533 : static_cast<GUInt64>(nBlockYSize)))) &&
7125 : // Can be set to NO for easier debugging of the !bIntegerStats
7126 : // case which requires huge rasters to trigger
7127 243 : CPLTestBool(
7128 243 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7129 :
7130 243 : const GUInt32 nMaxValueType =
7131 243 : (eDataType == GDT_UInt8) ? 255 : 65535;
7132 243 : GUInt32 nMin = nMaxValueType;
7133 243 : GUInt32 nMax = 0;
7134 243 : GUIntBig nSum = 0;
7135 243 : GUIntBig nSumSquare = 0;
7136 : // If no valid nodata, map to invalid value (256 for Byte)
7137 243 : const GUInt32 nNoDataValue =
7138 270 : (sNoDataValues.bGotNoDataValue &&
7139 27 : sNoDataValues.dfNoDataValue >= 0 &&
7140 27 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7141 27 : fabs(sNoDataValues.dfNoDataValue -
7142 27 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7143 : 1e-10)) < 1e-10)
7144 270 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7145 : : nMaxValueType + 1;
7146 :
7147 243 : for (GIntBig iSampleBlock = 0;
7148 13082 : iSampleBlock <
7149 13082 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7150 12839 : iSampleBlock += nSampleRate)
7151 : {
7152 12839 : const int iYBlock =
7153 12839 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7154 12839 : const int iXBlock =
7155 12839 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7156 :
7157 : GDALRasterBlock *const poBlock =
7158 12839 : GetLockedBlockRef(iXBlock, iYBlock);
7159 12839 : if (poBlock == nullptr)
7160 0 : return CE_Failure;
7161 :
7162 12839 : void *const pData = poBlock->GetDataRef();
7163 :
7164 12839 : int nXCheck = 0, nYCheck = 0;
7165 12839 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7166 :
7167 12839 : GUIntBig nBlockSum = 0;
7168 12839 : GUIntBig nBlockSumSquare = 0;
7169 12839 : GUIntBig nBlockSampleCount = 0;
7170 12839 : GUIntBig nBlockValidCount = 0;
7171 12839 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7172 12839 : GUIntBig &nBlockSumSquareRef =
7173 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7174 12839 : GUIntBig &nBlockSampleCountRef =
7175 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7176 12839 : GUIntBig &nBlockValidCountRef =
7177 : bIntegerStats ? nValidCount : nBlockValidCount;
7178 :
7179 12839 : if (eDataType == GDT_UInt8)
7180 : {
7181 : ComputeStatisticsInternal<
7182 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7183 12157 : f(nXCheck, nBlockXSize, nYCheck,
7184 : static_cast<const GByte *>(pData),
7185 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7186 : nMax, nBlockSumRef, nBlockSumSquareRef,
7187 : nBlockSampleCountRef, nBlockValidCountRef);
7188 : }
7189 : else
7190 : {
7191 : ComputeStatisticsInternal<
7192 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7193 682 : f(nXCheck, nBlockXSize, nYCheck,
7194 : static_cast<const GUInt16 *>(pData),
7195 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7196 : nMax, nBlockSumRef, nBlockSumSquareRef,
7197 : nBlockSampleCountRef, nBlockValidCountRef);
7198 : }
7199 :
7200 12839 : poBlock->DropLock();
7201 :
7202 12839 : if (!bIntegerStats)
7203 : {
7204 169 : nSampleCount += nBlockSampleCount;
7205 169 : if (nBlockValidCount)
7206 : {
7207 : // Update the global mean and M2 (the difference of the
7208 : // square to the mean) from the values of the block
7209 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7210 169 : const double dfBlockValidCount =
7211 169 : static_cast<double>(nBlockValidCount);
7212 169 : const double dfBlockMean =
7213 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7214 : const double dfBlockM2 =
7215 169 : static_cast<double>(
7216 169 : GDALUInt128::Mul(nBlockSumSquare,
7217 169 : nBlockValidCount) -
7218 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7219 169 : dfBlockValidCount;
7220 169 : const double dfDelta = dfBlockMean - dfMean;
7221 169 : const auto nNewValidCount =
7222 169 : nValidCount + nBlockValidCount;
7223 169 : const double dfNewValidCount =
7224 : static_cast<double>(nNewValidCount);
7225 169 : dfMean +=
7226 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7227 169 : dfM2 +=
7228 169 : dfBlockM2 + dfDelta * dfDelta *
7229 169 : static_cast<double>(nValidCount) *
7230 169 : dfBlockValidCount / dfNewValidCount;
7231 169 : nValidCount = nNewValidCount;
7232 : }
7233 : }
7234 :
7235 12839 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7236 12839 : (static_cast<double>(nBlocksPerRow) *
7237 12839 : nBlocksPerColumn),
7238 : "Compute Statistics", pProgressData))
7239 : {
7240 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7241 : "User terminated");
7242 0 : return CE_Failure;
7243 : }
7244 : }
7245 :
7246 243 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7247 : {
7248 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7249 0 : return CE_Failure;
7250 : }
7251 :
7252 243 : double dfStdDev = 0;
7253 243 : if (bIntegerStats)
7254 : {
7255 219 : if (nValidCount)
7256 210 : dfMean = static_cast<double>(nSum) / nValidCount;
7257 :
7258 : // To avoid potential precision issues when doing the difference,
7259 : // we need to do that computation on 128 bit rather than casting
7260 : // to double
7261 : const GDALUInt128 nTmpForStdDev(
7262 219 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7263 438 : GDALUInt128::Mul(nSum, nSum));
7264 219 : dfStdDev =
7265 219 : nValidCount > 0
7266 219 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7267 : : 0.0;
7268 : }
7269 24 : else if (nValidCount > 0)
7270 : {
7271 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7272 : }
7273 :
7274 : /// Save computed information
7275 243 : if (nValidCount > 0)
7276 : {
7277 234 : if (bApproxOK)
7278 : {
7279 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7280 : }
7281 210 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7282 : {
7283 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7284 : }
7285 234 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7286 : }
7287 :
7288 243 : SetValidPercent(nSampleCount, nValidCount);
7289 :
7290 : /* --------------------------------------------------------------------
7291 : */
7292 : /* Record results. */
7293 : /* --------------------------------------------------------------------
7294 : */
7295 243 : if (pdfMin != nullptr)
7296 240 : *pdfMin = nValidCount ? nMin : 0;
7297 243 : if (pdfMax != nullptr)
7298 240 : *pdfMax = nValidCount ? nMax : 0;
7299 :
7300 243 : if (pdfMean != nullptr)
7301 236 : *pdfMean = dfMean;
7302 :
7303 243 : if (pdfStdDev != nullptr)
7304 236 : *pdfStdDev = dfStdDev;
7305 :
7306 243 : if (nValidCount > 0)
7307 234 : return CE_None;
7308 :
7309 9 : ReportError(CE_Failure, CPLE_AppDefined,
7310 : "Failed to compute statistics, no valid pixels found "
7311 : "in sampling.");
7312 9 : return CE_Failure;
7313 : }
7314 :
7315 271 : GByte *pabyMaskData = nullptr;
7316 271 : if (poMaskBand)
7317 : {
7318 : pabyMaskData = static_cast<GByte *>(
7319 46 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7320 46 : if (!pabyMaskData)
7321 : {
7322 0 : return CE_Failure;
7323 : }
7324 : }
7325 :
7326 271 : float fMin = std::numeric_limits<float>::infinity();
7327 271 : float fMax = -std::numeric_limits<float>::infinity();
7328 : const bool bFloat32Optim =
7329 46 : eDataType == GDT_Float32 && !pabyMaskData &&
7330 337 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7331 20 : CPLTestBool(
7332 271 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7333 :
7334 : #if (defined(__x86_64__) || defined(_M_X64))
7335 : const bool bFloat64Optim =
7336 15 : eDataType == GDT_Float64 && !pabyMaskData &&
7337 301 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7338 15 : CPLTestBool(
7339 271 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7340 : #endif
7341 :
7342 271 : for (GIntBig iSampleBlock = 0;
7343 5938 : iSampleBlock <
7344 5938 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7345 5667 : iSampleBlock += nSampleRate)
7346 : {
7347 5667 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7348 5667 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7349 :
7350 5667 : int nXCheck = 0, nYCheck = 0;
7351 5667 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7352 :
7353 6240 : if (poMaskBand &&
7354 573 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7355 573 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7356 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7357 573 : 0, nBlockXSize, nullptr) != CE_None)
7358 : {
7359 0 : CPLFree(pabyMaskData);
7360 0 : return CE_Failure;
7361 : }
7362 :
7363 : GDALRasterBlock *const poBlock =
7364 5667 : GetLockedBlockRef(iXBlock, iYBlock);
7365 5667 : if (poBlock == nullptr)
7366 : {
7367 0 : CPLFree(pabyMaskData);
7368 0 : return CE_Failure;
7369 : }
7370 :
7371 5667 : const void *const pData = poBlock->GetDataRef();
7372 :
7373 5667 : if (bFloat32Optim)
7374 : {
7375 2334 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7376 0 : !std::isnan(sNoDataValues.fNoDataValue);
7377 2334 : double dfBlockMean = 0;
7378 2334 : double dfBlockM2 = 0;
7379 2334 : double dfBlockValidCount = 0;
7380 8223 : for (int iY = 0; iY < nYCheck; iY++)
7381 : {
7382 5889 : const int iOffset = iY * nBlockXSize;
7383 5889 : if (dfBlockValidCount > 0 && fMin != fMax)
7384 : {
7385 3428 : int iX = 0;
7386 : #if (defined(__x86_64__) || defined(_M_X64))
7387 3428 : if (bHasNoData)
7388 : {
7389 : iX = ComputeStatisticsFloat32_SSE2<
7390 : /* bCheckMinEqMax = */ false,
7391 0 : /* bHasNoData = */ true>(
7392 0 : static_cast<const float *>(pData) + iOffset,
7393 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7394 : fMax, dfBlockMean, dfBlockM2,
7395 : dfBlockValidCount);
7396 : }
7397 : else
7398 : {
7399 : iX = ComputeStatisticsFloat32_SSE2<
7400 : /* bCheckMinEqMax = */ false,
7401 3428 : /* bHasNoData = */ false>(
7402 3428 : static_cast<const float *>(pData) + iOffset,
7403 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7404 : fMax, dfBlockMean, dfBlockM2,
7405 : dfBlockValidCount);
7406 : }
7407 : #endif
7408 3957 : for (; iX < nXCheck; iX++)
7409 : {
7410 529 : const float fValue =
7411 529 : static_cast<const float *>(pData)[iOffset + iX];
7412 529 : if (std::isnan(fValue) ||
7413 0 : (bHasNoData &&
7414 0 : fValue == sNoDataValues.fNoDataValue))
7415 11 : continue;
7416 518 : fMin = std::min(fMin, fValue);
7417 518 : fMax = std::max(fMax, fValue);
7418 518 : dfBlockValidCount += 1.0;
7419 518 : const double dfValue = static_cast<double>(fValue);
7420 518 : const double dfDelta = dfValue - dfBlockMean;
7421 518 : dfBlockMean += dfDelta / dfBlockValidCount;
7422 518 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7423 3428 : }
7424 : }
7425 : else
7426 : {
7427 2461 : int iX = 0;
7428 2461 : if (dfBlockValidCount == 0)
7429 : {
7430 2334 : for (; iX < nXCheck; iX++)
7431 : {
7432 2334 : const float fValue = static_cast<const float *>(
7433 2334 : pData)[iOffset + iX];
7434 2334 : if (std::isnan(fValue) ||
7435 0 : (bHasNoData &&
7436 0 : fValue == sNoDataValues.fNoDataValue))
7437 0 : continue;
7438 2334 : fMin = std::min(fMin, fValue);
7439 2334 : fMax = std::max(fMax, fValue);
7440 2334 : dfBlockValidCount = 1;
7441 2334 : dfBlockMean = static_cast<double>(fValue);
7442 2334 : iX++;
7443 2334 : break;
7444 : }
7445 : }
7446 : #if (defined(__x86_64__) || defined(_M_X64))
7447 2461 : if (bHasNoData)
7448 : {
7449 : iX = ComputeStatisticsFloat32_SSE2<
7450 : /* bCheckMinEqMax = */ true,
7451 0 : /* bHasNoData = */ true>(
7452 0 : static_cast<const float *>(pData) + iOffset,
7453 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7454 : fMax, dfBlockMean, dfBlockM2,
7455 : dfBlockValidCount);
7456 : }
7457 : else
7458 : {
7459 : iX = ComputeStatisticsFloat32_SSE2<
7460 : /* bCheckMinEqMax = */ true,
7461 2461 : /* bHasNoData = */ false>(
7462 2461 : static_cast<const float *>(pData) + iOffset,
7463 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7464 : fMax, dfBlockMean, dfBlockM2,
7465 : dfBlockValidCount);
7466 : }
7467 : #endif
7468 9326 : for (; iX < nXCheck; iX++)
7469 : {
7470 6865 : const float fValue =
7471 6865 : static_cast<const float *>(pData)[iOffset + iX];
7472 6865 : if (std::isnan(fValue) ||
7473 0 : (bHasNoData &&
7474 0 : fValue == sNoDataValues.fNoDataValue))
7475 1 : continue;
7476 6864 : fMin = std::min(fMin, fValue);
7477 6864 : fMax = std::max(fMax, fValue);
7478 6864 : dfBlockValidCount += 1.0;
7479 6864 : if (fMin != fMax)
7480 : {
7481 3099 : const double dfValue =
7482 3099 : static_cast<double>(fValue);
7483 3099 : const double dfDelta = dfValue - dfBlockMean;
7484 3099 : dfBlockMean += dfDelta / dfBlockValidCount;
7485 3099 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7486 : }
7487 : }
7488 : }
7489 : }
7490 :
7491 2334 : if (dfBlockValidCount > 0)
7492 : {
7493 : // Update the global mean and M2 (the difference of the
7494 : // square to the mean) from the values of the block
7495 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7496 2334 : const auto nNewValidCount =
7497 2334 : nValidCount + static_cast<int>(dfBlockValidCount);
7498 2334 : dfM2 += dfBlockM2;
7499 2334 : if (dfBlockMean != dfMean)
7500 : {
7501 1070 : if (nValidCount == 0)
7502 : {
7503 14 : dfMean = dfBlockMean;
7504 : }
7505 : else
7506 : {
7507 1056 : const double dfDelta = dfBlockMean - dfMean;
7508 1056 : const double dfNewValidCount =
7509 : static_cast<double>(nNewValidCount);
7510 1056 : dfMean +=
7511 1056 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7512 1056 : dfM2 += dfDelta * dfDelta *
7513 1056 : static_cast<double>(nValidCount) *
7514 1056 : dfBlockValidCount / dfNewValidCount;
7515 : }
7516 : }
7517 2334 : nValidCount = nNewValidCount;
7518 : }
7519 : }
7520 :
7521 : #if (defined(__x86_64__) || defined(_M_X64))
7522 3333 : else if (bFloat64Optim)
7523 : {
7524 : const bool bHasNoData =
7525 549 : sNoDataValues.bGotNoDataValue &&
7526 263 : !std::isnan(sNoDataValues.dfNoDataValue);
7527 286 : double dfBlockMean = 0;
7528 286 : double dfBlockM2 = 0;
7529 286 : double dfBlockValidCount = 0;
7530 2637 : for (int iY = 0; iY < nYCheck; iY++)
7531 : {
7532 2351 : const int iOffset = iY * nBlockXSize;
7533 2351 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7534 : {
7535 1809 : int iX = 0;
7536 1809 : if (bHasNoData)
7537 : {
7538 : iX = ComputeStatisticsFloat64_SSE2<
7539 : /* bCheckMinEqMax = */ false,
7540 381 : /* bHasNoData = */ true>(
7541 381 : static_cast<const double *>(pData) + iOffset,
7542 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7543 : dfMax, dfBlockMean, dfBlockM2,
7544 : dfBlockValidCount);
7545 : }
7546 : else
7547 : {
7548 : iX = ComputeStatisticsFloat64_SSE2<
7549 : /* bCheckMinEqMax = */ false,
7550 1428 : /* bHasNoData = */ false>(
7551 1428 : static_cast<const double *>(pData) + iOffset,
7552 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7553 : dfMax, dfBlockMean, dfBlockM2,
7554 : dfBlockValidCount);
7555 : }
7556 2927 : for (; iX < nXCheck; iX++)
7557 : {
7558 1118 : const double dfValue = static_cast<const double *>(
7559 1118 : pData)[iOffset + iX];
7560 1625 : if (std::isnan(dfValue) ||
7561 507 : (bHasNoData &&
7562 507 : dfValue == sNoDataValues.dfNoDataValue))
7563 53 : continue;
7564 1065 : dfMin = std::min(dfMin, dfValue);
7565 1065 : dfMax = std::max(dfMax, dfValue);
7566 1065 : dfBlockValidCount += 1.0;
7567 1065 : const double dfDelta = dfValue - dfBlockMean;
7568 1065 : dfBlockMean += dfDelta / dfBlockValidCount;
7569 1065 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7570 1809 : }
7571 : }
7572 : else
7573 : {
7574 542 : int iX = 0;
7575 542 : if (dfBlockValidCount == 0)
7576 : {
7577 7665 : for (; iX < nXCheck; iX++)
7578 : {
7579 7631 : const double dfValue =
7580 : static_cast<const double *>(
7581 7631 : pData)[iOffset + iX];
7582 15239 : if (std::isnan(dfValue) ||
7583 7608 : (bHasNoData &&
7584 7608 : dfValue == sNoDataValues.dfNoDataValue))
7585 7377 : continue;
7586 254 : dfMin = std::min(dfMin, dfValue);
7587 254 : dfMax = std::max(dfMax, dfValue);
7588 254 : dfBlockValidCount = 1;
7589 254 : dfBlockMean = dfValue;
7590 254 : iX++;
7591 254 : break;
7592 : }
7593 : }
7594 542 : if (bHasNoData)
7595 : {
7596 : iX = ComputeStatisticsFloat64_SSE2<
7597 : /* bCheckMinEqMax = */ true,
7598 392 : /* bHasNoData = */ true>(
7599 392 : static_cast<const double *>(pData) + iOffset,
7600 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7601 : dfMax, dfBlockMean, dfBlockM2,
7602 : dfBlockValidCount);
7603 : }
7604 : else
7605 : {
7606 : iX = ComputeStatisticsFloat64_SSE2<
7607 : /* bCheckMinEqMax = */ true,
7608 150 : /* bHasNoData = */ false>(
7609 150 : static_cast<const double *>(pData) + iOffset,
7610 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7611 : dfMax, dfBlockMean, dfBlockM2,
7612 : dfBlockValidCount);
7613 : }
7614 1097 : for (; iX < nXCheck; iX++)
7615 : {
7616 555 : const double dfValue = static_cast<const double *>(
7617 555 : pData)[iOffset + iX];
7618 1077 : if (std::isnan(dfValue) ||
7619 522 : (bHasNoData &&
7620 522 : dfValue == sNoDataValues.dfNoDataValue))
7621 140 : continue;
7622 415 : dfMin = std::min(dfMin, dfValue);
7623 415 : dfMax = std::max(dfMax, dfValue);
7624 415 : dfBlockValidCount += 1.0;
7625 415 : if (dfMin != dfMax)
7626 : {
7627 140 : const double dfDelta = dfValue - dfBlockMean;
7628 140 : dfBlockMean += dfDelta / dfBlockValidCount;
7629 140 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7630 : }
7631 : }
7632 : }
7633 : }
7634 :
7635 286 : if (dfBlockValidCount > 0)
7636 : {
7637 : // Update the global mean and M2 (the difference of the
7638 : // square to the mean) from the values of the block
7639 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7640 254 : const auto nNewValidCount =
7641 254 : nValidCount + static_cast<int>(dfBlockValidCount);
7642 254 : dfM2 += dfBlockM2;
7643 254 : if (dfBlockMean != dfMean)
7644 : {
7645 241 : if (nValidCount == 0)
7646 : {
7647 12 : dfMean = dfBlockMean;
7648 : }
7649 : else
7650 : {
7651 229 : const double dfDelta = dfBlockMean - dfMean;
7652 229 : const double dfNewValidCount =
7653 : static_cast<double>(nNewValidCount);
7654 229 : dfMean +=
7655 229 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7656 229 : dfM2 += dfDelta * dfDelta *
7657 229 : static_cast<double>(nValidCount) *
7658 229 : dfBlockValidCount / dfNewValidCount;
7659 : }
7660 : }
7661 254 : nValidCount = nNewValidCount;
7662 : }
7663 : }
7664 : #endif // (defined(__x86_64__) || defined(_M_X64))
7665 :
7666 : else
7667 : {
7668 : // This isn't the fastest way to do this, but is easier for now.
7669 10762 : for (int iY = 0; iY < nYCheck; iY++)
7670 : {
7671 7715 : if (nValidCount && dfMin != dfMax)
7672 : {
7673 714032 : for (int iX = 0; iX < nXCheck; iX++)
7674 : {
7675 709450 : const GPtrDiff_t iOffset =
7676 709450 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7677 709450 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7678 9635 : continue;
7679 :
7680 699827 : bool bValid = true;
7681 : double dfValue =
7682 699827 : GetPixelValue(eDataType, bSignedByte, pData,
7683 699827 : iOffset, sNoDataValues, bValid);
7684 :
7685 699827 : if (!bValid)
7686 12 : continue;
7687 :
7688 699815 : dfMin = std::min(dfMin, dfValue);
7689 699815 : dfMax = std::max(dfMax, dfValue);
7690 :
7691 699815 : nValidCount++;
7692 699815 : const double dfDelta = dfValue - dfMean;
7693 699815 : dfMean += dfDelta / nValidCount;
7694 699815 : dfM2 += dfDelta * (dfValue - dfMean);
7695 4582 : }
7696 : }
7697 : else
7698 : {
7699 3133 : int iX = 0;
7700 3133 : if (nValidCount == 0)
7701 : {
7702 94579 : for (; iX < nXCheck; iX++)
7703 : {
7704 94522 : const GPtrDiff_t iOffset =
7705 94522 : iX +
7706 94522 : static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7707 94522 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7708 94282 : continue;
7709 :
7710 241 : bool bValid = true;
7711 241 : double dfValue = GetPixelValue(
7712 : eDataType, bSignedByte, pData, iOffset,
7713 : sNoDataValues, bValid);
7714 :
7715 241 : if (!bValid)
7716 1 : continue;
7717 :
7718 240 : dfMin = dfValue;
7719 240 : dfMax = dfValue;
7720 240 : dfMean = dfValue;
7721 240 : nValidCount = 1;
7722 240 : iX++;
7723 240 : break;
7724 : }
7725 : }
7726 228187 : for (; iX < nXCheck; iX++)
7727 : {
7728 225054 : const GPtrDiff_t iOffset =
7729 225054 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7730 225054 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7731 358 : continue;
7732 :
7733 224697 : bool bValid = true;
7734 : double dfValue =
7735 224697 : GetPixelValue(eDataType, bSignedByte, pData,
7736 224697 : iOffset, sNoDataValues, bValid);
7737 :
7738 224697 : if (!bValid)
7739 1 : continue;
7740 :
7741 224696 : dfMin = std::min(dfMin, dfValue);
7742 224696 : dfMax = std::max(dfMax, dfValue);
7743 :
7744 224696 : nValidCount++;
7745 224696 : if (dfMin != dfMax)
7746 : {
7747 2680 : const double dfDelta = dfValue - dfMean;
7748 2680 : dfMean += dfDelta / nValidCount;
7749 2680 : dfM2 += dfDelta * (dfValue - dfMean);
7750 : }
7751 : }
7752 : }
7753 : }
7754 : }
7755 :
7756 5667 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
7757 :
7758 5667 : poBlock->DropLock();
7759 :
7760 5667 : if (!pfnProgress(
7761 5667 : static_cast<double>(iSampleBlock) /
7762 5667 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
7763 : "Compute Statistics", pProgressData))
7764 : {
7765 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7766 0 : CPLFree(pabyMaskData);
7767 0 : return CE_Failure;
7768 : }
7769 : }
7770 :
7771 271 : if (bFloat32Optim)
7772 : {
7773 18 : dfMin = static_cast<double>(fMin);
7774 18 : dfMax = static_cast<double>(fMax);
7775 : }
7776 271 : CPLFree(pabyMaskData);
7777 : }
7778 :
7779 271 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7780 : {
7781 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7782 0 : return CE_Failure;
7783 : }
7784 :
7785 : /* -------------------------------------------------------------------- */
7786 : /* Save computed information. */
7787 : /* -------------------------------------------------------------------- */
7788 271 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7789 :
7790 271 : if (nValidCount > 0)
7791 : {
7792 270 : if (bApproxOK)
7793 : {
7794 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7795 : }
7796 262 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7797 : {
7798 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7799 : }
7800 270 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7801 : }
7802 : else
7803 : {
7804 1 : dfMin = 0.0;
7805 1 : dfMax = 0.0;
7806 : }
7807 :
7808 271 : SetValidPercent(nSampleCount, nValidCount);
7809 :
7810 : /* -------------------------------------------------------------------- */
7811 : /* Record results. */
7812 : /* -------------------------------------------------------------------- */
7813 271 : if (pdfMin != nullptr)
7814 268 : *pdfMin = dfMin;
7815 271 : if (pdfMax != nullptr)
7816 268 : *pdfMax = dfMax;
7817 :
7818 271 : if (pdfMean != nullptr)
7819 265 : *pdfMean = dfMean;
7820 :
7821 271 : if (pdfStdDev != nullptr)
7822 265 : *pdfStdDev = dfStdDev;
7823 :
7824 271 : if (nValidCount > 0)
7825 270 : return CE_None;
7826 :
7827 1 : ReportError(
7828 : CE_Failure, CPLE_AppDefined,
7829 : "Failed to compute statistics, no valid pixels found in sampling.");
7830 1 : return CE_Failure;
7831 : }
7832 :
7833 : /************************************************************************/
7834 : /* GDALComputeRasterStatistics() */
7835 : /************************************************************************/
7836 :
7837 : /**
7838 : * \brief Compute image statistics.
7839 : *
7840 : * @see GDALRasterBand::ComputeStatistics()
7841 : */
7842 :
7843 173 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7844 : int bApproxOK, double *pdfMin,
7845 : double *pdfMax, double *pdfMean,
7846 : double *pdfStdDev,
7847 : GDALProgressFunc pfnProgress,
7848 : void *pProgressData)
7849 :
7850 : {
7851 173 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7852 :
7853 173 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7854 :
7855 173 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7856 173 : pdfStdDev, pfnProgress, pProgressData);
7857 : }
7858 :
7859 : /************************************************************************/
7860 : /* SetStatistics() */
7861 : /************************************************************************/
7862 :
7863 : /**
7864 : * \brief Set statistics on band.
7865 : *
7866 : * This method can be used to store min/max/mean/standard deviation
7867 : * statistics on a raster band.
7868 : *
7869 : * The default implementation stores them as metadata, and will only work
7870 : * on formats that can save arbitrary metadata. This method cannot detect
7871 : * whether metadata will be properly saved and so may return CE_None even
7872 : * if the statistics will never be saved.
7873 : *
7874 : * This method is the same as the C function GDALSetRasterStatistics().
7875 : *
7876 : * @param dfMin minimum pixel value.
7877 : *
7878 : * @param dfMax maximum pixel value.
7879 : *
7880 : * @param dfMean mean (average) of all pixel values.
7881 : *
7882 : * @param dfStdDev Standard deviation of all pixel values.
7883 : *
7884 : * @return CE_None on success or CE_Failure on failure.
7885 : */
7886 :
7887 537 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7888 : double dfStdDev)
7889 :
7890 : {
7891 537 : char szValue[128] = {0};
7892 :
7893 537 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7894 537 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7895 :
7896 537 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7897 537 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7898 :
7899 537 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7900 537 : SetMetadataItem("STATISTICS_MEAN", szValue);
7901 :
7902 537 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7903 537 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7904 :
7905 537 : return CE_None;
7906 : }
7907 :
7908 : /************************************************************************/
7909 : /* GDALSetRasterStatistics() */
7910 : /************************************************************************/
7911 :
7912 : /**
7913 : * \brief Set statistics on band.
7914 : *
7915 : * @see GDALRasterBand::SetStatistics()
7916 : */
7917 :
7918 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7919 : double dfMax, double dfMean,
7920 : double dfStdDev)
7921 :
7922 : {
7923 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7924 :
7925 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7926 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7927 : }
7928 :
7929 : /************************************************************************/
7930 : /* ComputeRasterMinMax() */
7931 : /************************************************************************/
7932 :
7933 : template <class T, bool HAS_NODATA>
7934 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7935 : T *pMax)
7936 : {
7937 2 : T min0 = *pMin;
7938 2 : T max0 = *pMax;
7939 2 : T min1 = *pMin;
7940 2 : T max1 = *pMax;
7941 : size_t i;
7942 2 : for (i = 0; i + 1 < nElts; i += 2)
7943 : {
7944 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
7945 : {
7946 0 : min0 = std::min(min0, buffer[i]);
7947 0 : max0 = std::max(max0, buffer[i]);
7948 : }
7949 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7950 : {
7951 0 : min1 = std::min(min1, buffer[i + 1]);
7952 0 : max1 = std::max(max1, buffer[i + 1]);
7953 : }
7954 : }
7955 2 : T min = std::min(min0, min1);
7956 2 : T max = std::max(max0, max1);
7957 2 : if (i < nElts)
7958 : {
7959 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
7960 : {
7961 2 : min = std::min(min, buffer[i]);
7962 2 : max = std::max(max, buffer[i]);
7963 : }
7964 : }
7965 2 : *pMin = min;
7966 2 : *pMax = max;
7967 2 : }
7968 :
7969 : template <GDALDataType eDataType, bool bSignedByte>
7970 : static void
7971 6703 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7972 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7973 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7974 : {
7975 6703 : double dfLocalMin = dfMin;
7976 6703 : double dfLocalMax = dfMax;
7977 :
7978 22051 : for (int iY = 0; iY < nYCheck; iY++)
7979 : {
7980 14858421 : for (int iX = 0; iX < nXCheck; iX++)
7981 : {
7982 14843085 : const GPtrDiff_t iOffset =
7983 14843085 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7984 14843085 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7985 109836 : continue;
7986 14760102 : bool bValid = true;
7987 14760102 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7988 : iOffset, sNoDataValues, bValid);
7989 14760102 : if (!bValid)
7990 26871 : continue;
7991 :
7992 14733202 : dfLocalMin = std::min(dfLocalMin, dfValue);
7993 14733202 : dfLocalMax = std::max(dfLocalMax, dfValue);
7994 : }
7995 : }
7996 :
7997 6703 : dfMin = dfLocalMin;
7998 6703 : dfMax = dfLocalMax;
7999 6703 : }
8000 :
8001 6703 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8002 : bool bSignedByte, int nXCheck, int nYCheck,
8003 : int nBlockXSize,
8004 : const GDALNoDataValues &sNoDataValues,
8005 : const GByte *pabyMaskData, double &dfMin,
8006 : double &dfMax)
8007 : {
8008 6703 : switch (eDataType)
8009 : {
8010 0 : case GDT_Unknown:
8011 0 : CPLAssert(false);
8012 : break;
8013 660 : case GDT_UInt8:
8014 660 : if (bSignedByte)
8015 : {
8016 3 : ComputeMinMaxGeneric<GDT_UInt8, true>(
8017 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8018 : pabyMaskData, dfMin, dfMax);
8019 : }
8020 : else
8021 : {
8022 657 : ComputeMinMaxGeneric<GDT_UInt8, false>(
8023 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8024 : pabyMaskData, dfMin, dfMax);
8025 : }
8026 660 : break;
8027 4 : case GDT_Int8:
8028 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8029 : nBlockXSize, sNoDataValues,
8030 : pabyMaskData, dfMin, dfMax);
8031 4 : break;
8032 969 : case GDT_UInt16:
8033 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8034 : nBlockXSize, sNoDataValues,
8035 : pabyMaskData, dfMin, dfMax);
8036 969 : break;
8037 2 : case GDT_Int16:
8038 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8039 : nBlockXSize, sNoDataValues,
8040 : pabyMaskData, dfMin, dfMax);
8041 2 : break;
8042 3 : case GDT_UInt32:
8043 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8044 : nBlockXSize, sNoDataValues,
8045 : pabyMaskData, dfMin, dfMax);
8046 3 : break;
8047 3 : case GDT_Int32:
8048 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8049 : nBlockXSize, sNoDataValues,
8050 : pabyMaskData, dfMin, dfMax);
8051 3 : break;
8052 4 : case GDT_UInt64:
8053 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8054 : nBlockXSize, sNoDataValues,
8055 : pabyMaskData, dfMin, dfMax);
8056 4 : break;
8057 4 : case GDT_Int64:
8058 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8059 : nBlockXSize, sNoDataValues,
8060 : pabyMaskData, dfMin, dfMax);
8061 4 : break;
8062 2 : case GDT_Float16:
8063 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8064 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8065 : pabyMaskData, dfMin, dfMax);
8066 2 : break;
8067 4941 : case GDT_Float32:
8068 4941 : ComputeMinMaxGeneric<GDT_Float32, false>(
8069 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8070 : pabyMaskData, dfMin, dfMax);
8071 4941 : break;
8072 1 : case GDT_Float64:
8073 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8074 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8075 : pabyMaskData, dfMin, dfMax);
8076 1 : break;
8077 9 : case GDT_CInt16:
8078 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8079 : nBlockXSize, sNoDataValues,
8080 : pabyMaskData, dfMin, dfMax);
8081 9 : break;
8082 9 : case GDT_CInt32:
8083 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8084 : nBlockXSize, sNoDataValues,
8085 : pabyMaskData, dfMin, dfMax);
8086 9 : break;
8087 0 : case GDT_CFloat16:
8088 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8089 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8090 : pabyMaskData, dfMin, dfMax);
8091 0 : break;
8092 75 : case GDT_CFloat32:
8093 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8094 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8095 : pabyMaskData, dfMin, dfMax);
8096 75 : break;
8097 17 : case GDT_CFloat64:
8098 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8099 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8100 : pabyMaskData, dfMin, dfMax);
8101 17 : break;
8102 0 : case GDT_TypeCount:
8103 0 : CPLAssert(false);
8104 : break;
8105 : }
8106 6703 : }
8107 :
8108 189 : static bool ComputeMinMaxGenericIterBlocks(
8109 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8110 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8111 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8112 : double &dfMin, double &dfMax)
8113 :
8114 : {
8115 189 : GByte *pabyMaskData = nullptr;
8116 : int nBlockXSize, nBlockYSize;
8117 189 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8118 :
8119 189 : if (poMaskBand)
8120 : {
8121 : pabyMaskData =
8122 125 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8123 125 : if (!pabyMaskData)
8124 : {
8125 0 : return false;
8126 : }
8127 : }
8128 :
8129 6892 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8130 6703 : iSampleBlock += nSampleRate)
8131 : {
8132 6703 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8133 6703 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8134 :
8135 6703 : int nXCheck = 0, nYCheck = 0;
8136 6703 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8137 :
8138 13283 : if (poMaskBand &&
8139 6580 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8140 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8141 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8142 : nBlockXSize, nullptr) != CE_None)
8143 : {
8144 0 : CPLFree(pabyMaskData);
8145 0 : return false;
8146 : }
8147 :
8148 6703 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8149 6703 : if (poBlock == nullptr)
8150 : {
8151 0 : CPLFree(pabyMaskData);
8152 0 : return false;
8153 : }
8154 :
8155 6703 : void *const pData = poBlock->GetDataRef();
8156 :
8157 6703 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8158 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8159 : dfMax);
8160 :
8161 6703 : poBlock->DropLock();
8162 : }
8163 :
8164 189 : CPLFree(pabyMaskData);
8165 189 : return true;
8166 : }
8167 :
8168 : /**
8169 : * \brief Compute the min/max values for a band.
8170 : *
8171 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8172 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8173 : * get an approximate min/max. If the band has a nodata value it will
8174 : * be excluded from the minimum and maximum.
8175 : *
8176 : * If bApprox is FALSE, then all pixels will be read and used to compute
8177 : * an exact range.
8178 : *
8179 : * This method is the same as the C function GDALComputeRasterMinMax().
8180 : *
8181 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8182 : * FALSE.
8183 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8184 : * maximum (adfMinMax[1]) are returned.
8185 : *
8186 : * @return CE_None on success or CE_Failure on failure.
8187 : */
8188 :
8189 1818 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8190 : {
8191 : /* -------------------------------------------------------------------- */
8192 : /* Does the driver already know the min/max? */
8193 : /* -------------------------------------------------------------------- */
8194 1818 : if (bApproxOK)
8195 : {
8196 23 : int bSuccessMin = FALSE;
8197 23 : int bSuccessMax = FALSE;
8198 :
8199 23 : double dfMin = GetMinimum(&bSuccessMin);
8200 23 : double dfMax = GetMaximum(&bSuccessMax);
8201 :
8202 23 : if (bSuccessMin && bSuccessMax)
8203 : {
8204 1 : adfMinMax[0] = dfMin;
8205 1 : adfMinMax[1] = dfMax;
8206 1 : return CE_None;
8207 : }
8208 : }
8209 :
8210 : /* -------------------------------------------------------------------- */
8211 : /* If we have overview bands, use them for min/max. */
8212 : /* -------------------------------------------------------------------- */
8213 : // cppcheck-suppress knownConditionTrueFalse
8214 1817 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8215 : {
8216 : GDALRasterBand *poBand =
8217 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8218 :
8219 0 : if (poBand != this)
8220 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8221 : }
8222 :
8223 : /* -------------------------------------------------------------------- */
8224 : /* Read actual data and compute minimum and maximum. */
8225 : /* -------------------------------------------------------------------- */
8226 1817 : GDALNoDataValues sNoDataValues(this, eDataType);
8227 1817 : GDALRasterBand *poMaskBand = nullptr;
8228 1817 : if (!sNoDataValues.bGotNoDataValue)
8229 : {
8230 1555 : const int l_nMaskFlags = GetMaskFlags();
8231 1680 : if (l_nMaskFlags != GMF_ALL_VALID &&
8232 125 : GetColorInterpretation() != GCI_AlphaBand)
8233 : {
8234 125 : poMaskBand = GetMaskBand();
8235 : }
8236 : }
8237 :
8238 1817 : if (!bApproxOK &&
8239 1795 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8240 1657 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8241 1454 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8242 1408 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8243 1795 : eDataType == GDT_Float64) &&
8244 : !poMaskBand)
8245 : {
8246 1470 : CPLErr eErr = ComputeRasterMinMaxLocation(
8247 735 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8248 735 : if (eErr == CE_Warning)
8249 : {
8250 9 : ReportError(CE_Failure, CPLE_AppDefined,
8251 : "Failed to compute min/max, no valid pixels found in "
8252 : "sampling.");
8253 9 : eErr = CE_Failure;
8254 : }
8255 735 : return eErr;
8256 : }
8257 :
8258 1082 : bool bSignedByte = false;
8259 1082 : if (eDataType == GDT_UInt8)
8260 : {
8261 782 : EnablePixelTypeSignedByteWarning(false);
8262 : const char *pszPixelType =
8263 782 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8264 782 : EnablePixelTypeSignedByteWarning(true);
8265 782 : bSignedByte =
8266 782 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8267 : }
8268 :
8269 : GDALRasterIOExtraArg sExtraArg;
8270 1082 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8271 :
8272 2164 : GUInt32 nMin = (eDataType == GDT_UInt8)
8273 1082 : ? 255
8274 : : 65535; // used for GByte & GUInt16 cases
8275 1082 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8276 1082 : GInt16 nMinInt16 =
8277 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8278 1082 : GInt16 nMaxInt16 =
8279 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8280 1082 : double dfMin =
8281 : std::numeric_limits<double>::infinity(); // used for generic code path
8282 1082 : double dfMax =
8283 : -std::numeric_limits<double>::infinity(); // used for generic code path
8284 1082 : const bool bUseOptimizedPath =
8285 1288 : !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8286 206 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8287 :
8288 : const auto ComputeMinMaxForBlock =
8289 19540 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8290 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8291 113100 : int nYCheck)
8292 : {
8293 19540 : if (eDataType == GDT_UInt8 && !bSignedByte)
8294 : {
8295 : const bool bHasNoData =
8296 11562 : sNoDataValues.bGotNoDataValue &&
8297 29687 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8298 11562 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8299 11562 : sNoDataValues.dfNoDataValue;
8300 18125 : const GUInt32 nNoDataValue =
8301 18125 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8302 : : 0;
8303 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8304 : ComputeStatisticsInternal<GByte,
8305 : /* COMPUTE_OTHER_STATS = */ false>::
8306 18125 : f(nXCheck, nBufferWidth, nYCheck,
8307 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8308 18125 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8309 : }
8310 1415 : else if (eDataType == GDT_UInt16)
8311 : {
8312 : const bool bHasNoData =
8313 84 : sNoDataValues.bGotNoDataValue &&
8314 1497 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8315 84 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8316 84 : sNoDataValues.dfNoDataValue;
8317 1413 : const GUInt32 nNoDataValue =
8318 1413 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8319 : : 0;
8320 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8321 : ComputeStatisticsInternal<GUInt16,
8322 : /* COMPUTE_OTHER_STATS = */ false>::
8323 1413 : f(nXCheck, nBufferWidth, nYCheck,
8324 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8325 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8326 : }
8327 2 : else if (eDataType == GDT_Int16)
8328 : {
8329 : const bool bHasNoData =
8330 0 : sNoDataValues.bGotNoDataValue &&
8331 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8332 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8333 0 : sNoDataValues.dfNoDataValue;
8334 2 : if (bHasNoData)
8335 : {
8336 0 : const int16_t nNoDataValue =
8337 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8338 0 : for (int iY = 0; iY < nYCheck; iY++)
8339 : {
8340 0 : ComputeMinMax<int16_t, true>(
8341 0 : static_cast<const int16_t *>(pData) +
8342 0 : static_cast<size_t>(iY) * nBufferWidth,
8343 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8344 : }
8345 : }
8346 : else
8347 : {
8348 4 : for (int iY = 0; iY < nYCheck; iY++)
8349 : {
8350 2 : ComputeMinMax<int16_t, false>(
8351 2 : static_cast<const int16_t *>(pData) +
8352 2 : static_cast<size_t>(iY) * nBufferWidth,
8353 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8354 : }
8355 : }
8356 : }
8357 19540 : };
8358 :
8359 1082 : if (bApproxOK && HasArbitraryOverviews())
8360 : {
8361 : /* --------------------------------------------------------------------
8362 : */
8363 : /* Figure out how much the image should be reduced to get an */
8364 : /* approximate value. */
8365 : /* --------------------------------------------------------------------
8366 : */
8367 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8368 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8369 :
8370 0 : int nXReduced = nRasterXSize;
8371 0 : int nYReduced = nRasterYSize;
8372 0 : if (dfReduction > 1.0)
8373 : {
8374 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8375 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8376 :
8377 : // Catch the case of huge resizing ratios here
8378 0 : if (nXReduced == 0)
8379 0 : nXReduced = 1;
8380 0 : if (nYReduced == 0)
8381 0 : nYReduced = 1;
8382 : }
8383 :
8384 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8385 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8386 :
8387 : const CPLErr eErr =
8388 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8389 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8390 0 : if (eErr != CE_None)
8391 : {
8392 0 : CPLFree(pData);
8393 0 : return eErr;
8394 : }
8395 :
8396 0 : GByte *pabyMaskData = nullptr;
8397 0 : if (poMaskBand)
8398 : {
8399 : pabyMaskData =
8400 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8401 0 : if (!pabyMaskData)
8402 : {
8403 0 : CPLFree(pData);
8404 0 : return CE_Failure;
8405 : }
8406 :
8407 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8408 : pabyMaskData, nXReduced, nYReduced,
8409 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
8410 : {
8411 0 : CPLFree(pData);
8412 0 : CPLFree(pabyMaskData);
8413 0 : return CE_Failure;
8414 : }
8415 : }
8416 :
8417 0 : if (bUseOptimizedPath)
8418 : {
8419 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8420 : }
8421 : else
8422 : {
8423 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8424 : nYReduced, nXReduced, sNoDataValues,
8425 : pabyMaskData, dfMin, dfMax);
8426 : }
8427 :
8428 0 : CPLFree(pData);
8429 0 : CPLFree(pabyMaskData);
8430 : }
8431 :
8432 : else // No arbitrary overviews
8433 : {
8434 1082 : if (!InitBlockInfo())
8435 0 : return CE_Failure;
8436 :
8437 : /* --------------------------------------------------------------------
8438 : */
8439 : /* Figure out the ratio of blocks we will read to get an */
8440 : /* approximate value. */
8441 : /* --------------------------------------------------------------------
8442 : */
8443 1082 : int nSampleRate = 1;
8444 :
8445 1082 : if (bApproxOK)
8446 : {
8447 22 : nSampleRate = static_cast<int>(std::max(
8448 44 : 1.0,
8449 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8450 : // We want to avoid probing only the first column of blocks for
8451 : // a square shaped raster, because it is not unlikely that it may
8452 : // be padding only (#6378).
8453 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8454 0 : nSampleRate += 1;
8455 : }
8456 :
8457 1082 : if (bUseOptimizedPath)
8458 : {
8459 893 : for (GIntBig iSampleBlock = 0;
8460 20359 : iSampleBlock <
8461 20359 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8462 19466 : iSampleBlock += nSampleRate)
8463 : {
8464 19542 : const int iYBlock =
8465 19542 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8466 19542 : const int iXBlock =
8467 19542 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8468 :
8469 19542 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8470 19542 : if (poBlock == nullptr)
8471 2 : return CE_Failure;
8472 :
8473 19540 : void *const pData = poBlock->GetDataRef();
8474 :
8475 19540 : int nXCheck = 0, nYCheck = 0;
8476 19540 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8477 :
8478 19540 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8479 :
8480 19540 : poBlock->DropLock();
8481 :
8482 19540 : if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8483 4110 : nMax == 255)
8484 74 : break;
8485 : }
8486 : }
8487 : else
8488 : {
8489 189 : const GIntBig nTotalBlocks =
8490 189 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8491 189 : if (!ComputeMinMaxGenericIterBlocks(
8492 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8493 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8494 : {
8495 0 : return CE_Failure;
8496 : }
8497 : }
8498 : }
8499 :
8500 1080 : if (bUseOptimizedPath)
8501 : {
8502 891 : if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8503 : {
8504 890 : dfMin = nMin;
8505 890 : dfMax = nMax;
8506 : }
8507 1 : else if (eDataType == GDT_Int16)
8508 : {
8509 1 : dfMin = nMinInt16;
8510 1 : dfMax = nMaxInt16;
8511 : }
8512 : }
8513 :
8514 1080 : if (dfMin > dfMax)
8515 : {
8516 23 : adfMinMax[0] = 0;
8517 23 : adfMinMax[1] = 0;
8518 23 : ReportError(
8519 : CE_Failure, CPLE_AppDefined,
8520 : "Failed to compute min/max, no valid pixels found in sampling.");
8521 23 : return CE_Failure;
8522 : }
8523 :
8524 1057 : adfMinMax[0] = dfMin;
8525 1057 : adfMinMax[1] = dfMax;
8526 :
8527 1057 : return CE_None;
8528 : }
8529 :
8530 : /************************************************************************/
8531 : /* GDALComputeRasterMinMax() */
8532 : /************************************************************************/
8533 :
8534 : /**
8535 : * \brief Compute the min/max values for a band.
8536 : *
8537 : * @see GDALRasterBand::ComputeRasterMinMax()
8538 : *
8539 : * @note Prior to GDAL 3.6, this function returned void
8540 : */
8541 :
8542 1667 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8543 : double adfMinMax[2])
8544 :
8545 : {
8546 1667 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8547 :
8548 1667 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8549 1667 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8550 : }
8551 :
8552 : /************************************************************************/
8553 : /* ComputeRasterMinMaxLocation() */
8554 : /************************************************************************/
8555 :
8556 : /**
8557 : * \brief Compute the min/max values for a band, and their location.
8558 : *
8559 : * Pixels whose value matches the nodata value or are masked by the mask
8560 : * band are ignored.
8561 : *
8562 : * If the minimum or maximum value is hit in several locations, it is not
8563 : * specified which one will be returned.
8564 : *
8565 : * @param[out] pdfMin Pointer to the minimum value.
8566 : * @param[out] pdfMax Pointer to the maximum value.
8567 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8568 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8569 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8570 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8571 : *
8572 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8573 : * CE_Failure in case of error.
8574 : *
8575 : * @since GDAL 3.11
8576 : */
8577 :
8578 751 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8579 : double *pdfMax, int *pnMinX,
8580 : int *pnMinY, int *pnMaxX,
8581 : int *pnMaxY)
8582 : {
8583 751 : int nMinX = -1;
8584 751 : int nMinY = -1;
8585 751 : int nMaxX = -1;
8586 751 : int nMaxY = -1;
8587 751 : double dfMin = std::numeric_limits<double>::infinity();
8588 751 : double dfMax = -std::numeric_limits<double>::infinity();
8589 751 : if (pdfMin)
8590 748 : *pdfMin = dfMin;
8591 751 : if (pdfMax)
8592 748 : *pdfMax = dfMax;
8593 751 : if (pnMinX)
8594 14 : *pnMinX = nMinX;
8595 751 : if (pnMinY)
8596 14 : *pnMinY = nMinY;
8597 751 : if (pnMaxX)
8598 14 : *pnMaxX = nMaxX;
8599 751 : if (pnMaxY)
8600 14 : *pnMaxY = nMaxY;
8601 :
8602 751 : if (GDALDataTypeIsComplex(eDataType))
8603 : {
8604 0 : CPLError(CE_Failure, CPLE_NotSupported,
8605 : "Complex data type not supported");
8606 0 : return CE_Failure;
8607 : }
8608 :
8609 751 : if (!InitBlockInfo())
8610 0 : return CE_Failure;
8611 :
8612 751 : GDALNoDataValues sNoDataValues(this, eDataType);
8613 751 : GDALRasterBand *poMaskBand = nullptr;
8614 751 : if (!sNoDataValues.bGotNoDataValue)
8615 : {
8616 578 : const int l_nMaskFlags = GetMaskFlags();
8617 579 : if (l_nMaskFlags != GMF_ALL_VALID &&
8618 1 : GetColorInterpretation() != GCI_AlphaBand)
8619 : {
8620 1 : poMaskBand = GetMaskBand();
8621 : }
8622 : }
8623 :
8624 751 : bool bSignedByte = false;
8625 751 : if (eDataType == GDT_UInt8)
8626 : {
8627 7 : EnablePixelTypeSignedByteWarning(false);
8628 : const char *pszPixelType =
8629 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8630 7 : EnablePixelTypeSignedByteWarning(true);
8631 7 : bSignedByte =
8632 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8633 : }
8634 :
8635 751 : GByte *pabyMaskData = nullptr;
8636 751 : if (poMaskBand)
8637 : {
8638 : pabyMaskData =
8639 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8640 1 : if (!pabyMaskData)
8641 : {
8642 0 : return CE_Failure;
8643 : }
8644 : }
8645 :
8646 751 : const GIntBig nTotalBlocks =
8647 751 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8648 751 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8649 751 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8650 7857 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8651 : {
8652 7109 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8653 7109 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8654 :
8655 7109 : int nXCheck = 0, nYCheck = 0;
8656 7109 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8657 :
8658 7111 : if (poMaskBand &&
8659 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8660 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8661 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8662 2 : nBlockXSize, nullptr) != CE_None)
8663 : {
8664 0 : CPLFree(pabyMaskData);
8665 0 : return CE_Failure;
8666 : }
8667 :
8668 7109 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8669 7109 : if (poBlock == nullptr)
8670 : {
8671 0 : CPLFree(pabyMaskData);
8672 0 : return CE_Failure;
8673 : }
8674 :
8675 7109 : void *const pData = poBlock->GetDataRef();
8676 :
8677 7109 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8678 : {
8679 5059 : for (int iY = 0; iY < nYCheck; ++iY)
8680 : {
8681 238290 : for (int iX = 0; iX < nXCheck; ++iX)
8682 : {
8683 233478 : const GPtrDiff_t iOffset =
8684 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8685 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8686 2 : continue;
8687 233476 : bool bValid = true;
8688 : double dfValue =
8689 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8690 : sNoDataValues, bValid);
8691 233476 : if (!bValid)
8692 0 : continue;
8693 233476 : if (dfValue < dfMin)
8694 : {
8695 606 : dfMin = dfValue;
8696 606 : nMinX = iXBlock * nBlockXSize + iX;
8697 606 : nMinY = iYBlock * nBlockYSize + iY;
8698 : }
8699 233476 : if (dfValue > dfMax)
8700 : {
8701 1515 : dfMax = dfValue;
8702 1515 : nMaxX = iXBlock * nBlockXSize + iX;
8703 1515 : nMaxY = iYBlock * nBlockYSize + iY;
8704 : }
8705 : }
8706 247 : }
8707 : }
8708 : else
8709 : {
8710 6862 : size_t pos_min = 0;
8711 6862 : size_t pos_max = 0;
8712 6862 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8713 6862 : if (bNeedsMin && bNeedsMax)
8714 : {
8715 13716 : std::tie(pos_min, pos_max) = gdal::minmax_element(
8716 6858 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8717 6858 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8718 13716 : sNoDataValues.dfNoDataValue);
8719 : }
8720 4 : else if (bNeedsMin)
8721 : {
8722 1 : pos_min = gdal::min_element(
8723 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8724 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8725 : sNoDataValues.dfNoDataValue);
8726 : }
8727 3 : else if (bNeedsMax)
8728 : {
8729 2 : pos_max = gdal::max_element(
8730 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8731 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8732 : sNoDataValues.dfNoDataValue);
8733 : }
8734 :
8735 6862 : if (bNeedsMin)
8736 : {
8737 6859 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8738 6859 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8739 6859 : bool bValid = true;
8740 : const double dfMinValueBlock =
8741 6859 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
8742 : sNoDataValues, bValid);
8743 6859 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
8744 : {
8745 1042 : dfMin = dfMinValueBlock;
8746 1042 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
8747 1042 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
8748 : }
8749 : }
8750 :
8751 6862 : if (bNeedsMax)
8752 : {
8753 6860 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
8754 6860 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
8755 6860 : bool bValid = true;
8756 : const double dfMaxValueBlock =
8757 6860 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
8758 : sNoDataValues, bValid);
8759 6860 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
8760 : {
8761 962 : dfMax = dfMaxValueBlock;
8762 962 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
8763 962 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
8764 : }
8765 : }
8766 : }
8767 :
8768 7109 : poBlock->DropLock();
8769 :
8770 7109 : if (eDataType == GDT_UInt8)
8771 : {
8772 10 : if (bNeedsMin && dfMin == 0)
8773 : {
8774 1 : bNeedsMin = false;
8775 : }
8776 10 : if (bNeedsMax && dfMax == 255)
8777 : {
8778 4 : bNeedsMax = false;
8779 : }
8780 10 : if (!bNeedsMin && !bNeedsMax)
8781 : {
8782 3 : break;
8783 : }
8784 : }
8785 : }
8786 :
8787 751 : CPLFree(pabyMaskData);
8788 :
8789 751 : if (pdfMin)
8790 748 : *pdfMin = dfMin;
8791 751 : if (pdfMax)
8792 748 : *pdfMax = dfMax;
8793 751 : if (pnMinX)
8794 14 : *pnMinX = nMinX;
8795 751 : if (pnMinY)
8796 14 : *pnMinY = nMinY;
8797 751 : if (pnMaxX)
8798 14 : *pnMaxX = nMaxX;
8799 751 : if (pnMaxY)
8800 14 : *pnMaxY = nMaxY;
8801 751 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8802 751 : : CE_None;
8803 : }
8804 :
8805 : /************************************************************************/
8806 : /* GDALComputeRasterMinMaxLocation() */
8807 : /************************************************************************/
8808 :
8809 : /**
8810 : * \brief Compute the min/max values for a band, and their location.
8811 : *
8812 : * @see GDALRasterBand::ComputeRasterMinMax()
8813 : * @since GDAL 3.11
8814 : */
8815 :
8816 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8817 : double *pdfMax, int *pnMinX, int *pnMinY,
8818 : int *pnMaxX, int *pnMaxY)
8819 :
8820 : {
8821 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8822 :
8823 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8824 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8825 14 : pnMaxX, pnMaxY);
8826 : }
8827 :
8828 : /************************************************************************/
8829 : /* SetDefaultHistogram() */
8830 : /************************************************************************/
8831 :
8832 : /* FIXME : add proper documentation */
8833 : /**
8834 : * \brief Set default histogram.
8835 : *
8836 : * This method is the same as the C function GDALSetDefaultHistogram() and
8837 : * GDALSetDefaultHistogramEx()
8838 : */
8839 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8840 : double /* dfMax */,
8841 : int /* nBuckets */,
8842 : GUIntBig * /* panHistogram */)
8843 :
8844 : {
8845 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8846 0 : ReportError(CE_Failure, CPLE_NotSupported,
8847 : "SetDefaultHistogram() not implemented for this format.");
8848 :
8849 0 : return CE_Failure;
8850 : }
8851 :
8852 : /************************************************************************/
8853 : /* GDALSetDefaultHistogram() */
8854 : /************************************************************************/
8855 :
8856 : /**
8857 : * \brief Set default histogram.
8858 : *
8859 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8860 : * 2 billion.
8861 : *
8862 : * @see GDALRasterBand::SetDefaultHistogram()
8863 : * @see GDALSetRasterHistogramEx()
8864 : */
8865 :
8866 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8867 : double dfMax, int nBuckets,
8868 : int *panHistogram)
8869 :
8870 : {
8871 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8872 :
8873 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8874 :
8875 : GUIntBig *panHistogramTemp =
8876 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8877 0 : if (panHistogramTemp == nullptr)
8878 : {
8879 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8880 : "Out of memory in GDALSetDefaultHistogram().");
8881 0 : return CE_Failure;
8882 : }
8883 :
8884 0 : for (int i = 0; i < nBuckets; ++i)
8885 : {
8886 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8887 : }
8888 :
8889 : const CPLErr eErr =
8890 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8891 :
8892 0 : CPLFree(panHistogramTemp);
8893 :
8894 0 : return eErr;
8895 : }
8896 :
8897 : /************************************************************************/
8898 : /* GDALSetDefaultHistogramEx() */
8899 : /************************************************************************/
8900 :
8901 : /**
8902 : * \brief Set default histogram.
8903 : *
8904 : * @see GDALRasterBand::SetDefaultHistogram()
8905 : *
8906 : */
8907 :
8908 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8909 : double dfMin, double dfMax,
8910 : int nBuckets,
8911 : GUIntBig *panHistogram)
8912 :
8913 : {
8914 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8915 :
8916 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8917 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8918 : }
8919 :
8920 : /************************************************************************/
8921 : /* GetDefaultRAT() */
8922 : /************************************************************************/
8923 :
8924 : /**
8925 : * \brief Fetch default Raster Attribute Table.
8926 : *
8927 : * A RAT will be returned if there is a default one associated with the
8928 : * band, otherwise NULL is returned. The returned RAT is owned by the
8929 : * band and should not be deleted by the application.
8930 : *
8931 : * This method is the same as the C function GDALGetDefaultRAT().
8932 : *
8933 : * @return NULL, or a pointer to an internal RAT owned by the band.
8934 : */
8935 :
8936 180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8937 :
8938 : {
8939 180 : return nullptr;
8940 : }
8941 :
8942 : /************************************************************************/
8943 : /* GDALGetDefaultRAT() */
8944 : /************************************************************************/
8945 :
8946 : /**
8947 : * \brief Fetch default Raster Attribute Table.
8948 : *
8949 : * @see GDALRasterBand::GetDefaultRAT()
8950 : */
8951 :
8952 1165 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8953 :
8954 : {
8955 1165 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8956 :
8957 1165 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8958 1165 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8959 : }
8960 :
8961 : /************************************************************************/
8962 : /* SetDefaultRAT() */
8963 : /************************************************************************/
8964 :
8965 : /**
8966 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8967 : * \brief Set default Raster Attribute Table.
8968 : *
8969 : * Associates a default RAT with the band. If not implemented for the
8970 : * format a CPLE_NotSupported error will be issued. If successful a copy
8971 : * of the RAT is made, the original remains owned by the caller.
8972 : *
8973 : * This method is the same as the C function GDALSetDefaultRAT().
8974 : *
8975 : * @param poRAT the RAT to assign to the band.
8976 : *
8977 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8978 : * failing.
8979 : */
8980 :
8981 : /**/
8982 : /**/
8983 :
8984 : CPLErr
8985 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8986 : {
8987 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8988 : {
8989 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8990 0 : ReportError(CE_Failure, CPLE_NotSupported,
8991 : "SetDefaultRAT() not implemented for this format.");
8992 0 : CPLPopErrorHandler();
8993 : }
8994 0 : return CE_Failure;
8995 : }
8996 :
8997 : /************************************************************************/
8998 : /* GDALSetDefaultRAT() */
8999 : /************************************************************************/
9000 :
9001 : /**
9002 : * \brief Set default Raster Attribute Table.
9003 : *
9004 : * @see GDALRasterBand::GDALSetDefaultRAT()
9005 : */
9006 :
9007 39 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9008 : GDALRasterAttributeTableH hRAT)
9009 :
9010 : {
9011 39 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9012 :
9013 39 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9014 :
9015 39 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9016 : }
9017 :
9018 : /************************************************************************/
9019 : /* GetMaskBand() */
9020 : /************************************************************************/
9021 :
9022 : /**
9023 : * \brief Return the mask band associated with the band.
9024 : *
9025 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9026 : * that returns one of four default implementations :
9027 : * <ul>
9028 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9029 : * </li>
9030 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9031 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9032 : * GMF_NODATA | GMF_PER_DATASET.
9033 : * </li>
9034 : * <li>If the band has a nodata value set, an instance of the new
9035 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9036 : * GMF_NODATA.
9037 : * </li>
9038 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9039 : * to apply to this band (specific rules yet to be determined) and that is of
9040 : * type GDT_UInt8 then that alpha band will be returned, and the flags
9041 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9042 : * </li>
9043 : * <li>If neither of the above apply, an instance of the new
9044 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9045 : * pixels. The null flags will return GMF_ALL_VALID.
9046 : * </li>
9047 : * </ul>
9048 : *
9049 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9050 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9051 : *
9052 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9053 : * dataset, with the same name as the main dataset and suffixed with .msk,
9054 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9055 : * main dataset.
9056 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9057 : * level, where xx matches the band number of a band of the main dataset. The
9058 : * value of those items is a combination of the flags GMF_ALL_VALID,
9059 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9060 : * a band, then the other rules explained above will be used to generate a
9061 : * on-the-fly mask band.
9062 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9063 : *
9064 : * This method is the same as the C function GDALGetMaskBand().
9065 : *
9066 : * @return a valid mask band.
9067 : *
9068 : *
9069 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9070 : *
9071 : */
9072 814065 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9073 :
9074 : {
9075 400774 : const auto HasNoData = [this]()
9076 : {
9077 133269 : int bHaveNoDataRaw = FALSE;
9078 133269 : bool bHaveNoData = false;
9079 133269 : if (eDataType == GDT_Int64)
9080 : {
9081 210 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
9082 210 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9083 : }
9084 133059 : else if (eDataType == GDT_UInt64)
9085 : {
9086 158 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9087 158 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9088 : }
9089 : else
9090 : {
9091 132901 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
9092 132901 : if (bHaveNoDataRaw &&
9093 132901 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9094 : {
9095 1132 : bHaveNoData = true;
9096 : }
9097 : }
9098 133269 : return bHaveNoData;
9099 814065 : };
9100 :
9101 814065 : if (poMask != nullptr)
9102 : {
9103 714410 : if (poMask.IsOwned())
9104 : {
9105 334354 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9106 : {
9107 33695 : if (HasNoData())
9108 : {
9109 9 : InvalidateMaskBand();
9110 : }
9111 : }
9112 300659 : else if (auto poNoDataMaskBand =
9113 300659 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9114 : {
9115 398 : int bHaveNoDataRaw = FALSE;
9116 398 : bool bIsSame = false;
9117 398 : if (eDataType == GDT_Int64)
9118 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9119 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9120 10 : bHaveNoDataRaw;
9121 381 : else if (eDataType == GDT_UInt64)
9122 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9123 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9124 10 : bHaveNoDataRaw;
9125 : else
9126 : {
9127 : const double dfNoDataValue =
9128 364 : GetNoDataValue(&bHaveNoDataRaw);
9129 364 : if (bHaveNoDataRaw)
9130 : {
9131 361 : bIsSame =
9132 361 : std::isnan(dfNoDataValue)
9133 361 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9134 326 : : poNoDataMaskBand->m_dfNoDataValue ==
9135 : dfNoDataValue;
9136 : }
9137 : }
9138 398 : if (!bIsSame)
9139 23 : InvalidateMaskBand();
9140 : }
9141 : }
9142 :
9143 714410 : if (poMask)
9144 714378 : return poMask.get();
9145 : }
9146 :
9147 : /* -------------------------------------------------------------------- */
9148 : /* Check for a mask in a .msk file. */
9149 : /* -------------------------------------------------------------------- */
9150 99687 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9151 : {
9152 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9153 47 : if (poMask != nullptr)
9154 : {
9155 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9156 45 : return poMask.get();
9157 : }
9158 : }
9159 :
9160 : /* -------------------------------------------------------------------- */
9161 : /* Check for NODATA_VALUES metadata. */
9162 : /* -------------------------------------------------------------------- */
9163 99642 : if (poDS != nullptr)
9164 : {
9165 : const char *pszGDALNoDataValues =
9166 99626 : poDS->GetMetadataItem("NODATA_VALUES");
9167 99626 : if (pszGDALNoDataValues != nullptr)
9168 : {
9169 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9170 : pszGDALNoDataValues, " ", FALSE, FALSE);
9171 :
9172 : // Make sure we have as many values as bands.
9173 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9174 68 : poDS->GetRasterCount() != 0)
9175 : {
9176 : // Make sure that all bands have the same data type
9177 : // This is clearly not a fundamental condition, just a
9178 : // condition to make implementation easier.
9179 68 : GDALDataType eDT = GDT_Unknown;
9180 68 : int i = 0; // Used after for.
9181 270 : for (; i < poDS->GetRasterCount(); ++i)
9182 : {
9183 202 : if (i == 0)
9184 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9185 134 : else if (eDT !=
9186 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9187 : {
9188 0 : break;
9189 : }
9190 : }
9191 68 : if (i == poDS->GetRasterCount())
9192 : {
9193 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9194 : try
9195 : {
9196 68 : poMask.reset(
9197 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9198 : }
9199 0 : catch (const std::bad_alloc &)
9200 : {
9201 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9202 0 : poMask.reset();
9203 : }
9204 68 : CSLDestroy(papszGDALNoDataValues);
9205 68 : return poMask.get();
9206 : }
9207 : else
9208 : {
9209 0 : ReportError(CE_Warning, CPLE_AppDefined,
9210 : "All bands should have the same type in "
9211 : "order the NODATA_VALUES metadata item "
9212 : "to be used as a mask.");
9213 : }
9214 : }
9215 : else
9216 : {
9217 0 : ReportError(
9218 : CE_Warning, CPLE_AppDefined,
9219 : "NODATA_VALUES metadata item doesn't have the same number "
9220 : "of values as the number of bands. "
9221 : "Ignoring it for mask.");
9222 : }
9223 :
9224 0 : CSLDestroy(papszGDALNoDataValues);
9225 : }
9226 : }
9227 :
9228 : /* -------------------------------------------------------------------- */
9229 : /* Check for nodata case. */
9230 : /* -------------------------------------------------------------------- */
9231 99574 : if (HasNoData())
9232 : {
9233 1158 : nMaskFlags = GMF_NODATA;
9234 : try
9235 : {
9236 1158 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9237 : }
9238 0 : catch (const std::bad_alloc &)
9239 : {
9240 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9241 0 : poMask.reset();
9242 : }
9243 1158 : return poMask.get();
9244 : }
9245 :
9246 : /* -------------------------------------------------------------------- */
9247 : /* Check for alpha case. */
9248 : /* -------------------------------------------------------------------- */
9249 98401 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9250 197421 : this == poDS->GetRasterBand(1) &&
9251 604 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9252 : {
9253 231 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9254 : {
9255 187 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9256 187 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9257 187 : return poMask.get();
9258 : }
9259 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9260 : {
9261 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9262 : try
9263 : {
9264 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9265 46 : poDS->GetRasterBand(2)));
9266 : }
9267 0 : catch (const std::bad_alloc &)
9268 : {
9269 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9270 0 : poMask.reset();
9271 : }
9272 23 : return poMask.get();
9273 : }
9274 : }
9275 :
9276 98191 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9277 3139 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9278 197135 : this == poDS->GetRasterBand(3)) &&
9279 2452 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9280 : {
9281 1576 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9282 : {
9283 1520 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9284 1520 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9285 1520 : return poMask.get();
9286 : }
9287 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9288 : {
9289 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9290 : try
9291 : {
9292 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9293 84 : poDS->GetRasterBand(4)));
9294 : }
9295 0 : catch (const std::bad_alloc &)
9296 : {
9297 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9298 0 : poMask.reset();
9299 : }
9300 42 : return poMask.get();
9301 : }
9302 : }
9303 :
9304 : /* -------------------------------------------------------------------- */
9305 : /* Fallback to all valid case. */
9306 : /* -------------------------------------------------------------------- */
9307 96644 : nMaskFlags = GMF_ALL_VALID;
9308 : try
9309 : {
9310 96644 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9311 : }
9312 0 : catch (const std::bad_alloc &)
9313 : {
9314 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9315 0 : poMask.reset();
9316 : }
9317 :
9318 96644 : return poMask.get();
9319 : }
9320 :
9321 : /************************************************************************/
9322 : /* GDALGetMaskBand() */
9323 : /************************************************************************/
9324 :
9325 : /**
9326 : * \brief Return the mask band associated with the band.
9327 : *
9328 : * @see GDALRasterBand::GetMaskBand()
9329 : */
9330 :
9331 11045 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9332 :
9333 : {
9334 11045 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9335 :
9336 11045 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9337 11045 : return poBand->GetMaskBand();
9338 : }
9339 :
9340 : /************************************************************************/
9341 : /* GetMaskFlags() */
9342 : /************************************************************************/
9343 :
9344 : /**
9345 : * \brief Return the status flags of the mask band associated with the band.
9346 : *
9347 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9348 : * the following available definitions that may be extended in the future:
9349 : * <ul>
9350 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9351 : * 255. When used this will normally be the only flag set.
9352 : * </li>
9353 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9354 : * dataset.
9355 : * </li>
9356 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9357 : * and may have values other than 0 and 255.
9358 : * </li>
9359 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9360 : * nodata values. (mutually exclusive of GMF_ALPHA)
9361 : * </li>
9362 : * </ul>
9363 : *
9364 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9365 : * that returns one of four default implementations:
9366 : * <ul>
9367 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9368 : * </li>
9369 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9370 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9371 : * GMF_NODATA | GMF_PER_DATASET.
9372 : * </li>
9373 : * <li>If the band has a nodata value set, an instance of the new
9374 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9375 : * GMF_NODATA.
9376 : * </li>
9377 : * <li>If there is no nodata value, but the dataset has an alpha band that
9378 : * seems to apply to this band (specific rules yet to be determined) and that is
9379 : * of type GDT_UInt8 then that alpha band will be returned, and the flags
9380 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9381 : * </li>
9382 : * <li>If neither of the above apply, an instance of the new
9383 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9384 : * pixels. The null flags will return GMF_ALL_VALID.
9385 : * </li>
9386 : * </ul>
9387 : *
9388 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9389 : * dataset, with the same name as the main dataset and suffixed with .msk,
9390 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9391 : * main dataset.
9392 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9393 : * level, where xx matches the band number of a band of the main dataset. The
9394 : * value of those items is a combination of the flags GMF_ALL_VALID,
9395 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9396 : * a band, then the other rules explained above will be used to generate a
9397 : * on-the-fly mask band.
9398 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9399 : *
9400 : * This method is the same as the C function GDALGetMaskFlags().
9401 : *
9402 : *
9403 : * @return a valid mask band.
9404 : *
9405 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9406 : *
9407 : */
9408 159187 : int GDALRasterBand::GetMaskFlags()
9409 :
9410 : {
9411 : // If we don't have a band yet, force this now so that the masks value
9412 : // will be initialized.
9413 :
9414 159187 : if (poMask == nullptr)
9415 97966 : GetMaskBand();
9416 :
9417 159187 : return nMaskFlags;
9418 : }
9419 :
9420 : /************************************************************************/
9421 : /* GDALGetMaskFlags() */
9422 : /************************************************************************/
9423 :
9424 : /**
9425 : * \brief Return the status flags of the mask band associated with the band.
9426 : *
9427 : * @see GDALRasterBand::GetMaskFlags()
9428 : */
9429 :
9430 8860 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9431 :
9432 : {
9433 8860 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9434 :
9435 8860 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9436 8860 : return poBand->GetMaskFlags();
9437 : }
9438 :
9439 : /************************************************************************/
9440 : /* InvalidateMaskBand() */
9441 : /************************************************************************/
9442 :
9443 : //! @cond Doxygen_Suppress
9444 1853340 : void GDALRasterBand::InvalidateMaskBand()
9445 : {
9446 1853340 : poMask.reset();
9447 1853340 : nMaskFlags = 0;
9448 1853340 : }
9449 :
9450 : //! @endcond
9451 :
9452 : /************************************************************************/
9453 : /* CreateMaskBand() */
9454 : /************************************************************************/
9455 :
9456 : /**
9457 : * \brief Adds a mask band to the current band
9458 : *
9459 : * The default implementation of the CreateMaskBand() method is implemented
9460 : * based on similar rules to the .ovr handling implemented using the
9461 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9462 : * be created with the same basename as the original file, and it will have
9463 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9464 : * The mask images will be deflate compressed tiled images with the same
9465 : * block size as the original image if possible.
9466 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9467 : * level, where xx matches the band number of a band of the main dataset. The
9468 : * value of those items will be the one of the nFlagsIn parameter.
9469 : *
9470 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9471 : * it might be invalidated by CreateMaskBand(). So you have to call
9472 : * GetMaskBand() again.
9473 : *
9474 : * This method is the same as the C function GDALCreateMaskBand().
9475 : *
9476 : *
9477 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9478 : *
9479 : * @return CE_None on success or CE_Failure on an error.
9480 : *
9481 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9482 : * @see GDALDataset::CreateMaskBand()
9483 : *
9484 : */
9485 :
9486 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9487 :
9488 : {
9489 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9490 : {
9491 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9492 10 : if (eErr != CE_None)
9493 1 : return eErr;
9494 :
9495 9 : InvalidateMaskBand();
9496 :
9497 9 : return CE_None;
9498 : }
9499 :
9500 0 : ReportError(CE_Failure, CPLE_NotSupported,
9501 : "CreateMaskBand() not supported for this band.");
9502 :
9503 0 : return CE_Failure;
9504 : }
9505 :
9506 : /************************************************************************/
9507 : /* GDALCreateMaskBand() */
9508 : /************************************************************************/
9509 :
9510 : /**
9511 : * \brief Adds a mask band to the current band
9512 : *
9513 : * @see GDALRasterBand::CreateMaskBand()
9514 : */
9515 :
9516 36 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9517 :
9518 : {
9519 36 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9520 :
9521 36 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9522 36 : return poBand->CreateMaskBand(nFlags);
9523 : }
9524 :
9525 : /************************************************************************/
9526 : /* IsMaskBand() */
9527 : /************************************************************************/
9528 :
9529 : /**
9530 : * \brief Returns whether a band is a mask band.
9531 : *
9532 : * Mask band must be understood in the broad term: it can be a per-dataset
9533 : * mask band, an alpha band, or an implicit mask band.
9534 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9535 : *
9536 : * This method is the same as the C function GDALIsMaskBand().
9537 : *
9538 : * @return true if the band is a mask band.
9539 : *
9540 : * @see GDALDataset::CreateMaskBand()
9541 : *
9542 : * @since GDAL 3.5.0
9543 : *
9544 : */
9545 :
9546 444 : bool GDALRasterBand::IsMaskBand() const
9547 : {
9548 : // The GeoTIFF driver, among others, override this method to
9549 : // also handle external .msk bands.
9550 444 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9551 444 : GCI_AlphaBand;
9552 : }
9553 :
9554 : /************************************************************************/
9555 : /* GDALIsMaskBand() */
9556 : /************************************************************************/
9557 :
9558 : /**
9559 : * \brief Returns whether a band is a mask band.
9560 : *
9561 : * Mask band must be understood in the broad term: it can be a per-dataset
9562 : * mask band, an alpha band, or an implicit mask band.
9563 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9564 : *
9565 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9566 : *
9567 : * @return true if the band is a mask band.
9568 : *
9569 : * @see GDALRasterBand::IsMaskBand()
9570 : *
9571 : * @since GDAL 3.5.0
9572 : *
9573 : */
9574 :
9575 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9576 :
9577 : {
9578 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9579 :
9580 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9581 37 : return poBand->IsMaskBand();
9582 : }
9583 :
9584 : /************************************************************************/
9585 : /* GetMaskValueRange() */
9586 : /************************************************************************/
9587 :
9588 : /**
9589 : * \brief Returns the range of values that a mask band can take.
9590 : *
9591 : * @return the range of values that a mask band can take.
9592 : *
9593 : * @since GDAL 3.5.0
9594 : *
9595 : */
9596 :
9597 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9598 : {
9599 0 : return GMVR_UNKNOWN;
9600 : }
9601 :
9602 : /************************************************************************/
9603 : /* GetIndexColorTranslationTo() */
9604 : /************************************************************************/
9605 :
9606 : /**
9607 : * \brief Compute translation table for color tables.
9608 : *
9609 : * When the raster band has a palette index, it may be useful to compute
9610 : * the "translation" of this palette to the palette of another band.
9611 : * The translation tries to do exact matching first, and then approximate
9612 : * matching if no exact matching is possible.
9613 : * This method returns a table such that table[i] = j where i is an index
9614 : * of the 'this' rasterband and j the corresponding index for the reference
9615 : * rasterband.
9616 : *
9617 : * This method is thought as internal to GDAL and is used for drivers
9618 : * like RPFTOC.
9619 : *
9620 : * The implementation only supports 1-byte palette rasterbands.
9621 : *
9622 : * @param poReferenceBand the raster band
9623 : * @param pTranslationTable an already allocated translation table (at least 256
9624 : * bytes), or NULL to let the method allocate it
9625 : * @param pApproximateMatching a pointer to a flag that is set if the matching
9626 : * is approximate. May be NULL.
9627 : *
9628 : * @return a translation table if the two bands are palette index and that they
9629 : * do not match or NULL in other cases. The table must be freed with CPLFree if
9630 : * NULL was passed for pTranslationTable.
9631 : */
9632 :
9633 : unsigned char *
9634 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9635 : unsigned char *pTranslationTable,
9636 : int *pApproximateMatching)
9637 : {
9638 4 : if (poReferenceBand == nullptr)
9639 0 : return nullptr;
9640 :
9641 : // cppcheck-suppress knownConditionTrueFalse
9642 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9643 : // cppcheck-suppress knownConditionTrueFalse
9644 4 : GetColorInterpretation() == GCI_PaletteIndex &&
9645 12 : poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
9646 4 : GetRasterDataType() == GDT_UInt8)
9647 : {
9648 4 : const GDALColorTable *srcColorTable = GetColorTable();
9649 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9650 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
9651 : {
9652 4 : const int nEntries = srcColorTable->GetColorEntryCount();
9653 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
9654 :
9655 4 : int bHasNoDataValueSrc = FALSE;
9656 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9657 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9658 4 : dfNoDataValueSrc <= 255 &&
9659 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9660 0 : bHasNoDataValueSrc = FALSE;
9661 4 : const int noDataValueSrc =
9662 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
9663 :
9664 4 : int bHasNoDataValueRef = FALSE;
9665 : const double dfNoDataValueRef =
9666 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
9667 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
9668 3 : dfNoDataValueRef <= 255 &&
9669 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
9670 1 : bHasNoDataValueRef = FALSE;
9671 4 : const int noDataValueRef =
9672 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
9673 :
9674 4 : bool samePalette = false;
9675 :
9676 4 : if (pApproximateMatching)
9677 3 : *pApproximateMatching = FALSE;
9678 :
9679 4 : if (nEntries == nRefEntries &&
9680 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
9681 3 : (bHasNoDataValueSrc == FALSE ||
9682 : noDataValueSrc == noDataValueRef))
9683 : {
9684 3 : samePalette = true;
9685 654 : for (int i = 0; i < nEntries; ++i)
9686 : {
9687 651 : if (noDataValueSrc == i)
9688 3 : continue;
9689 : const GDALColorEntry *entry =
9690 648 : srcColorTable->GetColorEntry(i);
9691 : const GDALColorEntry *entryRef =
9692 648 : destColorTable->GetColorEntry(i);
9693 648 : if (entry->c1 != entryRef->c1 ||
9694 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
9695 : {
9696 0 : samePalette = false;
9697 : }
9698 : }
9699 : }
9700 :
9701 4 : if (!samePalette)
9702 : {
9703 1 : if (pTranslationTable == nullptr)
9704 : {
9705 : pTranslationTable = static_cast<unsigned char *>(
9706 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
9707 1 : if (pTranslationTable == nullptr)
9708 1 : return nullptr;
9709 : }
9710 :
9711 : // Trying to remap the product palette on the subdataset
9712 : // palette.
9713 5 : for (int i = 0; i < nEntries; ++i)
9714 : {
9715 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
9716 : noDataValueSrc == i)
9717 0 : continue;
9718 : const GDALColorEntry *entry =
9719 4 : srcColorTable->GetColorEntry(i);
9720 4 : bool bMatchFound = false;
9721 13 : for (int j = 0; j < nRefEntries; ++j)
9722 : {
9723 10 : if (bHasNoDataValueRef && noDataValueRef == j)
9724 0 : continue;
9725 : const GDALColorEntry *entryRef =
9726 10 : destColorTable->GetColorEntry(j);
9727 10 : if (entry->c1 == entryRef->c1 &&
9728 2 : entry->c2 == entryRef->c2 &&
9729 2 : entry->c3 == entryRef->c3)
9730 : {
9731 1 : pTranslationTable[i] =
9732 : static_cast<unsigned char>(j);
9733 1 : bMatchFound = true;
9734 1 : break;
9735 : }
9736 : }
9737 4 : if (!bMatchFound)
9738 : {
9739 : // No exact match. Looking for closest color now.
9740 3 : int best_j = 0;
9741 3 : int best_distance = 0;
9742 3 : if (pApproximateMatching)
9743 0 : *pApproximateMatching = TRUE;
9744 12 : for (int j = 0; j < nRefEntries; ++j)
9745 : {
9746 : const GDALColorEntry *entryRef =
9747 9 : destColorTable->GetColorEntry(j);
9748 9 : int distance = (entry->c1 - entryRef->c1) *
9749 9 : (entry->c1 - entryRef->c1) +
9750 9 : (entry->c2 - entryRef->c2) *
9751 9 : (entry->c2 - entryRef->c2) +
9752 9 : (entry->c3 - entryRef->c3) *
9753 9 : (entry->c3 - entryRef->c3);
9754 9 : if (j == 0 || distance < best_distance)
9755 : {
9756 7 : best_j = j;
9757 7 : best_distance = distance;
9758 : }
9759 : }
9760 3 : pTranslationTable[i] =
9761 : static_cast<unsigned char>(best_j);
9762 : }
9763 : }
9764 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
9765 0 : pTranslationTable[noDataValueSrc] =
9766 : static_cast<unsigned char>(noDataValueRef);
9767 :
9768 1 : return pTranslationTable;
9769 : }
9770 : }
9771 : }
9772 3 : return nullptr;
9773 : }
9774 :
9775 : /************************************************************************/
9776 : /* SetFlushBlockErr() */
9777 : /************************************************************************/
9778 :
9779 : /**
9780 : * \brief Store that an error occurred while writing a dirty block.
9781 : *
9782 : * This function stores the fact that an error occurred while writing a dirty
9783 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
9784 : * flushed when the block cache get full, it is not convenient/possible to
9785 : * report that a dirty block could not be written correctly. This function
9786 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
9787 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
9788 : * places where the user can easily match the error with the relevant dataset.
9789 : */
9790 :
9791 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
9792 : {
9793 0 : eFlushBlockErr = eErr;
9794 0 : }
9795 :
9796 : /************************************************************************/
9797 : /* IncDirtyBlocks() */
9798 : /************************************************************************/
9799 :
9800 : /**
9801 : * \brief Increment/decrement the number of dirty blocks
9802 : */
9803 :
9804 796852 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9805 : {
9806 796852 : if (poBandBlockCache)
9807 796852 : poBandBlockCache->IncDirtyBlocks(nInc);
9808 796852 : }
9809 :
9810 : /************************************************************************/
9811 : /* ReportError() */
9812 : /************************************************************************/
9813 :
9814 : #ifndef DOXYGEN_XML
9815 : /**
9816 : * \brief Emits an error related to a raster band.
9817 : *
9818 : * This function is a wrapper for regular CPLError(). The only difference
9819 : * with CPLError() is that it prepends the error message with the dataset
9820 : * name and the band number.
9821 : *
9822 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9823 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9824 : * @param fmt a printf() style format string. Any additional arguments
9825 : * will be treated as arguments to fill in this format in a manner
9826 : * similar to printf().
9827 : *
9828 : */
9829 :
9830 2502 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9831 : const char *fmt, ...) const
9832 : {
9833 : va_list args;
9834 :
9835 2502 : va_start(args, fmt);
9836 :
9837 2502 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9838 2502 : pszDSName = CPLGetFilename(pszDSName);
9839 2502 : if (pszDSName[0] != '\0')
9840 : {
9841 2407 : CPLError(eErrClass, err_no, "%s",
9842 4814 : CPLString()
9843 2407 : .Printf("%s, band %d: ", pszDSName, GetBand())
9844 4814 : .append(CPLString().vPrintf(fmt, args))
9845 : .c_str());
9846 : }
9847 : else
9848 : {
9849 95 : CPLErrorV(eErrClass, err_no, fmt, args);
9850 : }
9851 :
9852 2502 : va_end(args);
9853 2502 : }
9854 : #endif
9855 :
9856 : /************************************************************************/
9857 : /* GetVirtualMemAuto() */
9858 : /************************************************************************/
9859 :
9860 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9861 : *
9862 : * Only supported on Linux and Unix systems with mmap() for now.
9863 : *
9864 : * This method allows creating a virtual memory object for a GDALRasterBand,
9865 : * that exposes the whole image data as a virtual array.
9866 : *
9867 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9868 : * specialized implementation, such as for raw files, may also directly use
9869 : * mechanisms of the operating system to create a view of the underlying file
9870 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9871 : *
9872 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9873 : * offer a specialized implementation with direct file mapping, provided that
9874 : * some requirements are met :
9875 : * - for all drivers, the dataset must be backed by a "real" file in the file
9876 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9877 : * must match the native ordering of the CPU.
9878 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9879 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9880 : * the file in sequential order, and be equally spaced (which is generally the
9881 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9882 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9883 : *
9884 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9885 : * CPLVirtualMemFree() must be called before the raster band object is
9886 : * destroyed.
9887 : *
9888 : * If p is such a pointer and base_type the type matching
9889 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9890 : * accessed with
9891 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9892 : *
9893 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9894 : *
9895 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9896 : * read/write the band.
9897 : *
9898 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9899 : * one pixel value in the buffer to the start of the next pixel value within a
9900 : * scanline.
9901 : *
9902 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9903 : * one scanline in the buffer to the start of the next.
9904 : *
9905 : * @param papszOptions NULL terminated list of options.
9906 : * If a specialized implementation exists, defining
9907 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9908 : * used. On the contrary, defining
9909 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9910 : * being used (thus only allowing efficient implementations to be used). When
9911 : * requiring or falling back to the default implementation, the following
9912 : * options are available : CACHE_SIZE (in bytes, defaults to
9913 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9914 : * to FALSE)
9915 : *
9916 : * @return a virtual memory object that must be unreferenced by
9917 : * CPLVirtualMemFree(), or NULL in case of failure.
9918 : *
9919 : */
9920 :
9921 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9922 : int *pnPixelSpace,
9923 : GIntBig *pnLineSpace,
9924 : char **papszOptions)
9925 : {
9926 9 : const char *pszImpl = CSLFetchNameValueDef(
9927 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9928 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9929 8 : EQUAL(pszImpl, "FALSE"))
9930 : {
9931 1 : return nullptr;
9932 : }
9933 :
9934 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9935 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9936 8 : if (pnPixelSpace)
9937 8 : *pnPixelSpace = nPixelSpace;
9938 8 : if (pnLineSpace)
9939 8 : *pnLineSpace = nLineSpace;
9940 : const size_t nCacheSize =
9941 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9942 : const size_t nPageSizeHint =
9943 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9944 8 : const bool bSingleThreadUsage = CPLTestBool(
9945 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9946 8 : return GDALRasterBandGetVirtualMem(
9947 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9948 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9949 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9950 8 : papszOptions);
9951 : }
9952 :
9953 : /************************************************************************/
9954 : /* GDALGetVirtualMemAuto() */
9955 : /************************************************************************/
9956 :
9957 : /**
9958 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9959 : *
9960 : * @see GDALRasterBand::GetVirtualMemAuto()
9961 : */
9962 :
9963 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9964 : int *pnPixelSpace, GIntBig *pnLineSpace,
9965 : CSLConstList papszOptions)
9966 : {
9967 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9968 :
9969 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9970 :
9971 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9972 31 : const_cast<char **>(papszOptions));
9973 : }
9974 :
9975 : /************************************************************************/
9976 : /* GDALGetDataCoverageStatus() */
9977 : /************************************************************************/
9978 :
9979 : /**
9980 : * \brief Get the coverage status of a sub-window of the raster.
9981 : *
9982 : * Returns whether a sub-window of the raster contains only data, only empty
9983 : * blocks or a mix of both. This function can be used to determine quickly
9984 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9985 : * be sparse.
9986 : *
9987 : * Empty blocks are blocks that are generally not physically present in the
9988 : * file, and when read through GDAL, contain only pixels whose value is the
9989 : * nodata value when it is set, or whose value is 0 when the nodata value is
9990 : * not set.
9991 : *
9992 : * The query is done in an efficient way without reading the actual pixel
9993 : * values. If not possible, or not implemented at all by the driver,
9994 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9995 : * be returned.
9996 : *
9997 : * The values that can be returned by the function are the following,
9998 : * potentially combined with the binary or operator :
9999 : * <ul>
10000 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10001 : * GetDataCoverageStatus(). This flag should be returned together with
10002 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10003 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10004 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10005 : * the queried window. This is typically identified by the concept of missing
10006 : * block in formats that supports it.
10007 : * </li>
10008 : * </ul>
10009 : *
10010 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10011 : * should be interpreted more as hint of potential presence of data. For example
10012 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10013 : * nodata value), instead of using the missing block mechanism,
10014 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10015 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10016 : *
10017 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10018 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10019 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10020 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10021 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10022 : * the function will exit, so that you can potentially refine the requested area
10023 : * to find which particular region(s) have missing blocks.
10024 : *
10025 : * @see GDALRasterBand::GetDataCoverageStatus()
10026 : *
10027 : * @param hBand raster band
10028 : *
10029 : * @param nXOff The pixel offset to the top left corner of the region
10030 : * of the band to be queried. This would be zero to start from the left side.
10031 : *
10032 : * @param nYOff The line offset to the top left corner of the region
10033 : * of the band to be queried. This would be zero to start from the top.
10034 : *
10035 : * @param nXSize The width of the region of the band to be queried in pixels.
10036 : *
10037 : * @param nYSize The height of the region of the band to be queried in lines.
10038 : *
10039 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10040 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10041 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10042 : * as the computation of the coverage matches the mask, the computation will be
10043 : * stopped. *pdfDataPct will not be valid in that case.
10044 : *
10045 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10046 : * to the (approximate) percentage in [0,100] of pixels in the queried
10047 : * sub-window that have valid values. The implementation might not always be
10048 : * able to compute it, in which case it will be set to a negative value.
10049 : *
10050 : * @return a binary-or'ed combination of possible values
10051 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10052 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10053 : */
10054 :
10055 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10056 : int nYOff, int nXSize, int nYSize,
10057 : int nMaskFlagStop, double *pdfDataPct)
10058 : {
10059 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10060 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10061 :
10062 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10063 :
10064 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10065 29 : nMaskFlagStop, pdfDataPct);
10066 : }
10067 :
10068 : /************************************************************************/
10069 : /* GetDataCoverageStatus() */
10070 : /************************************************************************/
10071 :
10072 : /**
10073 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10074 : * int nYOff,
10075 : * int nXSize,
10076 : * int nYSize,
10077 : * int nMaskFlagStop,
10078 : * double* pdfDataPct)
10079 : * \brief Get the coverage status of a sub-window of the raster.
10080 : *
10081 : * Returns whether a sub-window of the raster contains only data, only empty
10082 : * blocks or a mix of both. This function can be used to determine quickly
10083 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10084 : * be sparse.
10085 : *
10086 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10087 : * value when it is set, or whose value is 0 when the nodata value is not set.
10088 : *
10089 : * The query is done in an efficient way without reading the actual pixel
10090 : * values. If not possible, or not implemented at all by the driver,
10091 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10092 : * be returned.
10093 : *
10094 : * The values that can be returned by the function are the following,
10095 : * potentially combined with the binary or operator :
10096 : * <ul>
10097 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10098 : * GetDataCoverageStatus(). This flag should be returned together with
10099 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10100 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10101 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10102 : * the queried window. This is typically identified by the concept of missing
10103 : * block in formats that supports it.
10104 : * </li>
10105 : * </ul>
10106 : *
10107 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10108 : * should be interpreted more as hint of potential presence of data. For example
10109 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10110 : * nodata value), instead of using the missing block mechanism,
10111 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10112 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10113 : *
10114 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10115 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10116 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10117 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10118 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10119 : * the function will exit, so that you can potentially refine the requested area
10120 : * to find which particular region(s) have missing blocks.
10121 : *
10122 : * @see GDALGetDataCoverageStatus()
10123 : *
10124 : * @param nXOff The pixel offset to the top left corner of the region
10125 : * of the band to be queried. This would be zero to start from the left side.
10126 : *
10127 : * @param nYOff The line offset to the top left corner of the region
10128 : * of the band to be queried. This would be zero to start from the top.
10129 : *
10130 : * @param nXSize The width of the region of the band to be queried in pixels.
10131 : *
10132 : * @param nYSize The height of the region of the band to be queried in lines.
10133 : *
10134 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10135 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10136 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10137 : * as the computation of the coverage matches the mask, the computation will be
10138 : * stopped. *pdfDataPct will not be valid in that case.
10139 : *
10140 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10141 : * to the (approximate) percentage in [0,100] of pixels in the queried
10142 : * sub-window that have valid values. The implementation might not always be
10143 : * able to compute it, in which case it will be set to a negative value.
10144 : *
10145 : * @return a binary-or'ed combination of possible values
10146 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10147 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10148 : */
10149 :
10150 : /**
10151 : * \brief Get the coverage status of a sub-window of the raster.
10152 : *
10153 : * Returns whether a sub-window of the raster contains only data, only empty
10154 : * blocks or a mix of both. This function can be used to determine quickly
10155 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10156 : * be sparse.
10157 : *
10158 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10159 : * value when it is set, or whose value is 0 when the nodata value is not set.
10160 : *
10161 : * The query is done in an efficient way without reading the actual pixel
10162 : * values. If not possible, or not implemented at all by the driver,
10163 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10164 : * be returned.
10165 : *
10166 : * The values that can be returned by the function are the following,
10167 : * potentially combined with the binary or operator :
10168 : * <ul>
10169 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10170 : * GetDataCoverageStatus(). This flag should be returned together with
10171 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10172 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10173 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10174 : * the queried window. This is typically identified by the concept of missing
10175 : * block in formats that supports it.
10176 : * </li>
10177 : * </ul>
10178 : *
10179 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10180 : * should be interpreted more as hint of potential presence of data. For example
10181 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10182 : * nodata value), instead of using the missing block mechanism,
10183 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10184 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10185 : *
10186 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10187 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10188 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10189 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10190 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10191 : * the function will exit, so that you can potentially refine the requested area
10192 : * to find which particular region(s) have missing blocks.
10193 : *
10194 : * @see GDALGetDataCoverageStatus()
10195 : *
10196 : * @param nXOff The pixel offset to the top left corner of the region
10197 : * of the band to be queried. This would be zero to start from the left side.
10198 : *
10199 : * @param nYOff The line offset to the top left corner of the region
10200 : * of the band to be queried. This would be zero to start from the top.
10201 : *
10202 : * @param nXSize The width of the region of the band to be queried in pixels.
10203 : *
10204 : * @param nYSize The height of the region of the band to be queried in lines.
10205 : *
10206 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10207 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10208 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10209 : * as the computation of the coverage matches the mask, the computation will be
10210 : * stopped. *pdfDataPct will not be valid in that case.
10211 : *
10212 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10213 : * to the (approximate) percentage in [0,100] of pixels in the queried
10214 : * sub-window that have valid values. The implementation might not always be
10215 : * able to compute it, in which case it will be set to a negative value.
10216 : *
10217 : * @return a binary-or'ed combination of possible values
10218 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10219 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10220 : */
10221 :
10222 4720 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10223 : int nYSize, int nMaskFlagStop,
10224 : double *pdfDataPct)
10225 : {
10226 4720 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
10227 4720 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
10228 4720 : nYOff + nYSize > nRasterYSize)
10229 : {
10230 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10231 0 : if (pdfDataPct)
10232 0 : *pdfDataPct = 0.0;
10233 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10234 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10235 : }
10236 4720 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10237 4720 : pdfDataPct);
10238 : }
10239 :
10240 : /************************************************************************/
10241 : /* IGetDataCoverageStatus() */
10242 : /************************************************************************/
10243 :
10244 687 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10245 : int /*nXSize*/, int /*nYSize*/,
10246 : int /*nMaskFlagStop*/,
10247 : double *pdfDataPct)
10248 : {
10249 687 : if (pdfDataPct != nullptr)
10250 0 : *pdfDataPct = 100.0;
10251 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10252 687 : GDAL_DATA_COVERAGE_STATUS_DATA;
10253 : }
10254 :
10255 : //! @cond Doxygen_Suppress
10256 : /************************************************************************/
10257 : /* EnterReadWrite() */
10258 : /************************************************************************/
10259 :
10260 7808580 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10261 : {
10262 7808580 : if (poDS != nullptr)
10263 7041110 : return poDS->EnterReadWrite(eRWFlag);
10264 767468 : return FALSE;
10265 : }
10266 :
10267 : /************************************************************************/
10268 : /* LeaveReadWrite() */
10269 : /************************************************************************/
10270 :
10271 1131940 : void GDALRasterBand::LeaveReadWrite()
10272 : {
10273 1131940 : if (poDS != nullptr)
10274 1131940 : poDS->LeaveReadWrite();
10275 1131940 : }
10276 :
10277 : /************************************************************************/
10278 : /* InitRWLock() */
10279 : /************************************************************************/
10280 :
10281 3978390 : void GDALRasterBand::InitRWLock()
10282 : {
10283 3978390 : if (poDS != nullptr)
10284 3977990 : poDS->InitRWLock();
10285 3978390 : }
10286 :
10287 : //! @endcond
10288 :
10289 : // clang-format off
10290 :
10291 : /**
10292 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10293 : * \brief Set metadata.
10294 : *
10295 : * CAUTION: depending on the format, older values of the updated information
10296 : * might still be found in the file in a "ghost" state, even if no longer
10297 : * accessible through the GDAL API. This is for example the case of the GTiff
10298 : * format (this is not a exhaustive list)
10299 : *
10300 : * The C function GDALSetMetadata() does the same thing as this method.
10301 : *
10302 : * @param papszMetadata the metadata in name=value string list format to
10303 : * apply.
10304 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10305 : * domain.
10306 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10307 : * metadata has been accepted, but is likely not maintained persistently
10308 : * by the underlying object between sessions.
10309 : */
10310 :
10311 : /**
10312 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10313 : * \brief Set single metadata item.
10314 : *
10315 : * CAUTION: depending on the format, older values of the updated information
10316 : * might still be found in the file in a "ghost" state, even if no longer
10317 : * accessible through the GDAL API. This is for example the case of the GTiff
10318 : * format (this is not a exhaustive list)
10319 : *
10320 : * The C function GDALSetMetadataItem() does the same thing as this method.
10321 : *
10322 : * @param pszName the key for the metadata item to fetch.
10323 : * @param pszValue the value to assign to the key.
10324 : * @param pszDomain the domain to set within, use NULL for the default domain.
10325 : *
10326 : * @return CE_None on success, or an error code on failure.
10327 : */
10328 :
10329 : // clang-format on
10330 :
10331 : //! @cond Doxygen_Suppress
10332 : /************************************************************************/
10333 : /* EnablePixelTypeSignedByteWarning() */
10334 : /************************************************************************/
10335 :
10336 157303 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10337 : {
10338 157303 : m_bEnablePixelTypeSignedByteWarning = b;
10339 157303 : }
10340 :
10341 4910 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10342 : {
10343 4910 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10344 4910 : }
10345 :
10346 : //! @endcond
10347 :
10348 : /************************************************************************/
10349 : /* GetMetadataItem() */
10350 : /************************************************************************/
10351 :
10352 621507 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10353 : const char *pszDomain)
10354 : {
10355 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10356 621507 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10357 462744 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10358 322102 : EQUAL(pszName, "PIXELTYPE"))
10359 : {
10360 2 : CPLError(CE_Warning, CPLE_AppDefined,
10361 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10362 : "used to signal signed 8-bit raster. Change your code to "
10363 : "test for the new GDT_Int8 data type instead.");
10364 : }
10365 621507 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10366 : }
10367 :
10368 : /************************************************************************/
10369 : /* WindowIterator */
10370 : /************************************************************************/
10371 :
10372 : //! @cond Doxygen_Suppress
10373 :
10374 606 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10375 : int nRasterYSize,
10376 : int nBlockXSize, int nBlockYSize,
10377 606 : int nRow, int nCol)
10378 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10379 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10380 606 : m_col(nCol)
10381 : {
10382 606 : }
10383 :
10384 830 : bool GDALRasterBand::WindowIterator::operator==(
10385 : const WindowIterator &other) const
10386 : {
10387 273 : return m_row == other.m_row && m_col == other.m_col &&
10388 273 : m_nRasterXSize == other.m_nRasterXSize &&
10389 273 : m_nRasterYSize == other.m_nRasterYSize &&
10390 1376 : m_nBlockXSize == other.m_nBlockXSize &&
10391 1103 : m_nBlockYSize == other.m_nBlockYSize;
10392 : }
10393 :
10394 804 : bool GDALRasterBand::WindowIterator::operator!=(
10395 : const WindowIterator &other) const
10396 : {
10397 804 : return !(*this == other);
10398 : }
10399 :
10400 : GDALRasterBand::WindowIterator::value_type
10401 556 : GDALRasterBand::WindowIterator::operator*() const
10402 : {
10403 : GDALRasterWindow ret;
10404 556 : ret.nXOff = m_col * m_nBlockXSize;
10405 556 : ret.nYOff = m_row * m_nBlockYSize;
10406 556 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10407 556 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10408 :
10409 556 : return ret;
10410 : }
10411 :
10412 553 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10413 : {
10414 553 : m_col++;
10415 553 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10416 : {
10417 457 : m_col = 0;
10418 457 : m_row++;
10419 : }
10420 553 : return *this;
10421 : }
10422 :
10423 320 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10424 320 : const GDALRasterBand &band, size_t maxSize)
10425 320 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
10426 320 : m_nBlockXSize(-1), m_nBlockYSize(-1)
10427 : {
10428 : #ifdef CSA_BUILD
10429 : assert(this);
10430 : #endif
10431 : int nXSize, nYSize;
10432 :
10433 320 : CPLErrorStateBackuper state(CPLQuietErrorHandler);
10434 320 : band.GetBlockSize(&nXSize, &nYSize);
10435 320 : if (nXSize < 1 || nYSize < 0)
10436 : {
10437 : // If invalid block size is reported, assume scanlines
10438 4 : nXSize = m_nRasterXSize;
10439 4 : nYSize = 1;
10440 : }
10441 :
10442 320 : if (maxSize == 0)
10443 : {
10444 249 : m_nBlockXSize = nXSize;
10445 249 : m_nBlockYSize = nYSize;
10446 249 : return;
10447 : }
10448 :
10449 71 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10450 71 : const double dfBlocksPerChunk =
10451 71 : static_cast<double>(maxSize) /
10452 71 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10453 :
10454 71 : if (dfBlocksPerChunk < dfBlocksPerRow)
10455 : {
10456 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10457 14 : m_nRasterXSize,
10458 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10459 14 : m_nBlockYSize = nYSize;
10460 : }
10461 : else
10462 : {
10463 57 : m_nBlockXSize = m_nRasterXSize;
10464 57 : m_nBlockYSize = static_cast<int>(std::min<double>(
10465 57 : m_nRasterYSize,
10466 57 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10467 : }
10468 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10469 : {
10470 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10471 : {
10472 : nXSize = m_nRasterXSize;
10473 : nYSize = 1;
10474 : }
10475 : }
10476 : }
10477 :
10478 : GDALRasterBand::WindowIterator
10479 289 : GDALRasterBand::WindowIteratorWrapper::begin() const
10480 : {
10481 289 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10482 289 : m_nBlockYSize, 0, 0);
10483 : }
10484 :
10485 : GDALRasterBand::WindowIterator
10486 289 : GDALRasterBand::WindowIteratorWrapper::end() const
10487 : {
10488 289 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10489 289 : m_nBlockYSize,
10490 289 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10491 : }
10492 :
10493 63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10494 : {
10495 63 : return static_cast<uint64_t>(
10496 63 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10497 63 : static_cast<uint64_t>(
10498 63 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10499 : }
10500 :
10501 : //! @endcond
10502 :
10503 : /** Return an object whose begin() and end() methods can be used to iterate
10504 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10505 : * band. The iteration order is from left to right, then from top to bottom.
10506 : *
10507 : \code{.cpp}
10508 : std::vector<double> pixelValues;
10509 : for (const auto& window : poBand->IterateWindows()) {
10510 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10511 : window.nXSize, window.nYSize);
10512 : // check eErr
10513 : }
10514 : \endcode
10515 : *
10516 : *
10517 : * @param maxSize The maximum number of pixels in each window. If set to
10518 : * zero (the default), or a number smaller than the block size,
10519 : * the window size will be the same as the block size.
10520 : * @since GDAL 3.12
10521 : */
10522 : GDALRasterBand::WindowIteratorWrapper
10523 320 : GDALRasterBand::IterateWindows(size_t maxSize) const
10524 : {
10525 320 : return WindowIteratorWrapper(*this, maxSize);
10526 : }
10527 :
10528 : /************************************************************************/
10529 : /* GDALMDArrayFromRasterBand */
10530 : /************************************************************************/
10531 :
10532 : class GDALMDArrayFromRasterBand final : public GDALMDArray
10533 : {
10534 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10535 :
10536 : GDALDataset *m_poDS;
10537 : GDALRasterBand *m_poBand;
10538 : GDALExtendedDataType m_dt;
10539 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10540 : std::string m_osUnit;
10541 : std::vector<GByte> m_pabyNoData{};
10542 : std::shared_ptr<GDALMDArray> m_varX{};
10543 : std::shared_ptr<GDALMDArray> m_varY{};
10544 : std::string m_osFilename{};
10545 :
10546 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10547 : const size_t *count, const GInt64 *arrayStep,
10548 : const GPtrDiff_t *bufferStride,
10549 : const GDALExtendedDataType &bufferDataType,
10550 : void *pBuffer) const;
10551 :
10552 : protected:
10553 34 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10554 68 : : GDALAbstractMDArray(std::string(),
10555 68 : std::string(poDS->GetDescription()) +
10556 : CPLSPrintf(" band %d", poBand->GetBand())),
10557 68 : GDALMDArray(std::string(),
10558 68 : std::string(poDS->GetDescription()) +
10559 : CPLSPrintf(" band %d", poBand->GetBand())),
10560 : m_poDS(poDS), m_poBand(poBand),
10561 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10562 170 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10563 : {
10564 34 : m_poDS->Reference();
10565 :
10566 34 : int bHasNoData = false;
10567 34 : if (m_poBand->GetRasterDataType() == GDT_Int64)
10568 : {
10569 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10570 0 : if (bHasNoData)
10571 : {
10572 0 : m_pabyNoData.resize(m_dt.GetSize());
10573 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10574 : m_dt.GetNumericDataType(), 0, 1);
10575 : }
10576 : }
10577 34 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10578 : {
10579 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10580 0 : if (bHasNoData)
10581 : {
10582 0 : m_pabyNoData.resize(m_dt.GetSize());
10583 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10584 : m_dt.GetNumericDataType(), 0, 1);
10585 : }
10586 : }
10587 : else
10588 : {
10589 34 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10590 34 : if (bHasNoData)
10591 : {
10592 1 : m_pabyNoData.resize(m_dt.GetSize());
10593 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10594 : m_dt.GetNumericDataType(), 0, 1);
10595 : }
10596 : }
10597 :
10598 34 : const int nXSize = poBand->GetXSize();
10599 34 : const int nYSize = poBand->GetYSize();
10600 :
10601 34 : auto poSRS = m_poDS->GetSpatialRef();
10602 68 : std::string osTypeY;
10603 68 : std::string osTypeX;
10604 68 : std::string osDirectionY;
10605 68 : std::string osDirectionX;
10606 34 : if (poSRS && poSRS->GetAxesCount() == 2)
10607 : {
10608 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10609 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
10610 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
10611 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
10612 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
10613 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10614 : {
10615 8 : if (mapping == std::vector<int>{1, 2})
10616 : {
10617 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10618 8 : osDirectionY = "NORTH";
10619 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10620 8 : osDirectionX = "EAST";
10621 : }
10622 : }
10623 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
10624 : {
10625 16 : if (mapping == std::vector<int>{2, 1})
10626 : {
10627 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10628 16 : osDirectionY = "NORTH";
10629 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10630 16 : osDirectionX = "EAST";
10631 : }
10632 : }
10633 : }
10634 :
10635 170 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
10636 : "/", "Y", osTypeY, osDirectionY, nYSize),
10637 68 : std::make_shared<GDALDimensionWeakIndexingVar>(
10638 102 : "/", "X", osTypeX, osDirectionX, nXSize)};
10639 :
10640 34 : GDALGeoTransform gt;
10641 34 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
10642 : {
10643 50 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
10644 50 : gt[0], gt[1], 0.5);
10645 25 : m_dims[1]->SetIndexingVariable(m_varX);
10646 :
10647 50 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
10648 50 : gt[3], gt[5], 0.5);
10649 25 : m_dims[0]->SetIndexingVariable(m_varY);
10650 : }
10651 34 : }
10652 :
10653 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
10654 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10655 : const GDALExtendedDataType &bufferDataType,
10656 : void *pDstBuffer) const override;
10657 :
10658 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
10659 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10660 : const GDALExtendedDataType &bufferDataType,
10661 : const void *pSrcBuffer) override
10662 : {
10663 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
10664 : bufferStride, bufferDataType,
10665 1 : const_cast<void *>(pSrcBuffer));
10666 : }
10667 :
10668 : public:
10669 68 : ~GDALMDArrayFromRasterBand() override
10670 34 : {
10671 34 : m_poDS->ReleaseRef();
10672 68 : }
10673 :
10674 34 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
10675 : GDALRasterBand *poBand)
10676 : {
10677 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
10678 68 : new GDALMDArrayFromRasterBand(poDS, poBand)));
10679 34 : array->SetSelf(array);
10680 68 : return array;
10681 : }
10682 :
10683 5 : bool IsWritable() const override
10684 : {
10685 5 : return m_poDS->GetAccess() == GA_Update;
10686 : }
10687 :
10688 122 : const std::string &GetFilename() const override
10689 : {
10690 122 : return m_osFilename;
10691 : }
10692 :
10693 : const std::vector<std::shared_ptr<GDALDimension>> &
10694 343 : GetDimensions() const override
10695 : {
10696 343 : return m_dims;
10697 : }
10698 :
10699 158 : const GDALExtendedDataType &GetDataType() const override
10700 : {
10701 158 : return m_dt;
10702 : }
10703 :
10704 5 : const std::string &GetUnit() const override
10705 : {
10706 5 : return m_osUnit;
10707 : }
10708 :
10709 32 : const void *GetRawNoDataValue() const override
10710 : {
10711 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
10712 : }
10713 :
10714 4 : double GetOffset(bool *pbHasOffset,
10715 : GDALDataType *peStorageType) const override
10716 : {
10717 4 : int bHasOffset = false;
10718 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
10719 4 : if (pbHasOffset)
10720 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
10721 4 : if (peStorageType)
10722 1 : *peStorageType = GDT_Unknown;
10723 4 : return dfRes;
10724 : }
10725 :
10726 4 : double GetScale(bool *pbHasScale,
10727 : GDALDataType *peStorageType) const override
10728 : {
10729 4 : int bHasScale = false;
10730 4 : double dfRes = m_poBand->GetScale(&bHasScale);
10731 4 : if (pbHasScale)
10732 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
10733 4 : if (peStorageType)
10734 1 : *peStorageType = GDT_Unknown;
10735 4 : return dfRes;
10736 : }
10737 :
10738 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
10739 : {
10740 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
10741 88 : if (!poSrcSRS)
10742 2 : return nullptr;
10743 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
10744 :
10745 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
10746 86 : constexpr int iYDim = 0;
10747 86 : constexpr int iXDim = 1;
10748 258 : for (auto &m : axisMapping)
10749 : {
10750 172 : if (m == 1)
10751 86 : m = iXDim + 1;
10752 86 : else if (m == 2)
10753 86 : m = iYDim + 1;
10754 : else
10755 0 : m = 0;
10756 : }
10757 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
10758 86 : return poSRS;
10759 : }
10760 :
10761 32 : std::vector<GUInt64> GetBlockSize() const override
10762 : {
10763 32 : int nBlockXSize = 0;
10764 32 : int nBlockYSize = 0;
10765 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
10766 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
10767 32 : static_cast<GUInt64>(nBlockXSize)};
10768 : }
10769 :
10770 : std::vector<std::shared_ptr<GDALAttribute>>
10771 23 : GetAttributes(CSLConstList) const override
10772 : {
10773 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
10774 23 : auto papszMD = m_poBand->GetMetadata();
10775 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
10776 : {
10777 2 : char *pszKey = nullptr;
10778 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
10779 2 : if (pszKey && pszValue)
10780 : {
10781 : res.emplace_back(
10782 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
10783 : }
10784 2 : CPLFree(pszKey);
10785 : }
10786 23 : return res;
10787 : }
10788 : };
10789 :
10790 39 : bool GDALMDArrayFromRasterBand::IRead(
10791 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
10792 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
10793 : void *pDstBuffer) const
10794 : {
10795 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
10796 39 : bufferDataType, pDstBuffer);
10797 : }
10798 :
10799 : /************************************************************************/
10800 : /* ReadWrite() */
10801 : /************************************************************************/
10802 :
10803 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
10804 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10805 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10806 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10807 : {
10808 40 : constexpr size_t iDimX = 1;
10809 40 : constexpr size_t iDimY = 0;
10810 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10811 : arrayStartIdx, count, arrayStep, bufferStride,
10812 40 : bufferDataType, pBuffer);
10813 : }
10814 :
10815 : /************************************************************************/
10816 : /* GDALMDRasterIOFromBand() */
10817 : /************************************************************************/
10818 :
10819 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10820 : size_t iDimX, size_t iDimY,
10821 : const GUInt64 *arrayStartIdx, const size_t *count,
10822 : const GInt64 *arrayStep,
10823 : const GPtrDiff_t *bufferStride,
10824 : const GDALExtendedDataType &bufferDataType,
10825 : void *pBuffer)
10826 : {
10827 73 : const auto eDT(bufferDataType.GetNumericDataType());
10828 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10829 73 : const int nX =
10830 73 : arrayStep[iDimX] > 0
10831 73 : ? static_cast<int>(arrayStartIdx[iDimX])
10832 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10833 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10834 73 : const int nY =
10835 73 : arrayStep[iDimY] > 0
10836 73 : ? static_cast<int>(arrayStartIdx[iDimY])
10837 6 : : static_cast<int>(arrayStartIdx[iDimY] -
10838 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10839 73 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10840 73 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10841 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10842 73 : int nStrideXSign = 1;
10843 73 : if (arrayStep[iDimX] < 0)
10844 : {
10845 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10846 2 : nStrideXSign = -1;
10847 : }
10848 73 : int nStrideYSign = 1;
10849 73 : if (arrayStep[iDimY] < 0)
10850 : {
10851 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10852 6 : nStrideYSign = -1;
10853 : }
10854 :
10855 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10856 73 : static_cast<int>(count[iDimX]),
10857 73 : static_cast<int>(count[iDimY]), eDT,
10858 : static_cast<GSpacing>(
10859 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10860 : static_cast<GSpacing>(
10861 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10862 73 : nullptr) == CE_None;
10863 : }
10864 :
10865 : /************************************************************************/
10866 : /* AsMDArray() */
10867 : /************************************************************************/
10868 :
10869 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10870 : *
10871 : * The band must be linked to a GDALDataset. If this dataset is not already
10872 : * marked as shared, it will be, so that the returned array holds a reference
10873 : * to it.
10874 : *
10875 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10876 : * returned array will have an associated indexing variable.
10877 : *
10878 : * This is the same as the C function GDALRasterBandAsMDArray().
10879 : *
10880 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10881 : *
10882 : * @return a new array, or nullptr.
10883 : *
10884 : * @since GDAL 3.1
10885 : */
10886 34 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10887 : {
10888 34 : if (!poDS)
10889 : {
10890 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10891 0 : return nullptr;
10892 : }
10893 34 : if (!poDS->GetShared())
10894 : {
10895 33 : poDS->MarkAsShared();
10896 : }
10897 : return GDALMDArrayFromRasterBand::Create(
10898 34 : poDS, const_cast<GDALRasterBand *>(this));
10899 : }
10900 :
10901 : /************************************************************************/
10902 : /* InterpolateAtPoint() */
10903 : /************************************************************************/
10904 :
10905 : /**
10906 : * \brief Interpolates the value between pixels using a resampling algorithm,
10907 : * taking pixel/line coordinates as input.
10908 : *
10909 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10910 : * @param dfLine line coordinate as a double, where interpolation should be done.
10911 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10912 : * @param pdfRealValue pointer to real part of interpolated value
10913 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10914 : *
10915 : * @return CE_None on success, or an error code on failure.
10916 : * @since GDAL 3.10
10917 : */
10918 :
10919 168 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10920 : GDALRIOResampleAlg eInterpolation,
10921 : double *pdfRealValue,
10922 : double *pdfImagValue) const
10923 : {
10924 168 : if (eInterpolation != GRIORA_NearestNeighbour &&
10925 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10926 : eInterpolation != GRIORA_CubicSpline)
10927 : {
10928 2 : CPLError(CE_Failure, CPLE_AppDefined,
10929 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10930 : "methods "
10931 : "allowed");
10932 :
10933 2 : return CE_Failure;
10934 : }
10935 :
10936 166 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10937 166 : if (!m_poPointsCache)
10938 86 : m_poPointsCache = new GDALDoublePointsCache();
10939 :
10940 : const bool res =
10941 166 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10942 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10943 :
10944 166 : return res ? CE_None : CE_Failure;
10945 : }
10946 :
10947 : /************************************************************************/
10948 : /* GDALRasterInterpolateAtPoint() */
10949 : /************************************************************************/
10950 :
10951 : /**
10952 : * \brief Interpolates the value between pixels using
10953 : * a resampling algorithm
10954 : *
10955 : * @see GDALRasterBand::InterpolateAtPoint()
10956 : * @since GDAL 3.10
10957 : */
10958 :
10959 145 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10960 : double dfLine,
10961 : GDALRIOResampleAlg eInterpolation,
10962 : double *pdfRealValue, double *pdfImagValue)
10963 : {
10964 145 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10965 :
10966 145 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10967 145 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10968 145 : pdfRealValue, pdfImagValue);
10969 : }
10970 :
10971 : /************************************************************************/
10972 : /* InterpolateAtGeolocation() */
10973 : /************************************************************************/
10974 :
10975 : /**
10976 : * \brief Interpolates the value between pixels using a resampling algorithm,
10977 : * taking georeferenced coordinates as input.
10978 : *
10979 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10980 : * must be in the "natural" SRS of the dataset, that is the one returned by
10981 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10982 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10983 : * array (generally WGS 84) if there is a geolocation array.
10984 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10985 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10986 : * be a easting, and dfGeolocY a northing.
10987 : *
10988 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10989 : * expressed in that CRS, and that tuple must be conformant with the
10990 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10991 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10992 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10993 : * before calling this method, and in that case, dfGeolocX must be a longitude
10994 : * or an easting value, and dfGeolocX a latitude or a northing value.
10995 : *
10996 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10997 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10998 : * it for details on how that transformation is done.
10999 : *
11000 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11001 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11002 : * where interpolation should be done.
11003 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11004 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11005 : * where interpolation should be done.
11006 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11007 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11008 : * @param pdfRealValue pointer to real part of interpolated value
11009 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11010 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11011 : *
11012 : * @return CE_None on success, or an error code on failure.
11013 : * @since GDAL 3.11
11014 : */
11015 :
11016 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11017 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11018 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11019 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11020 : {
11021 : double dfPixel;
11022 : double dfLine;
11023 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11024 : &dfLine,
11025 15 : papszTransformerOptions) != CE_None)
11026 : {
11027 1 : return CE_Failure;
11028 : }
11029 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11030 14 : pdfImagValue);
11031 : }
11032 :
11033 : /************************************************************************/
11034 : /* GDALRasterInterpolateAtGeolocation() */
11035 : /************************************************************************/
11036 :
11037 : /**
11038 : * \brief Interpolates the value between pixels using a resampling algorithm,
11039 : * taking georeferenced coordinates as input.
11040 : *
11041 : * @see GDALRasterBand::InterpolateAtGeolocation()
11042 : * @since GDAL 3.11
11043 : */
11044 :
11045 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11046 : double dfGeolocX, double dfGeolocY,
11047 : OGRSpatialReferenceH hSRS,
11048 : GDALRIOResampleAlg eInterpolation,
11049 : double *pdfRealValue,
11050 : double *pdfImagValue,
11051 : CSLConstList papszTransformerOptions)
11052 : {
11053 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11054 :
11055 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11056 15 : return poBand->InterpolateAtGeolocation(
11057 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11058 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11059 : }
11060 :
11061 : /************************************************************************/
11062 : /* GDALRasterBand::SplitRasterIO() */
11063 : /************************************************************************/
11064 :
11065 : //! @cond Doxygen_Suppress
11066 :
11067 : /** Implements IRasterIO() by dividing the request in 2.
11068 : *
11069 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11070 : *
11071 : * Return CE_Warning if the split could not be done, CE_None in case of
11072 : * success and CE_Failure in case of error.
11073 : *
11074 : * @since 3.12
11075 : */
11076 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11077 : [[maybe_unused]] int nXSize,
11078 : [[maybe_unused]] int nYSize, void *pData,
11079 : int nBufXSize, int nBufYSize,
11080 : GDALDataType eBufType,
11081 : GSpacing nPixelSpace, GSpacing nLineSpace,
11082 : GDALRasterIOExtraArg *psExtraArg)
11083 : {
11084 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11085 :
11086 999 : GByte *pabyData = static_cast<GByte *>(pData);
11087 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11088 : {
11089 : GDALRasterIOExtraArg sArg;
11090 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11091 499 : const int nHalfHeight = nBufYSize / 2;
11092 :
11093 499 : sArg.pfnProgress = GDALScaledProgress;
11094 499 : sArg.pProgressData = GDALCreateScaledProgress(
11095 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11096 499 : if (sArg.pProgressData == nullptr)
11097 499 : sArg.pfnProgress = nullptr;
11098 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11099 : pabyData, nBufXSize, nHalfHeight, eBufType,
11100 499 : nPixelSpace, nLineSpace, &sArg);
11101 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11102 :
11103 499 : if (eErr == CE_None)
11104 : {
11105 499 : sArg.pfnProgress = GDALScaledProgress;
11106 499 : sArg.pProgressData = GDALCreateScaledProgress(
11107 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11108 499 : if (sArg.pProgressData == nullptr)
11109 499 : sArg.pfnProgress = nullptr;
11110 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11111 : nBufYSize - nHalfHeight,
11112 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11113 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11114 499 : nLineSpace, &sArg);
11115 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11116 : }
11117 499 : return eErr;
11118 : }
11119 500 : else if (nBufXSize >= 2)
11120 : {
11121 : GDALRasterIOExtraArg sArg;
11122 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11123 500 : const int nHalfWidth = nBufXSize / 2;
11124 :
11125 500 : sArg.pfnProgress = GDALScaledProgress;
11126 500 : sArg.pProgressData = GDALCreateScaledProgress(
11127 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11128 500 : if (sArg.pProgressData == nullptr)
11129 500 : sArg.pfnProgress = nullptr;
11130 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11131 : pabyData, nHalfWidth, nBufYSize, eBufType,
11132 500 : nPixelSpace, nLineSpace, &sArg);
11133 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11134 :
11135 500 : if (eErr == CE_None)
11136 : {
11137 500 : sArg.pfnProgress = GDALScaledProgress;
11138 500 : sArg.pProgressData = GDALCreateScaledProgress(
11139 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11140 500 : if (sArg.pProgressData == nullptr)
11141 500 : sArg.pfnProgress = nullptr;
11142 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11143 : nBufXSize - nHalfWidth, nBufYSize,
11144 500 : pabyData + nHalfWidth * nPixelSpace,
11145 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11146 500 : nPixelSpace, nLineSpace, &sArg);
11147 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11148 : }
11149 500 : return eErr;
11150 : }
11151 :
11152 0 : return CE_Warning;
11153 : }
11154 :
11155 : //! @endcond
11156 :
11157 : /************************************************************************/
11158 : /* ThrowIfNotSameDimensions() */
11159 : /************************************************************************/
11160 :
11161 : //! @cond Doxygen_Suppress
11162 : /* static */
11163 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11164 : const GDALRasterBand &second)
11165 : {
11166 320 : if (first.GetXSize() != second.GetXSize() ||
11167 151 : first.GetYSize() != second.GetYSize())
11168 : {
11169 36 : throw std::runtime_error("Bands do not have the same dimensions");
11170 : }
11171 133 : }
11172 :
11173 : //! @endcond
11174 :
11175 : /************************************************************************/
11176 : /* GDALRasterBandUnaryOp() */
11177 : /************************************************************************/
11178 :
11179 : /** Apply a unary operation on this band.
11180 : *
11181 : * The resulting band is lazy evaluated. A reference is taken on the input
11182 : * dataset.
11183 : *
11184 : * @since 3.12
11185 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11186 : */
11187 : GDALComputedRasterBandH
11188 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11189 : GDALRasterAlgebraUnaryOperation eOp)
11190 : {
11191 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11192 6 : GDALComputedRasterBand::Operation cppOp{};
11193 6 : switch (eOp)
11194 : {
11195 2 : case GRAUO_LOGICAL_NOT:
11196 : return new GDALComputedRasterBand(
11197 : GDALComputedRasterBand::Operation::OP_NE,
11198 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11199 1 : case GRAUO_ABS:
11200 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11201 1 : break;
11202 1 : case GRAUO_SQRT:
11203 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11204 1 : break;
11205 1 : case GRAUO_LOG:
11206 : #ifndef HAVE_MUPARSER
11207 : CPLError(
11208 : CE_Failure, CPLE_NotSupported,
11209 : "log(band) not available on a GDAL build without muparser");
11210 : return nullptr;
11211 : #else
11212 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11213 1 : break;
11214 : #endif
11215 1 : case GRAUO_LOG10:
11216 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11217 1 : break;
11218 : }
11219 : return new GDALComputedRasterBand(cppOp,
11220 4 : *(GDALRasterBand::FromHandle(hBand)));
11221 : }
11222 :
11223 : /************************************************************************/
11224 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11225 : /************************************************************************/
11226 :
11227 : static GDALComputedRasterBand::Operation
11228 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11229 : GDALRasterAlgebraBinaryOperation eOp)
11230 : {
11231 120 : switch (eOp)
11232 : {
11233 26 : case GRABO_ADD:
11234 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11235 2 : case GRABO_SUB:
11236 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11237 24 : case GRABO_MUL:
11238 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11239 3 : case GRABO_DIV:
11240 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11241 6 : case GRABO_GT:
11242 6 : return GDALComputedRasterBand::Operation::OP_GT;
11243 8 : case GRABO_GE:
11244 8 : return GDALComputedRasterBand::Operation::OP_GE;
11245 6 : case GRABO_LT:
11246 6 : return GDALComputedRasterBand::Operation::OP_LT;
11247 6 : case GRABO_LE:
11248 6 : return GDALComputedRasterBand::Operation::OP_LE;
11249 6 : case GRABO_EQ:
11250 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11251 6 : case GRABO_NE:
11252 6 : break;
11253 12 : case GRABO_LOGICAL_AND:
11254 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11255 12 : case GRABO_LOGICAL_OR:
11256 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11257 3 : case GRABO_POW:
11258 3 : return GDALComputedRasterBand::Operation::OP_POW;
11259 : }
11260 6 : return GDALComputedRasterBand::Operation::OP_NE;
11261 : }
11262 :
11263 : /************************************************************************/
11264 : /* GDALRasterBandBinaryOpBand() */
11265 : /************************************************************************/
11266 :
11267 : /** Apply a binary operation on this band with another one.
11268 : *
11269 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11270 : * "hBand1 - hBand2".
11271 : *
11272 : * The resulting band is lazy evaluated. A reference is taken on both input
11273 : * datasets.
11274 : *
11275 : * @since 3.12
11276 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11277 : */
11278 : GDALComputedRasterBandH
11279 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11280 : GDALRasterAlgebraBinaryOperation eOp,
11281 : GDALRasterBandH hOtherBand)
11282 : {
11283 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11284 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11285 : #ifndef HAVE_MUPARSER
11286 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11287 : {
11288 : CPLError(
11289 : CE_Failure, CPLE_NotSupported,
11290 : "Band comparison operators not available on a GDAL build without "
11291 : "muparser");
11292 : return nullptr;
11293 : }
11294 : else if (eOp == GRABO_POW)
11295 : {
11296 : CPLError(
11297 : CE_Failure, CPLE_NotSupported,
11298 : "pow(band, band) not available on a GDAL build without muparser");
11299 : return nullptr;
11300 : }
11301 : #endif
11302 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11303 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11304 : try
11305 : {
11306 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11307 : }
11308 13 : catch (const std::exception &e)
11309 : {
11310 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11311 13 : return nullptr;
11312 : }
11313 : return new GDALComputedRasterBand(
11314 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11315 44 : secondBand);
11316 : }
11317 :
11318 : /************************************************************************/
11319 : /* GDALRasterBandBinaryOpDouble() */
11320 : /************************************************************************/
11321 :
11322 : /** Apply a binary operation on this band with a constant
11323 : *
11324 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11325 : * "hBand - constant".
11326 : *
11327 : * The resulting band is lazy evaluated. A reference is taken on the input
11328 : * dataset.
11329 : *
11330 : * @since 3.12
11331 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11332 : */
11333 : GDALComputedRasterBandH
11334 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11335 : GDALRasterAlgebraBinaryOperation eOp,
11336 : double constant)
11337 : {
11338 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11339 : #ifndef HAVE_MUPARSER
11340 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11341 : {
11342 : CPLError(
11343 : CE_Failure, CPLE_NotSupported,
11344 : "Band comparison operators not available on a GDAL build without "
11345 : "muparser");
11346 : return nullptr;
11347 : }
11348 : #endif
11349 : return new GDALComputedRasterBand(
11350 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11351 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11352 : }
11353 :
11354 : /************************************************************************/
11355 : /* GDALRasterBandBinaryOpDoubleToBand() */
11356 : /************************************************************************/
11357 :
11358 : /** Apply a binary operation on the constant with this band
11359 : *
11360 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11361 : * "constant - hBand".
11362 : *
11363 : * The resulting band is lazy evaluated. A reference is taken on the input
11364 : * dataset.
11365 : *
11366 : * @since 3.12
11367 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11368 : */
11369 : GDALComputedRasterBandH
11370 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11371 : GDALRasterAlgebraBinaryOperation eOp,
11372 : GDALRasterBandH hBand)
11373 : {
11374 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11375 : #ifndef HAVE_MUPARSER
11376 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11377 : {
11378 : CPLError(
11379 : CE_Failure, CPLE_NotSupported,
11380 : "Band comparison operators not available on a GDAL build without "
11381 : "muparser");
11382 : return nullptr;
11383 : }
11384 : #endif
11385 18 : switch (eOp)
11386 : {
11387 15 : case GRABO_ADD:
11388 : case GRABO_MUL:
11389 : {
11390 : return new GDALComputedRasterBand(
11391 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11392 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11393 : }
11394 :
11395 2 : case GRABO_DIV:
11396 : case GRABO_GT:
11397 : case GRABO_GE:
11398 : case GRABO_LT:
11399 : case GRABO_LE:
11400 : case GRABO_EQ:
11401 : case GRABO_NE:
11402 : case GRABO_LOGICAL_AND:
11403 : case GRABO_LOGICAL_OR:
11404 : case GRABO_POW:
11405 : {
11406 : return new GDALComputedRasterBand(
11407 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11408 2 : *(GDALRasterBand::FromHandle(hBand)));
11409 : }
11410 :
11411 1 : case GRABO_SUB:
11412 : {
11413 1 : break;
11414 : }
11415 : }
11416 :
11417 : return new GDALComputedRasterBand(
11418 : GDALComputedRasterBand::Operation::OP_ADD,
11419 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11420 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11421 1 : constant);
11422 : }
11423 :
11424 : /************************************************************************/
11425 : /* operator+() */
11426 : /************************************************************************/
11427 :
11428 : /** Add this band with another one.
11429 : *
11430 : * The resulting band is lazy evaluated. A reference is taken on both input
11431 : * datasets.
11432 : *
11433 : * @since 3.12
11434 : * @throw std::runtime_error if both bands do not have the same dimensions.
11435 : */
11436 : GDALComputedRasterBand
11437 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11438 : {
11439 8 : ThrowIfNotSameDimensions(*this, other);
11440 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11441 7 : *this, other);
11442 : }
11443 :
11444 : /************************************************************************/
11445 : /* operator+() */
11446 : /************************************************************************/
11447 :
11448 : /** Add this band with a constant.
11449 : *
11450 : * The resulting band is lazy evaluated. A reference is taken on the input
11451 : * dataset.
11452 : *
11453 : * @since 3.12
11454 : */
11455 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11456 : {
11457 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11458 13 : *this, constant);
11459 : }
11460 :
11461 : /************************************************************************/
11462 : /* operator+() */
11463 : /************************************************************************/
11464 :
11465 : /** Add a band with a constant.
11466 : *
11467 : * The resulting band is lazy evaluated. A reference is taken on the input
11468 : * dataset.
11469 : *
11470 : * @since 3.12
11471 : */
11472 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11473 : {
11474 1 : return other + constant;
11475 : }
11476 :
11477 : /************************************************************************/
11478 : /* operator-() */
11479 : /************************************************************************/
11480 :
11481 : /** Return a band whose value is the opposite value of the band for each
11482 : * pixel.
11483 : *
11484 : * The resulting band is lazy evaluated. A reference is taken on the input
11485 : * dataset.
11486 : *
11487 : * @since 3.12
11488 : */
11489 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
11490 : {
11491 2 : return 0 - *this;
11492 : }
11493 :
11494 : /************************************************************************/
11495 : /* operator-() */
11496 : /************************************************************************/
11497 :
11498 : /** Subtract this band with another one.
11499 : *
11500 : * The resulting band is lazy evaluated. A reference is taken on both input
11501 : * datasets.
11502 : *
11503 : * @since 3.12
11504 : * @throw std::runtime_error if both bands do not have the same dimensions.
11505 : */
11506 : GDALComputedRasterBand
11507 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
11508 : {
11509 2 : ThrowIfNotSameDimensions(*this, other);
11510 : return GDALComputedRasterBand(
11511 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11512 : }
11513 :
11514 : /************************************************************************/
11515 : /* operator-() */
11516 : /************************************************************************/
11517 :
11518 : /** Subtract this band with a constant.
11519 : *
11520 : * The resulting band is lazy evaluated. A reference is taken on the input
11521 : * dataset.
11522 : *
11523 : * @since 3.12
11524 : */
11525 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11526 : {
11527 : return GDALComputedRasterBand(
11528 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11529 : }
11530 :
11531 : /************************************************************************/
11532 : /* operator-() */
11533 : /************************************************************************/
11534 :
11535 : /** Subtract a constant with a band.
11536 : *
11537 : * The resulting band is lazy evaluated. A reference is taken on the input
11538 : * dataset.
11539 : *
11540 : * @since 3.12
11541 : */
11542 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11543 : {
11544 6 : return other * (-1.0) + constant;
11545 : }
11546 :
11547 : /************************************************************************/
11548 : /* operator*() */
11549 : /************************************************************************/
11550 :
11551 : /** Multiply this band with another one.
11552 : *
11553 : * The resulting band is lazy evaluated. A reference is taken on both input
11554 : * datasets.
11555 : *
11556 : * @since 3.12
11557 : * @throw std::runtime_error if both bands do not have the same dimensions.
11558 : */
11559 : GDALComputedRasterBand
11560 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
11561 : {
11562 2 : ThrowIfNotSameDimensions(*this, other);
11563 : return GDALComputedRasterBand(
11564 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11565 : }
11566 :
11567 : /************************************************************************/
11568 : /* operator*() */
11569 : /************************************************************************/
11570 :
11571 : /** Multiply this band by a constant.
11572 : *
11573 : * The resulting band is lazy evaluated. A reference is taken on the input
11574 : * dataset.
11575 : *
11576 : * @since 3.12
11577 : */
11578 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11579 : {
11580 : return GDALComputedRasterBand(
11581 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11582 : }
11583 :
11584 : /************************************************************************/
11585 : /* operator*() */
11586 : /************************************************************************/
11587 :
11588 : /** Multiply a band with a constant.
11589 : *
11590 : * The resulting band is lazy evaluated. A reference is taken on the input
11591 : * dataset.
11592 : *
11593 : * @since 3.12
11594 : */
11595 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
11596 : {
11597 2 : return other * constant;
11598 : }
11599 :
11600 : /************************************************************************/
11601 : /* operator/() */
11602 : /************************************************************************/
11603 :
11604 : /** Divide this band with another one.
11605 : *
11606 : * The resulting band is lazy evaluated. A reference is taken on both input
11607 : * datasets.
11608 : *
11609 : * @since 3.12
11610 : * @throw std::runtime_error if both bands do not have the same dimensions.
11611 : */
11612 : GDALComputedRasterBand
11613 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
11614 : {
11615 2 : ThrowIfNotSameDimensions(*this, other);
11616 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11617 2 : *this, other);
11618 : }
11619 :
11620 : /************************************************************************/
11621 : /* operator/() */
11622 : /************************************************************************/
11623 :
11624 : /** Divide this band by a constant.
11625 : *
11626 : * The resulting band is lazy evaluated. A reference is taken on the input
11627 : * dataset.
11628 : *
11629 : * @since 3.12
11630 : */
11631 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
11632 : {
11633 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11634 0 : *this, constant);
11635 : }
11636 :
11637 : /************************************************************************/
11638 : /* operator/() */
11639 : /************************************************************************/
11640 :
11641 : /** Divide a constant by a band.
11642 : *
11643 : * The resulting band is lazy evaluated. A reference is taken on the input
11644 : * dataset.
11645 : *
11646 : * @since 3.12
11647 : */
11648 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
11649 : {
11650 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11651 1 : constant, other);
11652 : }
11653 :
11654 : /************************************************************************/
11655 : /* ThrowIfNotMuparser() */
11656 : /************************************************************************/
11657 :
11658 : #ifndef HAVE_MUPARSER
11659 : static GDALComputedRasterBand ThrowIfNotMuparser()
11660 : {
11661 : throw std::runtime_error("Operator not available on a "
11662 : "GDAL build without muparser");
11663 : }
11664 : #endif
11665 :
11666 : /************************************************************************/
11667 : /* operator>() */
11668 : /************************************************************************/
11669 :
11670 : /** Return a band whose value is 1 if the pixel value of the left operand
11671 : * is greater than the pixel value of the right operand.
11672 : *
11673 : * The resulting band is lazy evaluated. A reference is taken on the input
11674 : * dataset.
11675 : *
11676 : * @since 3.12
11677 : */
11678 : GDALComputedRasterBand
11679 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
11680 : {
11681 : #ifndef HAVE_MUPARSER
11682 : (void)other;
11683 : return ThrowIfNotMuparser();
11684 : #else
11685 3 : ThrowIfNotSameDimensions(*this, other);
11686 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11687 2 : *this, other);
11688 : #endif
11689 : }
11690 :
11691 : /************************************************************************/
11692 : /* operator>() */
11693 : /************************************************************************/
11694 :
11695 : /** Return a band whose value is 1 if the pixel value of the left operand
11696 : * is greater than the constant.
11697 : *
11698 : * The resulting band is lazy evaluated. A reference is taken on the input
11699 : * dataset.
11700 : *
11701 : * @since 3.12
11702 : */
11703 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
11704 : {
11705 : #ifndef HAVE_MUPARSER
11706 : (void)constant;
11707 : return ThrowIfNotMuparser();
11708 : #else
11709 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11710 3 : *this, constant);
11711 : #endif
11712 : }
11713 :
11714 : /************************************************************************/
11715 : /* operator>() */
11716 : /************************************************************************/
11717 :
11718 : /** Return a band whose value is 1 if the constant is greater than the pixel
11719 : * value of the right operand.
11720 : *
11721 : * The resulting band is lazy evaluated. A reference is taken on the input
11722 : * dataset.
11723 : *
11724 : * @since 3.12
11725 : */
11726 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
11727 : {
11728 : #ifndef HAVE_MUPARSER
11729 : (void)constant;
11730 : (void)other;
11731 : return ThrowIfNotMuparser();
11732 : #else
11733 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11734 2 : constant, other);
11735 : #endif
11736 : }
11737 :
11738 : /************************************************************************/
11739 : /* operator>=() */
11740 : /************************************************************************/
11741 :
11742 : /** Return a band whose value is 1 if the pixel value of the left operand
11743 : * is greater or equal to the pixel value of the right operand.
11744 : *
11745 : * The resulting band is lazy evaluated. A reference is taken on the input
11746 : * dataset.
11747 : *
11748 : * @since 3.12
11749 : */
11750 : GDALComputedRasterBand
11751 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
11752 : {
11753 : #ifndef HAVE_MUPARSER
11754 : (void)other;
11755 : return ThrowIfNotMuparser();
11756 : #else
11757 4 : ThrowIfNotSameDimensions(*this, other);
11758 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11759 3 : *this, other);
11760 : #endif
11761 : }
11762 :
11763 : /************************************************************************/
11764 : /* operator>=() */
11765 : /************************************************************************/
11766 :
11767 : /** Return a band whose value is 1 if the pixel value of the left operand
11768 : * is greater or equal to the constant.
11769 : *
11770 : * The resulting band is lazy evaluated. A reference is taken on the input
11771 : * dataset.
11772 : *
11773 : * @since 3.12
11774 : */
11775 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
11776 : {
11777 : #ifndef HAVE_MUPARSER
11778 : (void)constant;
11779 : return ThrowIfNotMuparser();
11780 : #else
11781 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11782 3 : *this, constant);
11783 : #endif
11784 : }
11785 :
11786 : /************************************************************************/
11787 : /* operator>=() */
11788 : /************************************************************************/
11789 :
11790 : /** Return a band whose value is 1 if the constant is greater or equal to
11791 : * the pixel value of the right operand.
11792 : *
11793 : * The resulting band is lazy evaluated. A reference is taken on the input
11794 : * dataset.
11795 : *
11796 : * @since 3.12
11797 : */
11798 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
11799 : {
11800 : #ifndef HAVE_MUPARSER
11801 : (void)constant;
11802 : (void)other;
11803 : return ThrowIfNotMuparser();
11804 : #else
11805 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11806 2 : constant, other);
11807 : #endif
11808 : }
11809 :
11810 : /************************************************************************/
11811 : /* operator<() */
11812 : /************************************************************************/
11813 :
11814 : /** Return a band whose value is 1 if the pixel value of the left operand
11815 : * is lesser than the pixel value of the right operand.
11816 : *
11817 : * The resulting band is lazy evaluated. A reference is taken on the input
11818 : * dataset.
11819 : *
11820 : * @since 3.12
11821 : */
11822 : GDALComputedRasterBand
11823 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
11824 : {
11825 : #ifndef HAVE_MUPARSER
11826 : (void)other;
11827 : return ThrowIfNotMuparser();
11828 : #else
11829 3 : ThrowIfNotSameDimensions(*this, other);
11830 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11831 2 : *this, other);
11832 : #endif
11833 : }
11834 :
11835 : /************************************************************************/
11836 : /* operator<() */
11837 : /************************************************************************/
11838 :
11839 : /** Return a band whose value is 1 if the pixel value of the left operand
11840 : * is lesser than the constant.
11841 : *
11842 : * The resulting band is lazy evaluated. A reference is taken on the input
11843 : * dataset.
11844 : *
11845 : * @since 3.12
11846 : */
11847 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11848 : {
11849 : #ifndef HAVE_MUPARSER
11850 : (void)constant;
11851 : return ThrowIfNotMuparser();
11852 : #else
11853 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11854 3 : *this, constant);
11855 : #endif
11856 : }
11857 :
11858 : /************************************************************************/
11859 : /* operator<() */
11860 : /************************************************************************/
11861 :
11862 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11863 : * value of the right operand.
11864 : *
11865 : * The resulting band is lazy evaluated. A reference is taken on the input
11866 : * dataset.
11867 : *
11868 : * @since 3.12
11869 : */
11870 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11871 : {
11872 : #ifndef HAVE_MUPARSER
11873 : (void)constant;
11874 : (void)other;
11875 : return ThrowIfNotMuparser();
11876 : #else
11877 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11878 2 : constant, other);
11879 : #endif
11880 : }
11881 :
11882 : /************************************************************************/
11883 : /* operator<=() */
11884 : /************************************************************************/
11885 :
11886 : /** Return a band whose value is 1 if the pixel value of the left operand
11887 : * is lesser or equal to the pixel value of the right operand.
11888 : *
11889 : * The resulting band is lazy evaluated. A reference is taken on the input
11890 : * dataset.
11891 : *
11892 : * @since 3.12
11893 : */
11894 : GDALComputedRasterBand
11895 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11896 : {
11897 : #ifndef HAVE_MUPARSER
11898 : (void)other;
11899 : return ThrowIfNotMuparser();
11900 : #else
11901 4 : ThrowIfNotSameDimensions(*this, other);
11902 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11903 3 : *this, other);
11904 : #endif
11905 : }
11906 :
11907 : /************************************************************************/
11908 : /* operator<=() */
11909 : /************************************************************************/
11910 :
11911 : /** Return a band whose value is 1 if the pixel value of the left operand
11912 : * is lesser or equal to the constant.
11913 : *
11914 : * The resulting band is lazy evaluated. A reference is taken on the input
11915 : * dataset.
11916 : *
11917 : * @since 3.12
11918 : */
11919 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11920 : {
11921 : #ifndef HAVE_MUPARSER
11922 : (void)constant;
11923 : return ThrowIfNotMuparser();
11924 : #else
11925 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11926 3 : *this, constant);
11927 : #endif
11928 : }
11929 :
11930 : /************************************************************************/
11931 : /* operator<=() */
11932 : /************************************************************************/
11933 :
11934 : /** Return a band whose value is 1 if the constant is lesser or equal to
11935 : * the pixel value of the right operand.
11936 : *
11937 : * The resulting band is lazy evaluated. A reference is taken on the input
11938 : * dataset.
11939 : *
11940 : * @since 3.12
11941 : */
11942 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11943 : {
11944 : #ifndef HAVE_MUPARSER
11945 : (void)constant;
11946 : (void)other;
11947 : return ThrowIfNotMuparser();
11948 : #else
11949 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11950 2 : constant, other);
11951 : #endif
11952 : }
11953 :
11954 : /************************************************************************/
11955 : /* operator==() */
11956 : /************************************************************************/
11957 :
11958 : /** Return a band whose value is 1 if the pixel value of the left operand
11959 : * is equal to the pixel value of the right operand.
11960 : *
11961 : * The resulting band is lazy evaluated. A reference is taken on the input
11962 : * dataset.
11963 : *
11964 : * @since 3.12
11965 : */
11966 : GDALComputedRasterBand
11967 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11968 : {
11969 : #ifndef HAVE_MUPARSER
11970 : (void)other;
11971 : return ThrowIfNotMuparser();
11972 : #else
11973 3 : ThrowIfNotSameDimensions(*this, other);
11974 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11975 2 : *this, other);
11976 : #endif
11977 : }
11978 :
11979 : /************************************************************************/
11980 : /* operator==() */
11981 : /************************************************************************/
11982 :
11983 : /** Return a band whose value is 1 if the pixel value of the left operand
11984 : * is equal to the constant.
11985 : *
11986 : * The resulting band is lazy evaluated. A reference is taken on the input
11987 : * dataset.
11988 : *
11989 : * @since 3.12
11990 : */
11991 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11992 : {
11993 : #ifndef HAVE_MUPARSER
11994 : (void)constant;
11995 : return ThrowIfNotMuparser();
11996 : #else
11997 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11998 8 : *this, constant);
11999 : #endif
12000 : }
12001 :
12002 : /************************************************************************/
12003 : /* operator==() */
12004 : /************************************************************************/
12005 :
12006 : /** Return a band whose value is 1 if the constant is equal to
12007 : * the pixel value of the right operand.
12008 : *
12009 : * The resulting band is lazy evaluated. A reference is taken on the input
12010 : * dataset.
12011 : *
12012 : * @since 3.12
12013 : */
12014 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12015 : {
12016 : #ifndef HAVE_MUPARSER
12017 : (void)constant;
12018 : (void)other;
12019 : return ThrowIfNotMuparser();
12020 : #else
12021 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12022 2 : constant, other);
12023 : #endif
12024 : }
12025 :
12026 : /************************************************************************/
12027 : /* operator!=() */
12028 : /************************************************************************/
12029 :
12030 : /** Return a band whose value is 1 if the pixel value of the left operand
12031 : * is different from the pixel value of the right operand.
12032 : *
12033 : * The resulting band is lazy evaluated. A reference is taken on the input
12034 : * dataset.
12035 : *
12036 : * @since 3.12
12037 : */
12038 : GDALComputedRasterBand
12039 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12040 : {
12041 : #ifndef HAVE_MUPARSER
12042 : (void)other;
12043 : return ThrowIfNotMuparser();
12044 : #else
12045 3 : ThrowIfNotSameDimensions(*this, other);
12046 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12047 2 : *this, other);
12048 : #endif
12049 : }
12050 :
12051 : /************************************************************************/
12052 : /* operator!=() */
12053 : /************************************************************************/
12054 :
12055 : /** Return a band whose value is 1 if the pixel value of the left operand
12056 : * is different from the constant.
12057 : *
12058 : * The resulting band is lazy evaluated. A reference is taken on the input
12059 : * dataset.
12060 : *
12061 : * @since 3.12
12062 : */
12063 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12064 : {
12065 : #ifndef HAVE_MUPARSER
12066 : (void)constant;
12067 : return ThrowIfNotMuparser();
12068 : #else
12069 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12070 6 : *this, constant);
12071 : #endif
12072 : }
12073 :
12074 : /************************************************************************/
12075 : /* operator!=() */
12076 : /************************************************************************/
12077 :
12078 : /** Return a band whose value is 1 if the constant is different from
12079 : * the pixel value of the right operand.
12080 : *
12081 : * The resulting band is lazy evaluated. A reference is taken on the input
12082 : * dataset.
12083 : *
12084 : * @since 3.12
12085 : */
12086 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12087 : {
12088 : #ifndef HAVE_MUPARSER
12089 : (void)constant;
12090 : (void)other;
12091 : return ThrowIfNotMuparser();
12092 : #else
12093 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12094 2 : constant, other);
12095 : #endif
12096 : }
12097 :
12098 : #if defined(__GNUC__)
12099 : #pragma GCC diagnostic push
12100 : #pragma GCC diagnostic ignored "-Weffc++"
12101 : #endif
12102 :
12103 : /************************************************************************/
12104 : /* operator&&() */
12105 : /************************************************************************/
12106 :
12107 : /** Return a band whose value is 1 if the pixel value of the left and right
12108 : * operands is true.
12109 : *
12110 : * The resulting band is lazy evaluated. A reference is taken on the input
12111 : * dataset.
12112 : *
12113 : * @since 3.12
12114 : */
12115 : GDALComputedRasterBand
12116 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12117 : {
12118 : #ifndef HAVE_MUPARSER
12119 : (void)other;
12120 : return ThrowIfNotMuparser();
12121 : #else
12122 3 : ThrowIfNotSameDimensions(*this, other);
12123 : return GDALComputedRasterBand(
12124 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12125 : #endif
12126 : }
12127 :
12128 : /************************************************************************/
12129 : /* operator&&() */
12130 : /************************************************************************/
12131 :
12132 : /** Return a band whose value is 1 if the pixel value of the left operand
12133 : * is true, as well as the constant
12134 : *
12135 : * The resulting band is lazy evaluated. A reference is taken on the input
12136 : * dataset.
12137 : *
12138 : * @since 3.12
12139 : */
12140 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12141 : {
12142 : #ifndef HAVE_MUPARSER
12143 : (void)constant;
12144 : return ThrowIfNotMuparser();
12145 : #else
12146 : return GDALComputedRasterBand(
12147 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12148 : #endif
12149 : }
12150 :
12151 : /************************************************************************/
12152 : /* operator&&() */
12153 : /************************************************************************/
12154 :
12155 : /** Return a band whose value is 1 if the constant is true, as well as
12156 : * the pixel value of the right operand.
12157 : *
12158 : * The resulting band is lazy evaluated. A reference is taken on the input
12159 : * dataset.
12160 : *
12161 : * @since 3.12
12162 : */
12163 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12164 : {
12165 : #ifndef HAVE_MUPARSER
12166 : (void)constant;
12167 : (void)other;
12168 : return ThrowIfNotMuparser();
12169 : #else
12170 : return GDALComputedRasterBand(
12171 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12172 : #endif
12173 : }
12174 :
12175 : /************************************************************************/
12176 : /* operator||() */
12177 : /************************************************************************/
12178 :
12179 : /** Return a band whose value is 1 if the pixel value of the left or right
12180 : * operands is true.
12181 : *
12182 : * The resulting band is lazy evaluated. A reference is taken on the input
12183 : * dataset.
12184 : *
12185 : * @since 3.12
12186 : */
12187 : GDALComputedRasterBand
12188 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12189 : {
12190 : #ifndef HAVE_MUPARSER
12191 : (void)other;
12192 : return ThrowIfNotMuparser();
12193 : #else
12194 4 : ThrowIfNotSameDimensions(*this, other);
12195 : return GDALComputedRasterBand(
12196 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12197 : #endif
12198 : }
12199 :
12200 : /************************************************************************/
12201 : /* operator||() */
12202 : /************************************************************************/
12203 :
12204 : /** Return a band whose value is 1 if the pixel value of the left operand
12205 : * is true, or if the constant is true
12206 : *
12207 : * The resulting band is lazy evaluated. A reference is taken on the input
12208 : * dataset.
12209 : *
12210 : * @since 3.12
12211 : */
12212 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12213 : {
12214 : #ifndef HAVE_MUPARSER
12215 : (void)constant;
12216 : return ThrowIfNotMuparser();
12217 : #else
12218 : return GDALComputedRasterBand(
12219 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12220 : #endif
12221 : }
12222 :
12223 : /************************************************************************/
12224 : /* operator||() */
12225 : /************************************************************************/
12226 :
12227 : /** Return a band whose value is 1 if the constant is true, or
12228 : * the pixel value of the right operand is true
12229 : *
12230 : * The resulting band is lazy evaluated. A reference is taken on the input
12231 : * dataset.
12232 : *
12233 : * @since 3.12
12234 : */
12235 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12236 : {
12237 : #ifndef HAVE_MUPARSER
12238 : (void)constant;
12239 : (void)other;
12240 : return ThrowIfNotMuparser();
12241 : #else
12242 : return GDALComputedRasterBand(
12243 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12244 : #endif
12245 : }
12246 :
12247 : #if defined(__GNUC__)
12248 : #pragma GCC diagnostic pop
12249 : #endif
12250 :
12251 : /************************************************************************/
12252 : /* operator!() */
12253 : /************************************************************************/
12254 :
12255 : /** Return a band whose value is the logical negation of the pixel value
12256 : *
12257 : * The resulting band is lazy evaluated. A reference is taken on the input
12258 : * dataset.
12259 : *
12260 : * @since 3.12
12261 : */
12262 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12263 : {
12264 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12265 2 : *this, true);
12266 : }
12267 :
12268 : namespace gdal
12269 : {
12270 :
12271 : /************************************************************************/
12272 : /* IfThenElse() */
12273 : /************************************************************************/
12274 :
12275 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12276 : * is not zero, or the one from elseBand otherwise.
12277 : *
12278 : * Variants of this method exits where thenBand and/or elseBand can be double
12279 : * values.
12280 : *
12281 : * The resulting band is lazy evaluated. A reference is taken on the input
12282 : * datasets.
12283 : *
12284 : * This method is the same as the C function GDALRasterBandIfThenElse()
12285 : *
12286 : * @since 3.12
12287 : */
12288 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12289 : const GDALRasterBand &thenBand,
12290 : const GDALRasterBand &elseBand)
12291 : {
12292 : #ifndef HAVE_MUPARSER
12293 : (void)condBand;
12294 : (void)thenBand;
12295 : (void)elseBand;
12296 : return ThrowIfNotMuparser();
12297 : #else
12298 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12299 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12300 : return GDALComputedRasterBand(
12301 : GDALComputedRasterBand::Operation::OP_TERNARY,
12302 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12303 : #endif
12304 : }
12305 :
12306 : //! @cond Doxygen_Suppress
12307 :
12308 : /************************************************************************/
12309 : /* IfThenElse() */
12310 : /************************************************************************/
12311 :
12312 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12313 : * is not zero, or the one from elseBand otherwise.
12314 : *
12315 : * The resulting band is lazy evaluated. A reference is taken on the input
12316 : * datasets.
12317 : *
12318 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12319 : * with thenBand = (condBand * 0) + thenValue
12320 : *
12321 : * @since 3.12
12322 : */
12323 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12324 : double thenValue,
12325 : const GDALRasterBand &elseBand)
12326 : {
12327 : #ifndef HAVE_MUPARSER
12328 : (void)condBand;
12329 : (void)thenValue;
12330 : (void)elseBand;
12331 : return ThrowIfNotMuparser();
12332 : #else
12333 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12334 : auto thenBand =
12335 1 : (condBand * 0)
12336 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12337 1 : thenValue;
12338 : return GDALComputedRasterBand(
12339 : GDALComputedRasterBand::Operation::OP_TERNARY,
12340 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12341 : #endif
12342 : }
12343 :
12344 : /************************************************************************/
12345 : /* IfThenElse() */
12346 : /************************************************************************/
12347 :
12348 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12349 : * is not zero, or the one from elseValue otherwise.
12350 : *
12351 : * The resulting band is lazy evaluated. A reference is taken on the input
12352 : * datasets.
12353 : *
12354 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12355 : * with elseBand = (condBand * 0) + elseValue
12356 :
12357 : * @since 3.12
12358 : */
12359 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12360 : const GDALRasterBand &thenBand,
12361 : double elseValue)
12362 : {
12363 : #ifndef HAVE_MUPARSER
12364 : (void)condBand;
12365 : (void)thenBand;
12366 : (void)elseValue;
12367 : return ThrowIfNotMuparser();
12368 : #else
12369 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12370 : auto elseBand =
12371 1 : (condBand * 0)
12372 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12373 1 : elseValue;
12374 : return GDALComputedRasterBand(
12375 : GDALComputedRasterBand::Operation::OP_TERNARY,
12376 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12377 : #endif
12378 : }
12379 :
12380 : /************************************************************************/
12381 : /* IfThenElse() */
12382 : /************************************************************************/
12383 :
12384 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12385 : * is not zero, or the one from elseValue otherwise.
12386 : *
12387 : * The resulting band is lazy evaluated. A reference is taken on the input
12388 : * datasets.
12389 : *
12390 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12391 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12392 : *
12393 : * @since 3.12
12394 : */
12395 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12396 : double thenValue, double elseValue)
12397 : {
12398 : #ifndef HAVE_MUPARSER
12399 : (void)condBand;
12400 : (void)thenValue;
12401 : (void)elseValue;
12402 : return ThrowIfNotMuparser();
12403 : #else
12404 : auto thenBand =
12405 3 : (condBand * 0)
12406 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12407 6 : thenValue;
12408 : auto elseBand =
12409 3 : (condBand * 0)
12410 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12411 3 : elseValue;
12412 : return GDALComputedRasterBand(
12413 : GDALComputedRasterBand::Operation::OP_TERNARY,
12414 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12415 : #endif
12416 : }
12417 :
12418 : //! @endcond
12419 :
12420 : } // namespace gdal
12421 :
12422 : /************************************************************************/
12423 : /* GDALRasterBandIfThenElse() */
12424 : /************************************************************************/
12425 :
12426 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12427 : * is not zero, or the one from hElseBand otherwise.
12428 : *
12429 : * The resulting band is lazy evaluated. A reference is taken on the input
12430 : * datasets.
12431 : *
12432 : * This function is the same as the C++ method gdal::IfThenElse()
12433 : *
12434 : * @since 3.12
12435 : */
12436 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12437 : GDALRasterBandH hThenBand,
12438 : GDALRasterBandH hElseBand)
12439 : {
12440 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12441 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12442 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12443 : #ifndef HAVE_MUPARSER
12444 : CPLError(CE_Failure, CPLE_NotSupported,
12445 : "Band comparison operators not available on a GDAL build without "
12446 : "muparser");
12447 : return nullptr;
12448 : #else
12449 :
12450 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12451 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12452 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12453 : try
12454 : {
12455 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12456 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12457 : }
12458 2 : catch (const std::exception &e)
12459 : {
12460 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12461 2 : return nullptr;
12462 : }
12463 : return new GDALComputedRasterBand(
12464 : GDALComputedRasterBand::Operation::OP_TERNARY,
12465 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12466 : #endif
12467 : }
12468 :
12469 : /************************************************************************/
12470 : /* GDALRasterBand::AsType() */
12471 : /************************************************************************/
12472 :
12473 : /** Cast this band to another type.
12474 : *
12475 : * The resulting band is lazy evaluated. A reference is taken on the input
12476 : * dataset.
12477 : *
12478 : * This method is the same as the C function GDALRasterBandAsDataType()
12479 : *
12480 : * @since 3.12
12481 : */
12482 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12483 : {
12484 10 : if (dt == GDT_Unknown)
12485 : {
12486 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12487 : }
12488 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12489 9 : *this, dt);
12490 : }
12491 :
12492 : /************************************************************************/
12493 : /* GDALRasterBandAsDataType() */
12494 : /************************************************************************/
12495 :
12496 : /** Cast this band to another type.
12497 : *
12498 : * The resulting band is lazy evaluated. A reference is taken on the input
12499 : * dataset.
12500 : *
12501 : * This function is the same as the C++ method GDALRasterBand::AsType()
12502 : *
12503 : * @since 3.12
12504 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12505 : */
12506 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12507 : GDALDataType eDT)
12508 : {
12509 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
12510 16 : if (eDT == GDT_Unknown)
12511 : {
12512 1 : CPLError(CE_Failure, CPLE_NotSupported,
12513 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12514 1 : return nullptr;
12515 : }
12516 : return new GDALComputedRasterBand(
12517 : GDALComputedRasterBand::Operation::OP_CAST,
12518 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
12519 : }
12520 :
12521 : /************************************************************************/
12522 : /* GetBandVector() */
12523 : /************************************************************************/
12524 :
12525 : static std::vector<const GDALRasterBand *>
12526 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12527 : {
12528 10 : std::vector<const GDALRasterBand *> bands;
12529 27 : for (size_t i = 0; i < nBandCount; ++i)
12530 : {
12531 20 : if (i > 0)
12532 : {
12533 10 : GDALRasterBand::ThrowIfNotSameDimensions(
12534 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
12535 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
12536 : }
12537 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12538 : }
12539 7 : return bands;
12540 : }
12541 :
12542 : /************************************************************************/
12543 : /* GDALOperationOnNBands() */
12544 : /************************************************************************/
12545 :
12546 : static GDALComputedRasterBandH
12547 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12548 : GDALRasterBandH *pahBands)
12549 : {
12550 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
12551 11 : if (nBandCount == 0)
12552 : {
12553 1 : CPLError(CE_Failure, CPLE_AppDefined,
12554 : "At least one band should be passed");
12555 1 : return nullptr;
12556 : }
12557 :
12558 20 : std::vector<const GDALRasterBand *> bands;
12559 : try
12560 : {
12561 10 : bands = GetBandVector(nBandCount, pahBands);
12562 : }
12563 3 : catch (const std::exception &e)
12564 : {
12565 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12566 3 : return nullptr;
12567 : }
12568 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12569 : }
12570 :
12571 : /************************************************************************/
12572 : /* GDALMaximumOfNBands() */
12573 : /************************************************************************/
12574 :
12575 : /** Return a band whose each pixel value is the maximum of the corresponding
12576 : * pixel values in the input bands.
12577 : *
12578 : * The resulting band is lazy evaluated. A reference is taken on input
12579 : * datasets.
12580 : *
12581 : * This function is the same as the C ++ method gdal::max()
12582 : *
12583 : * @since 3.12
12584 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12585 : */
12586 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12587 : GDALRasterBandH *pahBands)
12588 : {
12589 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12590 4 : nBandCount, pahBands);
12591 : }
12592 :
12593 : /************************************************************************/
12594 : /* gdal::max() */
12595 : /************************************************************************/
12596 :
12597 : namespace gdal
12598 : {
12599 : /** Return a band whose each pixel value is the maximum of the corresponding
12600 : * pixel values in the inputs (bands or constants)
12601 : *
12602 : * The resulting band is lazy evaluated. A reference is taken on input
12603 : * datasets.
12604 : *
12605 : * Two or more bands can be passed.
12606 : *
12607 : * This method is the same as the C function GDALMaximumOfNBands()
12608 : *
12609 : * @since 3.12
12610 : * @throw std::runtime_error if bands do not have the same dimensions.
12611 : */
12612 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
12613 : const GDALRasterBand &second)
12614 : {
12615 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12616 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
12617 1 : first, second);
12618 : }
12619 : } // namespace gdal
12620 :
12621 : /************************************************************************/
12622 : /* GDALRasterBandMaxConstant() */
12623 : /************************************************************************/
12624 :
12625 : /** Return a band whose each pixel value is the maximum of the corresponding
12626 : * pixel values in the input band and the constant.
12627 : *
12628 : * The resulting band is lazy evaluated. A reference is taken on the input
12629 : * dataset.
12630 : *
12631 : * This function is the same as the C ++ method gdal::max()
12632 : *
12633 : * @since 3.12
12634 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12635 : */
12636 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
12637 : double dfConstant)
12638 : {
12639 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12640 : GDALComputedRasterBand::Operation::OP_MAX,
12641 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12642 6 : dfConstant));
12643 : }
12644 :
12645 : /************************************************************************/
12646 : /* GDALMinimumOfNBands() */
12647 : /************************************************************************/
12648 :
12649 : /** Return a band whose each pixel value is the minimum of the corresponding
12650 : * pixel values in the input bands.
12651 : *
12652 : * The resulting band is lazy evaluated. A reference is taken on input
12653 : * datasets.
12654 : *
12655 : * This function is the same as the C ++ method gdal::min()
12656 : *
12657 : * @since 3.12
12658 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12659 : */
12660 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
12661 : GDALRasterBandH *pahBands)
12662 : {
12663 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
12664 4 : nBandCount, pahBands);
12665 : }
12666 :
12667 : /************************************************************************/
12668 : /* gdal::min() */
12669 : /************************************************************************/
12670 :
12671 : namespace gdal
12672 : {
12673 : /** Return a band whose each pixel value is the minimum of the corresponding
12674 : * pixel values in the inputs (bands or constants)
12675 : *
12676 : * The resulting band is lazy evaluated. A reference is taken on input
12677 : * datasets.
12678 : *
12679 : * Two or more bands can be passed.
12680 : *
12681 : * This method is the same as the C function GDALMinimumOfNBands()
12682 : *
12683 : * @since 3.12
12684 : * @throw std::runtime_error if bands do not have the same dimensions.
12685 : */
12686 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
12687 : const GDALRasterBand &second)
12688 : {
12689 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12690 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
12691 0 : first, second);
12692 : }
12693 : } // namespace gdal
12694 :
12695 : /************************************************************************/
12696 : /* GDALRasterBandMinConstant() */
12697 : /************************************************************************/
12698 :
12699 : /** Return a band whose each pixel value is the minimum of the corresponding
12700 : * pixel values in the input band and the constant.
12701 : *
12702 : * The resulting band is lazy evaluated. A reference is taken on the input
12703 : * dataset.
12704 : *
12705 : * This function is the same as the C ++ method gdal::min()
12706 : *
12707 : * @since 3.12
12708 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12709 : */
12710 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
12711 : double dfConstant)
12712 : {
12713 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12714 : GDALComputedRasterBand::Operation::OP_MIN,
12715 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12716 6 : dfConstant));
12717 : }
12718 :
12719 : /************************************************************************/
12720 : /* GDALMeanOfNBands() */
12721 : /************************************************************************/
12722 :
12723 : /** Return a band whose each pixel value is the arithmetic mean of the
12724 : * corresponding pixel values in the input bands.
12725 : *
12726 : * The resulting band is lazy evaluated. A reference is taken on input
12727 : * datasets.
12728 : *
12729 : * This function is the same as the C ++ method gdal::mean()
12730 : *
12731 : * @since 3.12
12732 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12733 : */
12734 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
12735 : GDALRasterBandH *pahBands)
12736 : {
12737 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
12738 3 : nBandCount, pahBands);
12739 : }
12740 :
12741 : /************************************************************************/
12742 : /* gdal::mean() */
12743 : /************************************************************************/
12744 :
12745 : namespace gdal
12746 : {
12747 :
12748 : /** Return a band whose each pixel value is the arithmetic mean of the
12749 : * corresponding pixel values in the input bands.
12750 : *
12751 : * The resulting band is lazy evaluated. A reference is taken on input
12752 : * datasets.
12753 : *
12754 : * Two or more bands can be passed.
12755 : *
12756 : * This method is the same as the C function GDALMeanOfNBands()
12757 : *
12758 : * @since 3.12
12759 : * @throw std::runtime_error if bands do not have the same dimensions.
12760 : */
12761 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
12762 : const GDALRasterBand &second)
12763 : {
12764 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12765 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
12766 0 : first, second);
12767 : }
12768 : } // namespace gdal
12769 :
12770 : /************************************************************************/
12771 : /* gdal::abs() */
12772 : /************************************************************************/
12773 :
12774 : namespace gdal
12775 : {
12776 :
12777 : /** Return a band whose each pixel value is the absolute value (or module
12778 : * for complex data type) of the corresponding pixel value in the input band.
12779 : *
12780 : * The resulting band is lazy evaluated. A reference is taken on input
12781 : * datasets.
12782 : *
12783 : * @since 3.12
12784 : */
12785 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
12786 : {
12787 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12788 1 : band);
12789 : }
12790 : } // namespace gdal
12791 :
12792 : /************************************************************************/
12793 : /* gdal::fabs() */
12794 : /************************************************************************/
12795 :
12796 : namespace gdal
12797 : {
12798 :
12799 : /** Return a band whose each pixel value is the absolute value (or module
12800 : * for complex data type) of the corresponding pixel value in the input band.
12801 : *
12802 : * The resulting band is lazy evaluated. A reference is taken on input
12803 : * datasets.
12804 : *
12805 : * @since 3.12
12806 : */
12807 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
12808 : {
12809 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12810 1 : band);
12811 : }
12812 : } // namespace gdal
12813 :
12814 : /************************************************************************/
12815 : /* gdal::sqrt() */
12816 : /************************************************************************/
12817 :
12818 : namespace gdal
12819 : {
12820 :
12821 : /** Return a band whose each pixel value is the square root of the
12822 : * corresponding pixel value in the input band.
12823 : *
12824 : * The resulting band is lazy evaluated. A reference is taken on input
12825 : * datasets.
12826 : *
12827 : * @since 3.12
12828 : */
12829 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12830 : {
12831 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12832 1 : band);
12833 : }
12834 : } // namespace gdal
12835 :
12836 : /************************************************************************/
12837 : /* gdal::log() */
12838 : /************************************************************************/
12839 :
12840 : namespace gdal
12841 : {
12842 :
12843 : /** Return a band whose each pixel value is the natural logarithm of the
12844 : * corresponding pixel value in the input band.
12845 : *
12846 : * The resulting band is lazy evaluated. A reference is taken on input
12847 : * datasets.
12848 : *
12849 : * @since 3.12
12850 : */
12851 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12852 : {
12853 : #ifndef HAVE_MUPARSER
12854 : (void)band;
12855 : return ThrowIfNotMuparser();
12856 : #else
12857 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12858 1 : band);
12859 : #endif
12860 : }
12861 : } // namespace gdal
12862 :
12863 : /************************************************************************/
12864 : /* gdal::log10() */
12865 : /************************************************************************/
12866 :
12867 : namespace gdal
12868 : {
12869 :
12870 : /** Return a band whose each pixel value is the logarithm base 10 of the
12871 : * corresponding pixel value in the input band.
12872 : *
12873 : * The resulting band is lazy evaluated. A reference is taken on input
12874 : * datasets.
12875 : *
12876 : * @since 3.12
12877 : */
12878 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12879 : {
12880 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12881 1 : band);
12882 : }
12883 : } // namespace gdal
12884 :
12885 : /************************************************************************/
12886 : /* gdal::pow() */
12887 : /************************************************************************/
12888 :
12889 : namespace gdal
12890 : {
12891 :
12892 : #ifndef DOXYGEN_SKIP
12893 : /** Return a band whose each pixel value is the constant raised to the power of
12894 : * the corresponding pixel value in the input band.
12895 : *
12896 : * The resulting band is lazy evaluated. A reference is taken on input
12897 : * datasets.
12898 : *
12899 : * @since 3.12
12900 : */
12901 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12902 : {
12903 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12904 1 : constant, band);
12905 : }
12906 : #endif
12907 :
12908 : } // namespace gdal
12909 :
12910 : /************************************************************************/
12911 : /* gdal::pow() */
12912 : /************************************************************************/
12913 :
12914 : namespace gdal
12915 : {
12916 :
12917 : /** Return a band whose each pixel value is the the corresponding pixel value
12918 : * in the input band raised to the power of the constant.
12919 : *
12920 : * The resulting band is lazy evaluated. A reference is taken on input
12921 : * datasets.
12922 : *
12923 : * @since 3.12
12924 : */
12925 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12926 : {
12927 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12928 1 : band, constant);
12929 : }
12930 : } // namespace gdal
12931 :
12932 : /************************************************************************/
12933 : /* gdal::pow() */
12934 : /************************************************************************/
12935 :
12936 : namespace gdal
12937 : {
12938 :
12939 : #ifndef DOXYGEN_SKIP
12940 : /** Return a band whose each pixel value is the the corresponding pixel value
12941 : * in the input band1 raised to the power of the corresponding pixel value
12942 : * in the input band2
12943 : *
12944 : * The resulting band is lazy evaluated. A reference is taken on input
12945 : * datasets.
12946 : *
12947 : * @since 3.12
12948 : * @throw std::runtime_error if bands do not have the same dimensions.
12949 : */
12950 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12951 : const GDALRasterBand &band2)
12952 : {
12953 : #ifndef HAVE_MUPARSER
12954 : (void)band1;
12955 : (void)band2;
12956 : return ThrowIfNotMuparser();
12957 : #else
12958 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12959 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12960 1 : band1, band2);
12961 : #endif
12962 : }
12963 : #endif
12964 : } // namespace gdal
|