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 1572170 : GDALRasterBand::GDALRasterBand()
60 : : GDALRasterBand(
61 1572170 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
62 : {
63 1572140 : }
64 :
65 : /** Constructor. Applications should never create GDALRasterBands directly.
66 : * @param bForceCachedIOIn Whether cached IO should be forced.
67 : */
68 1849940 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
69 1849940 : : bForceCachedIO(bForceCachedIOIn)
70 :
71 : {
72 1849710 : }
73 :
74 : /************************************************************************/
75 : /* ~GDALRasterBand() */
76 : /************************************************************************/
77 :
78 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
79 : instead destroy the GDALDataset. */
80 :
81 1849940 : GDALRasterBand::~GDALRasterBand()
82 :
83 : {
84 1849940 : if (poDS && poDS->IsMarkedSuppressOnClose())
85 : {
86 501 : if (poBandBlockCache)
87 438 : poBandBlockCache->DisableDirtyBlockWriting();
88 : }
89 1849940 : GDALRasterBand::FlushCache(true);
90 :
91 1849950 : delete poBandBlockCache;
92 :
93 1849950 : if (static_cast<GIntBig>(nBlockReads) >
94 1849950 : 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 1849950 : InvalidateMaskBand();
104 1849940 : nBand = -nBand;
105 :
106 1849940 : delete m_poPointsCache;
107 1849940 : }
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 4406340 : 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 4406340 : if (psExtraArg == nullptr)
340 : {
341 3812530 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
342 3812530 : psExtraArg = &sExtraArg;
343 : }
344 593812 : 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 4406340 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
353 : nBufYSize);
354 :
355 4408310 : 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 4408310 : 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 4408310 : if (eRWFlag == GF_Write)
379 : {
380 365945 : 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 365945 : 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 4408210 : if (nPixelSpace == 0)
400 : {
401 4012750 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
402 : }
403 :
404 4408710 : if (nLineSpace == 0)
405 : {
406 4003700 : nLineSpace = nPixelSpace * nBufXSize;
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Do some validation of parameters. */
411 : /* -------------------------------------------------------------------- */
412 4408710 : 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 4408690 : 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 4408690 : 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 4408690 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
439 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
440 4402960 : nLineSpace, psExtraArg);
441 : }
442 :
443 : /************************************************************************/
444 : /* RasterIOInternal() */
445 : /************************************************************************/
446 :
447 4411710 : 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 4411710 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
457 :
458 : CPLErr eErr;
459 4410280 : 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 4402660 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
466 4410260 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
467 :
468 4402680 : if (bCallLeaveReadWrite)
469 600981 : LeaveReadWrite();
470 :
471 4410510 : 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 3397890 : 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 3397890 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
495 :
496 3397890 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
497 :
498 3396240 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
499 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
500 3390140 : 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 40520 : 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 40520 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
522 :
523 40520 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
524 :
525 40520 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
526 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
527 40516 : nLineSpace, psExtraArg));
528 : }
529 :
530 : /************************************************************************/
531 : /* GetGDTFromCppType() */
532 : /************************************************************************/
533 :
534 : namespace
535 : {
536 : template <class T> struct GetGDTFromCppType;
537 :
538 : #define DEFINE_GetGDTFromCppType(T, eDT) \
539 : template <> struct GetGDTFromCppType<T> \
540 : { \
541 : static constexpr GDALDataType GDT = eDT; \
542 : }
543 :
544 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
545 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
546 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
547 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
548 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
549 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
550 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
551 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
552 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
553 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
554 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
555 : // Not allowed by C++ standard
556 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
557 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
558 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
559 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
560 : } // namespace
561 :
562 : /************************************************************************/
563 : /* ReadRaster() */
564 : /************************************************************************/
565 :
566 : // clang-format off
567 : /** Read a region of image data for this band.
568 : *
569 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
570 : * for common use cases, like reading a whole band.
571 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
572 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
573 : * float, double, std::complex<float|double>.
574 : *
575 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
576 : * and can allocate memory automatically.
577 : *
578 : * To read a whole band (assuming it fits into memory), as an array of double:
579 : *
580 : \code{.cpp}
581 : double* myArray = static_cast<double*>(
582 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
583 : // TODO: check here that myArray != nullptr
584 : const size_t nArrayEltCount =
585 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
586 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
587 : {
588 : // do something
589 : }
590 : VSIFree(myArray)
591 : \endcode
592 : *
593 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
594 : *
595 : \code{.cpp}
596 : double* myArray = static_cast<double*>(
597 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
598 : // TODO: check here that myArray != nullptr
599 : const size_t nArrayEltCount = 128 * 128;
600 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
601 : {
602 : // do something
603 : }
604 : VSIFree(myArray)
605 : \endcode
606 : *
607 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
608 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
609 : * instance of this dataset) concurrently from several threads.
610 : *
611 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
612 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
613 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
614 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
615 : * Or use nLineSpace and a possibly shifted pData value.
616 : *
617 : * @param[out] pData The buffer into which the data should be written.
618 : * This buffer must contain at least nBufXSize *
619 : * nBufYSize words of type T. It is organized in left to right,
620 : * top to bottom pixel order, and fully packed.
621 : * The type of the buffer does not need to be the one of GetDataType(). The
622 : * method will perform data type translation (with potential rounding, clamping)
623 : * if needed.
624 : *
625 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
626 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
627 : * return in error if it is not. If set to zero, then pData is trusted to be
628 : * large enough.
629 : *
630 : * @param dfXOff The pixel offset to the top left corner of the region
631 : * of the band to be accessed. This would be zero to start from the left side.
632 : * Defaults to 0.
633 : *
634 : * @param dfYOff The line offset to the top left corner of the region
635 : * of the band to be accessed. This would be zero to start from the top.
636 : * Defaults to 0.
637 : *
638 : * @param dfXSize The width of the region of the band to be accessed in pixels.
639 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
640 : * dfXSize is set to the band width.
641 : *
642 : * @param dfYSize The height of the region of the band to be accessed in lines.
643 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
644 : * dfYSize is set to the band height.
645 : *
646 : * @param nBufXSize the width of the buffer image into which the desired region
647 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
648 : * then nBufXSize is initialized with dfXSize.
649 : *
650 : * @param nBufYSize the height of the buffer image into which the desired region
651 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
652 : * then nBufYSize is initialized with dfYSize.
653 : *
654 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
655 : *
656 : * @param pfnProgress Progress function. May be nullptr.
657 : *
658 : * @param pProgressData User data of pfnProgress. May be nullptr.
659 : *
660 : * @return CE_Failure if the access fails, otherwise CE_None.
661 : *
662 : * @see GDALRasterBand::RasterIO()
663 : * @since GDAL 3.10
664 : */
665 : // clang-format on
666 :
667 : template <class T>
668 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
669 : double dfXOff, double dfYOff, double dfXSize,
670 : double dfYSize, size_t nBufXSize,
671 : size_t nBufYSize,
672 : GDALRIOResampleAlg eResampleAlg,
673 : GDALProgressFunc pfnProgress,
674 : void *pProgressData) const
675 : {
676 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
677 : {
678 2 : return CE_Failure;
679 : }
680 :
681 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
682 : {
683 16 : dfXSize = nRasterXSize;
684 16 : dfYSize = nRasterYSize;
685 : }
686 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
687 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
688 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
689 2 : dfYOff + dfYSize > INT_MAX)
690 : {
691 0 : return CE_Failure;
692 : }
693 :
694 : GDALRasterIOExtraArg sExtraArg;
695 18 : sExtraArg.nVersion = 1;
696 18 : sExtraArg.eResampleAlg = eResampleAlg;
697 18 : sExtraArg.pfnProgress = pfnProgress;
698 18 : sExtraArg.pProgressData = pProgressData;
699 18 : sExtraArg.bFloatingPointWindowValidity = true;
700 18 : sExtraArg.dfXOff = dfXOff;
701 18 : sExtraArg.dfYOff = dfYOff;
702 18 : sExtraArg.dfXSize = dfXSize;
703 18 : sExtraArg.dfYSize = dfYSize;
704 18 : const int nXOff = static_cast<int>(dfXOff);
705 18 : const int nYOff = static_cast<int>(dfYOff);
706 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
707 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
708 18 : if (nBufXSize == 0 && nBufYSize == 0)
709 : {
710 17 : if (static_cast<int>(dfXSize) == dfXSize &&
711 17 : static_cast<int>(dfYSize) == dfYSize)
712 : {
713 17 : nBufXSize = static_cast<int>(dfXSize);
714 17 : nBufYSize = static_cast<int>(dfYSize);
715 : }
716 : else
717 : {
718 0 : CPLError(CE_Failure, CPLE_AppDefined,
719 : "nBufXSize and nBufYSize must be provided if dfXSize or "
720 : "dfYSize is not an integer value");
721 0 : return CE_Failure;
722 : }
723 : }
724 18 : if (nBufXSize == 0 || nBufYSize == 0)
725 : {
726 0 : CPLDebug("GDAL",
727 : "RasterIO() skipped for odd window or buffer size.\n"
728 : " Window = (%d,%d)x%dx%d\n"
729 : " Buffer = %dx%d\n",
730 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
731 : static_cast<int>(nBufYSize));
732 :
733 0 : return CE_None;
734 : }
735 :
736 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
737 : {
738 1 : CPLError(CE_Failure, CPLE_AppDefined,
739 : "Provided array is not large enough");
740 1 : return CE_Failure;
741 : }
742 :
743 17 : constexpr GSpacing nPixelSpace = sizeof(T);
744 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
745 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
746 :
747 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
748 :
749 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
750 : static_cast<int>(nBufXSize),
751 : static_cast<int>(nBufYSize), eBufType,
752 17 : nPixelSpace, nLineSpace, &sExtraArg);
753 : }
754 :
755 : //! @cond Doxygen_Suppress
756 :
757 : #define INSTANTIATE_READ_RASTER(T) \
758 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
759 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
760 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
761 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
762 : void *pProgressData) const;
763 :
764 : INSTANTIATE_READ_RASTER(uint8_t)
765 : INSTANTIATE_READ_RASTER(int8_t)
766 : INSTANTIATE_READ_RASTER(uint16_t)
767 : INSTANTIATE_READ_RASTER(int16_t)
768 : INSTANTIATE_READ_RASTER(uint32_t)
769 : INSTANTIATE_READ_RASTER(int32_t)
770 : INSTANTIATE_READ_RASTER(uint64_t)
771 : INSTANTIATE_READ_RASTER(int64_t)
772 : INSTANTIATE_READ_RASTER(GFloat16)
773 : INSTANTIATE_READ_RASTER(float)
774 : INSTANTIATE_READ_RASTER(double)
775 : // Not allowed by C++ standard
776 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
777 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
778 : INSTANTIATE_READ_RASTER(std::complex<float>)
779 : INSTANTIATE_READ_RASTER(std::complex<double>)
780 :
781 : //! @endcond
782 :
783 : /************************************************************************/
784 : /* ReadRaster() */
785 : /************************************************************************/
786 :
787 : /** Read a region of image data for this band.
788 : *
789 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
790 : * for common use cases, like reading a whole band.
791 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
792 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
793 : * float, double, std::complex<float|double>.
794 : *
795 : * To read a whole band (assuming it fits into memory), as a vector of double:
796 : *
797 : \code
798 : std::vector<double> myArray;
799 : if (poBand->ReadRaster(myArray) == CE_None)
800 : {
801 : // do something
802 : }
803 : \endcode
804 : *
805 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
806 : *
807 : \code{.cpp}
808 : std::vector<double> myArray;
809 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
810 : {
811 : // do something
812 : }
813 : \endcode
814 : *
815 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
816 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
817 : * instance of this dataset) concurrently from several threads.
818 : *
819 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
820 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
821 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
822 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
823 : * Or use nLineSpace and a possibly shifted pData value.
824 : *
825 : * @param[out] vData The vector into which the data should be written.
826 : * The vector will be resized, if needed, to contain at least nBufXSize *
827 : * nBufYSize values. The values in the vector are organized in left to right,
828 : * top to bottom pixel order, and fully packed.
829 : * The type of the vector does not need to be the one of GetDataType(). The
830 : * method will perform data type translation (with potential rounding, clamping)
831 : * if needed.
832 : *
833 : * @param dfXOff The pixel offset to the top left corner of the region
834 : * of the band to be accessed. This would be zero to start from the left side.
835 : * Defaults to 0.
836 : *
837 : * @param dfYOff The line offset to the top left corner of the region
838 : * of the band to be accessed. This would be zero to start from the top.
839 : * Defaults to 0.
840 : *
841 : * @param dfXSize The width of the region of the band to be accessed in pixels.
842 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
843 : * dfXSize is set to the band width.
844 : *
845 : * @param dfYSize The height of the region of the band to be accessed in lines.
846 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
847 : * dfYSize is set to the band height.
848 : *
849 : * @param nBufXSize the width of the buffer image into which the desired region
850 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
851 : * then nBufXSize is initialized with dfXSize.
852 : *
853 : * @param nBufYSize the height of the buffer image into which the desired region
854 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
855 : * then nBufYSize is initialized with dfYSize.
856 : *
857 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
858 : *
859 : * @param pfnProgress Progress function. May be nullptr.
860 : *
861 : * @param pProgressData User data of pfnProgress. May be nullptr.
862 : *
863 : * @return CE_Failure if the access fails, otherwise CE_None.
864 : *
865 : * @see GDALRasterBand::RasterIO()
866 : * @since GDAL 3.10
867 : */
868 : template <class T>
869 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
870 : double dfYOff, double dfXSize, double dfYSize,
871 : size_t nBufXSize, size_t nBufYSize,
872 : GDALRIOResampleAlg eResampleAlg,
873 : GDALProgressFunc pfnProgress,
874 : void *pProgressData) const
875 : {
876 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
877 : {
878 2 : return CE_Failure;
879 : }
880 :
881 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
882 : {
883 13 : dfXSize = nRasterXSize;
884 13 : dfYSize = nRasterYSize;
885 : }
886 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
887 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
888 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
889 7 : dfYOff + dfYSize > INT_MAX)
890 : {
891 0 : return CE_Failure;
892 : }
893 :
894 : GDALRasterIOExtraArg sExtraArg;
895 20 : sExtraArg.nVersion = 1;
896 20 : sExtraArg.eResampleAlg = eResampleAlg;
897 20 : sExtraArg.pfnProgress = pfnProgress;
898 20 : sExtraArg.pProgressData = pProgressData;
899 20 : sExtraArg.bFloatingPointWindowValidity = true;
900 20 : sExtraArg.dfXOff = dfXOff;
901 20 : sExtraArg.dfYOff = dfYOff;
902 20 : sExtraArg.dfXSize = dfXSize;
903 20 : sExtraArg.dfYSize = dfYSize;
904 20 : const int nXOff = static_cast<int>(dfXOff);
905 20 : const int nYOff = static_cast<int>(dfYOff);
906 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
907 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
908 20 : if (nBufXSize == 0 && nBufYSize == 0)
909 : {
910 16 : if (static_cast<int>(dfXSize) == dfXSize &&
911 15 : static_cast<int>(dfYSize) == dfYSize)
912 : {
913 15 : nBufXSize = static_cast<int>(dfXSize);
914 15 : nBufYSize = static_cast<int>(dfYSize);
915 : }
916 : else
917 : {
918 1 : CPLError(CE_Failure, CPLE_AppDefined,
919 : "nBufXSize and nBufYSize must be provided if "
920 : "dfXSize or dfYSize is not an integer value");
921 1 : return CE_Failure;
922 : }
923 : }
924 19 : if (nBufXSize == 0 || nBufYSize == 0)
925 : {
926 0 : CPLDebug("GDAL",
927 : "RasterIO() skipped for odd window or buffer size.\n"
928 : " Window = (%d,%d)x%dx%d\n"
929 : " Buffer = %dx%d\n",
930 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
931 : static_cast<int>(nBufYSize));
932 :
933 0 : return CE_None;
934 : }
935 :
936 : if constexpr (SIZEOF_VOIDP < 8)
937 : {
938 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
939 : {
940 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
941 : return CE_Failure;
942 : }
943 : }
944 :
945 19 : if (vData.size() < nBufXSize * nBufYSize)
946 : {
947 : try
948 : {
949 17 : vData.resize(nBufXSize * nBufYSize);
950 : }
951 1 : catch (const std::exception &)
952 : {
953 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
954 1 : return CE_Failure;
955 : }
956 : }
957 :
958 18 : constexpr GSpacing nPixelSpace = sizeof(T);
959 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
960 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
961 :
962 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
963 :
964 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
965 : vData.data(), static_cast<int>(nBufXSize),
966 : static_cast<int>(nBufYSize), eBufType,
967 18 : nPixelSpace, nLineSpace, &sExtraArg);
968 : }
969 :
970 : //! @cond Doxygen_Suppress
971 :
972 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
973 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
974 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
975 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
976 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
977 : void *pProgressData) const;
978 :
979 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
981 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
982 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
983 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
984 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
985 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
986 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
988 : INSTANTIATE_READ_RASTER_VECTOR(float)
989 : INSTANTIATE_READ_RASTER_VECTOR(double)
990 : // Not allowed by C++ standard
991 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
992 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
993 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
994 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
995 :
996 : //! @endcond
997 :
998 : /************************************************************************/
999 : /* ReadBlock() */
1000 : /************************************************************************/
1001 :
1002 : /**
1003 : * \brief Read a block of image data efficiently.
1004 : *
1005 : * This method accesses a "natural" block from the raster band without
1006 : * resampling, or data type conversion. For a more generalized, but
1007 : * potentially less efficient access use RasterIO().
1008 : *
1009 : * This method is the same as the C GDALReadBlock() function.
1010 : *
1011 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1012 : * block oriented data without an extra copy into an application buffer.
1013 : *
1014 : * The following code would efficiently compute a histogram of eight bit
1015 : * raster data. Note that the final block may be partial ... data beyond
1016 : * the edge of the underlying raster band in these edge blocks is of an
1017 : * undetermined value.
1018 : *
1019 : \code{.cpp}
1020 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1021 :
1022 : {
1023 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1024 :
1025 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1026 :
1027 : int nXBlockSize, nYBlockSize;
1028 :
1029 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1030 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1031 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1032 :
1033 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1034 :
1035 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1036 : {
1037 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1038 : {
1039 : int nXValid, nYValid;
1040 :
1041 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1042 :
1043 : // Compute the portion of the block that is valid
1044 : // for partial edge blocks.
1045 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1046 :
1047 : // Collect the histogram counts.
1048 : for( int iY = 0; iY < nYValid; iY++ )
1049 : {
1050 : for( int iX = 0; iX < nXValid; iX++ )
1051 : {
1052 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1053 : }
1054 : }
1055 : }
1056 : }
1057 : }
1058 : \endcode
1059 : *
1060 : * @param nXBlockOff the horizontal block offset, with zero indicating
1061 : * the left most block, 1 the next block and so forth.
1062 : *
1063 : * @param nYBlockOff the vertical block offset, with zero indicating
1064 : * the top most block, 1 the next block and so forth.
1065 : *
1066 : * @param pImage the buffer into which the data will be read. The buffer
1067 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1068 : * of type GetRasterDataType().
1069 : *
1070 : * @return CE_None on success or CE_Failure on an error.
1071 : */
1072 :
1073 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1074 :
1075 : {
1076 : /* -------------------------------------------------------------------- */
1077 : /* Validate arguments. */
1078 : /* -------------------------------------------------------------------- */
1079 894 : CPLAssert(pImage != nullptr);
1080 :
1081 894 : if (!InitBlockInfo())
1082 0 : return CE_Failure;
1083 :
1084 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1085 : {
1086 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1087 : "Illegal nXBlockOff value (%d) in "
1088 : "GDALRasterBand::ReadBlock()\n",
1089 : nXBlockOff);
1090 :
1091 0 : return (CE_Failure);
1092 : }
1093 :
1094 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1095 : {
1096 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1097 : "Illegal nYBlockOff value (%d) in "
1098 : "GDALRasterBand::ReadBlock()\n",
1099 : nYBlockOff);
1100 :
1101 0 : return (CE_Failure);
1102 : }
1103 :
1104 : /* -------------------------------------------------------------------- */
1105 : /* Invoke underlying implementation method. */
1106 : /* -------------------------------------------------------------------- */
1107 :
1108 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1109 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1110 894 : if (bCallLeaveReadWrite)
1111 4 : LeaveReadWrite();
1112 894 : return eErr;
1113 : }
1114 :
1115 : /************************************************************************/
1116 : /* GDALReadBlock() */
1117 : /************************************************************************/
1118 :
1119 : /**
1120 : * \brief Read a block of image data efficiently.
1121 : *
1122 : * @see GDALRasterBand::ReadBlock()
1123 : */
1124 :
1125 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1126 : void *pData)
1127 :
1128 : {
1129 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1130 :
1131 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1132 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1133 : }
1134 :
1135 : /************************************************************************/
1136 : /* IReadBlock() */
1137 : /************************************************************************/
1138 :
1139 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1140 : * ) \brief Read a block of data.
1141 : *
1142 : * Default internal implementation ... to be overridden by
1143 : * subclasses that support reading.
1144 : * @param nBlockXOff Block X Offset
1145 : * @param nBlockYOff Block Y Offset
1146 : * @param pData Pixel buffer into which to place read data.
1147 : * @return CE_None on success or CE_Failure on an error.
1148 : */
1149 :
1150 : /************************************************************************/
1151 : /* IWriteBlock() */
1152 : /************************************************************************/
1153 :
1154 : /**
1155 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1156 : * Write a block of data.
1157 : *
1158 : * Default internal implementation ... to be overridden by
1159 : * subclasses that support writing.
1160 : * @param nBlockXOff Block X Offset
1161 : * @param nBlockYOff Block Y Offset
1162 : * @param pData Pixel buffer to write
1163 : * @return CE_None on success or CE_Failure on an error.
1164 : */
1165 :
1166 : /**/
1167 : /**/
1168 :
1169 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1170 : void * /*pData*/)
1171 :
1172 : {
1173 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1174 0 : ReportError(CE_Failure, CPLE_NotSupported,
1175 : "WriteBlock() not supported for this dataset.");
1176 :
1177 0 : return (CE_Failure);
1178 : }
1179 :
1180 : /************************************************************************/
1181 : /* WriteBlock() */
1182 : /************************************************************************/
1183 :
1184 : /**
1185 : * \brief Write a block of image data efficiently.
1186 : *
1187 : * This method accesses a "natural" block from the raster band without
1188 : * resampling, or data type conversion. For a more generalized, but
1189 : * potentially less efficient access use RasterIO().
1190 : *
1191 : * This method is the same as the C GDALWriteBlock() function.
1192 : *
1193 : * See ReadBlock() for an example of block oriented data access.
1194 : *
1195 : * @param nXBlockOff the horizontal block offset, with zero indicating
1196 : * the left most block, 1 the next block and so forth.
1197 : *
1198 : * @param nYBlockOff the vertical block offset, with zero indicating
1199 : * the left most block, 1 the next block and so forth.
1200 : *
1201 : * @param pImage the buffer from which the data will be written. The buffer
1202 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1203 : * of type GetRasterDataType(). Note that the content of the buffer might be
1204 : * temporarily modified during the execution of this method (and eventually
1205 : * restored back to its original content), so it is not safe to use a buffer
1206 : * stored in a read-only section of the calling program.
1207 : *
1208 : * @return CE_None on success or CE_Failure on an error.
1209 : */
1210 :
1211 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1212 :
1213 : {
1214 : /* -------------------------------------------------------------------- */
1215 : /* Validate arguments. */
1216 : /* -------------------------------------------------------------------- */
1217 4883 : CPLAssert(pImage != nullptr);
1218 :
1219 4883 : if (!InitBlockInfo())
1220 0 : return CE_Failure;
1221 :
1222 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1223 : {
1224 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1225 : "Illegal nXBlockOff value (%d) in "
1226 : "GDALRasterBand::WriteBlock()\n",
1227 : nXBlockOff);
1228 :
1229 0 : return (CE_Failure);
1230 : }
1231 :
1232 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1233 : {
1234 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1235 : "Illegal nYBlockOff value (%d) in "
1236 : "GDALRasterBand::WriteBlock()\n",
1237 : nYBlockOff);
1238 :
1239 0 : return (CE_Failure);
1240 : }
1241 :
1242 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1243 : {
1244 0 : return CE_Failure;
1245 : }
1246 :
1247 4883 : if (eFlushBlockErr != CE_None)
1248 : {
1249 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1250 : "An error occurred while writing a dirty block "
1251 : "from GDALRasterBand::WriteBlock");
1252 0 : CPLErr eErr = eFlushBlockErr;
1253 0 : eFlushBlockErr = CE_None;
1254 0 : return eErr;
1255 : }
1256 :
1257 : /* -------------------------------------------------------------------- */
1258 : /* Invoke underlying implementation method. */
1259 : /* -------------------------------------------------------------------- */
1260 :
1261 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1262 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1263 4883 : if (bCallLeaveReadWrite)
1264 4883 : LeaveReadWrite();
1265 :
1266 4883 : return eErr;
1267 : }
1268 :
1269 : /************************************************************************/
1270 : /* GDALWriteBlock() */
1271 : /************************************************************************/
1272 :
1273 : /**
1274 : * \brief Write a block of image data efficiently.
1275 : *
1276 : * @see GDALRasterBand::WriteBlock()
1277 : */
1278 :
1279 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1280 : void *pData)
1281 :
1282 : {
1283 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1284 :
1285 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1286 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1287 : }
1288 :
1289 : /************************************************************************/
1290 : /* EmitErrorMessageIfWriteNotSupported() */
1291 : /************************************************************************/
1292 :
1293 : /**
1294 : * Emit an error message if a write operation to this band is not supported.
1295 : *
1296 : * The base implementation will emit an error message if the access mode is
1297 : * read-only. Derived classes may implement it to provide a custom message.
1298 : *
1299 : * @param pszCaller Calling function.
1300 : * @return true if an error message has been emitted.
1301 : */
1302 639491 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1303 : const char *pszCaller) const
1304 : {
1305 639491 : 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 639487 : 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 52101 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1342 : int *pnXValid, int *pnYValid) const
1343 : {
1344 104201 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1345 104199 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1346 104196 : nYBlockOff < 0 || nBlockYSize == 0 ||
1347 52098 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1348 : {
1349 4 : return CE_Failure;
1350 : }
1351 :
1352 52097 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1353 52097 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1354 :
1355 52097 : *pnXValid = nBlockXSize;
1356 52097 : *pnYValid = nBlockYSize;
1357 :
1358 52097 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1359 : {
1360 50463 : *pnXValid = nRasterXSize - nXPixelOff;
1361 : }
1362 :
1363 52097 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1364 : {
1365 3819 : *pnYValid = nRasterYSize - nYPixelOff;
1366 : }
1367 :
1368 52097 : 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 2413 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1428 : {
1429 2413 : 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 8943580 : GDALDataType GDALRasterBand::GetRasterDataType() const
1445 :
1446 : {
1447 8943580 : 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 905984 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1461 :
1462 : {
1463 905984 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1464 :
1465 905984 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1466 905984 : 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 5513220 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1496 :
1497 : {
1498 5513220 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1499 : {
1500 0 : ReportError(CE_Failure, CPLE_AppDefined,
1501 0 : "Invalid block dimension : %d * %d", nBlockXSize,
1502 0 : nBlockYSize);
1503 4 : if (pnXSize != nullptr)
1504 4 : *pnXSize = 0;
1505 4 : if (pnYSize != nullptr)
1506 4 : *pnYSize = 0;
1507 : }
1508 : else
1509 : {
1510 5527580 : if (pnXSize != nullptr)
1511 5528160 : *pnXSize = nBlockXSize;
1512 5527580 : if (pnYSize != nullptr)
1513 5533210 : *pnYSize = nBlockYSize;
1514 : }
1515 5527590 : }
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 41234 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1528 : int *pnYSize)
1529 :
1530 : {
1531 41234 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1532 :
1533 41234 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1534 41234 : poBand->GetBlockSize(pnXSize, pnYSize);
1535 : }
1536 :
1537 : /************************************************************************/
1538 : /* InitBlockInfo() */
1539 : /************************************************************************/
1540 :
1541 : //! @cond Doxygen_Suppress
1542 3647030 : int GDALRasterBand::InitBlockInfo()
1543 :
1544 : {
1545 3647030 : if (poBandBlockCache != nullptr)
1546 3408050 : 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 238979 : 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 238980 : 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 238981 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1567 238980 : 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 238980 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1590 238980 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1591 :
1592 : const char *pszBlockStrategy =
1593 238980 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1594 238984 : bool bUseArray = true;
1595 238984 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1596 : {
1597 238944 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1598 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1599 : {
1600 238925 : GUIntBig nBlockCount =
1601 238925 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1602 238925 : if (poDS != nullptr)
1603 238721 : nBlockCount *= poDS->GetRasterCount();
1604 238925 : 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 238944 : }
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 238984 : if (bUseArray)
1619 238913 : 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 238984 : if (poBandBlockCache == nullptr)
1627 0 : return FALSE;
1628 238984 : 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 5646630 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1650 :
1651 : {
1652 5763740 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1653 117119 : poBandBlockCache)
1654 3196 : poBandBlockCache->DisableDirtyBlockWriting();
1655 :
1656 5644850 : CPLErr eGlobalErr = eFlushBlockErr;
1657 :
1658 5644850 : 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 5644850 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1667 4883760 : return eGlobalErr;
1668 :
1669 761087 : 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 29683 : 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 29683 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1787 29683 : 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 29682 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1800 : {
1801 29682 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1802 29682 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1803 : }
1804 :
1805 : //! @endcond
1806 :
1807 : /************************************************************************/
1808 : /* HasDirtyBlocks() */
1809 : /************************************************************************/
1810 :
1811 : //! @cond Doxygen_Suppress
1812 17 : bool GDALRasterBand::HasDirtyBlocks() const
1813 : {
1814 17 : return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
1815 : }
1816 :
1817 : //! @endcond
1818 :
1819 : /************************************************************************/
1820 : /* FlushBlock() */
1821 : /************************************************************************/
1822 :
1823 : /** Flush a block out of the block cache.
1824 : * @param nXBlockOff block x offset
1825 : * @param nYBlockOff blocky offset
1826 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1827 : * @return CE_None in case of success, an error code otherwise.
1828 : */
1829 2311 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1830 : int bWriteDirtyBlock)
1831 :
1832 : {
1833 2311 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1834 0 : return (CE_Failure);
1835 :
1836 : /* -------------------------------------------------------------------- */
1837 : /* Validate the request */
1838 : /* -------------------------------------------------------------------- */
1839 2311 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1840 : {
1841 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1842 : "Illegal nBlockXOff value (%d) in "
1843 : "GDALRasterBand::FlushBlock()\n",
1844 : nXBlockOff);
1845 :
1846 0 : return (CE_Failure);
1847 : }
1848 :
1849 2311 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1850 : {
1851 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1852 : "Illegal nBlockYOff value (%d) in "
1853 : "GDALRasterBand::FlushBlock()\n",
1854 : nYBlockOff);
1855 :
1856 0 : return (CE_Failure);
1857 : }
1858 :
1859 2311 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1860 2311 : bWriteDirtyBlock);
1861 : }
1862 :
1863 : /************************************************************************/
1864 : /* TryGetLockedBlockRef() */
1865 : /************************************************************************/
1866 :
1867 : /**
1868 : * \brief Try fetching block ref.
1869 : *
1870 : * This method will returned the requested block (locked) if it is already
1871 : * in the block cache for the layer. If not, nullptr is returned.
1872 : *
1873 : * If a non-NULL value is returned, then a lock for the block will have been
1874 : * acquired on behalf of the caller. It is absolutely imperative that the
1875 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1876 : * severe problems may result.
1877 : *
1878 : * @param nXBlockOff the horizontal block offset, with zero indicating
1879 : * the left most block, 1 the next block and so forth.
1880 : *
1881 : * @param nYBlockOff the vertical block offset, with zero indicating
1882 : * the top most block, 1 the next block and so forth.
1883 : *
1884 : * @return NULL if block not available, or locked block pointer.
1885 : */
1886 :
1887 10642100 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1888 : int nYBlockOff)
1889 :
1890 : {
1891 10642100 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1892 172919 : return nullptr;
1893 :
1894 : /* -------------------------------------------------------------------- */
1895 : /* Validate the request */
1896 : /* -------------------------------------------------------------------- */
1897 10469000 : 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 10469300 : 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 10469300 : 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 10331900 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1955 : int nYBlockOff,
1956 : int bJustInitialize)
1957 :
1958 : {
1959 : /* -------------------------------------------------------------------- */
1960 : /* Try and fetch from cache. */
1961 : /* -------------------------------------------------------------------- */
1962 10331900 : 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 10332300 : if (poBlock == nullptr)
1970 : {
1971 3370030 : if (!InitBlockInfo())
1972 0 : return (nullptr);
1973 :
1974 : /* --------------------------------------------------------------------
1975 : */
1976 : /* Validate the request */
1977 : /* --------------------------------------------------------------------
1978 : */
1979 3370020 : 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 3370030 : 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 3370030 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2000 3370020 : if (poBlock == nullptr)
2001 0 : return nullptr;
2002 :
2003 3370020 : 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 3370020 : if (poDS)
2018 3369280 : poDS->TemporarilyDropReadWriteLock();
2019 : /* allocate data space */
2020 3370010 : CPLErr eErr = poBlock->Internalize();
2021 3370030 : if (poDS)
2022 3369290 : poDS->ReacquireReadWriteLock();
2023 3370020 : if (eErr != CE_None)
2024 : {
2025 0 : poBlock->DropLock();
2026 0 : delete poBlock;
2027 0 : return nullptr;
2028 : }
2029 :
2030 3370020 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2031 : {
2032 0 : poBlock->DropLock();
2033 0 : delete poBlock;
2034 0 : return nullptr;
2035 : }
2036 :
2037 3370020 : if (!bJustInitialize)
2038 : {
2039 2883820 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2040 2883830 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2041 2883830 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2042 2883810 : if (bCallLeaveReadWrite)
2043 130216 : LeaveReadWrite();
2044 2883810 : if (eErr != CE_None)
2045 : {
2046 1161 : poBlock->DropLock();
2047 1161 : FlushBlock(nXBlockOff, nYBlockOff);
2048 1161 : ReportError(CE_Failure, CPLE_AppDefined,
2049 : "IReadBlock failed at X offset %d, Y offset %d%s",
2050 : nXBlockOff, nYBlockOff,
2051 1161 : (nErrorCounter != CPLGetErrorCounter())
2052 1159 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2053 : : "");
2054 1161 : return nullptr;
2055 : }
2056 :
2057 2882650 : nBlockReads++;
2058 2882650 : if (static_cast<GIntBig>(nBlockReads) ==
2059 2882650 : 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 10331100 : 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 268859 : 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 268859 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2108 : {
2109 6 : return CE_Failure;
2110 : }
2111 :
2112 : // Make sure block parameters are set.
2113 268853 : if (!InitBlockInfo())
2114 0 : return CE_Failure;
2115 :
2116 : // Allocate the source block.
2117 268853 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2118 268853 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2119 268853 : auto blockByteSize = blockSize * elementSize;
2120 : unsigned char *srcBlock =
2121 268853 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2122 268853 : 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 268853 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2133 268853 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2134 : elementSize, blockSize);
2135 :
2136 268853 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2137 :
2138 : // Write block to block cache
2139 872362 : for (int j = 0; j < nBlocksPerColumn; ++j)
2140 : {
2141 1501360 : for (int i = 0; i < nBlocksPerRow; ++i)
2142 : {
2143 897856 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2144 897856 : 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 897856 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2153 897856 : destBlock->MarkDirty();
2154 897856 : destBlock->DropLock();
2155 : }
2156 : }
2157 :
2158 268853 : if (bCallLeaveReadWrite)
2159 267664 : LeaveReadWrite();
2160 :
2161 : // Free up the source block
2162 268853 : VSIFree(srcBlock);
2163 :
2164 268853 : 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 268661 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2177 : double dfImaginaryValue)
2178 : {
2179 268661 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2180 :
2181 268661 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2182 268661 : 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 3039 : GDALAccess GDALRasterBand::GetAccess()
2198 :
2199 : {
2200 3039 : 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 2381 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2214 :
2215 : {
2216 2381 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2217 :
2218 2381 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2219 2381 : 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 205 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2260 :
2261 : {
2262 205 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2263 :
2264 205 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2265 205 : 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 13120 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2348 :
2349 : {
2350 13120 : if (pbSuccess != nullptr)
2351 13120 : *pbSuccess = FALSE;
2352 :
2353 13120 : 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 414458 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2367 : int *pbSuccess)
2368 :
2369 : {
2370 414458 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2371 :
2372 414458 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2373 414458 : 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 993 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2674 : double dfValue)
2675 :
2676 : {
2677 993 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2678 :
2679 993 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2680 993 : 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 23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2746 : int64_t nValue)
2747 :
2748 : {
2749 23 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2750 :
2751 23 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2752 23 : 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 538 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2891 :
2892 : {
2893 538 : const char *pszValue = nullptr;
2894 :
2895 538 : 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 491 : if (pbSuccess != nullptr)
2904 487 : *pbSuccess = FALSE;
2905 :
2906 491 : switch (eDataType)
2907 : {
2908 340 : case GDT_Byte:
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 12 : case GDT_UInt32:
2935 12 : return 4294967295.0;
2936 :
2937 1 : case GDT_Int64:
2938 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2939 :
2940 1 : case GDT_UInt64:
2941 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2942 :
2943 0 : case GDT_Float16:
2944 : case GDT_CFloat16:
2945 0 : return 65504.0;
2946 :
2947 30 : case GDT_Float32:
2948 : case GDT_CFloat32:
2949 30 : return 4294967295.0; // Not actually accurate.
2950 :
2951 22 : case GDT_Float64:
2952 : case GDT_CFloat64:
2953 22 : return 4294967295.0; // Not actually accurate.
2954 :
2955 0 : case GDT_Unknown:
2956 : case GDT_TypeCount:
2957 0 : break;
2958 : }
2959 0 : return 4294967295.0; // Not actually accurate.
2960 : }
2961 :
2962 : /************************************************************************/
2963 : /* GDALGetRasterMaximum() */
2964 : /************************************************************************/
2965 :
2966 : /**
2967 : * \brief Fetch the maximum value for this band.
2968 : *
2969 : * @see GDALRasterBand::GetMaximum()
2970 : */
2971 :
2972 338 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2973 :
2974 : {
2975 338 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2976 :
2977 338 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2978 338 : 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 546 : double GDALRasterBand::GetMinimum(int *pbSuccess)
3000 :
3001 : {
3002 546 : const char *pszValue = nullptr;
3003 :
3004 546 : 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 494 : if (pbSuccess != nullptr)
3013 490 : *pbSuccess = FALSE;
3014 :
3015 494 : switch (eDataType)
3016 : {
3017 343 : case GDT_Byte:
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 12 : case GDT_UInt32:
3044 12 : return 0;
3045 :
3046 1 : case GDT_Int64:
3047 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3048 :
3049 1 : case GDT_UInt64:
3050 1 : return 0;
3051 :
3052 0 : case GDT_Float16:
3053 : case GDT_CFloat16:
3054 0 : return -65504.0;
3055 :
3056 30 : case GDT_Float32:
3057 : case GDT_CFloat32:
3058 30 : return -4294967295.0; // Not actually accurate.
3059 :
3060 22 : case GDT_Float64:
3061 : case GDT_CFloat64:
3062 22 : return -4294967295.0; // Not actually accurate.
3063 :
3064 0 : case GDT_Unknown:
3065 : case GDT_TypeCount:
3066 0 : break;
3067 : }
3068 0 : return -4294967295.0; // Not actually accurate.
3069 : }
3070 :
3071 : /************************************************************************/
3072 : /* GDALGetRasterMinimum() */
3073 : /************************************************************************/
3074 :
3075 : /**
3076 : * \brief Fetch the minimum value for this band.
3077 : *
3078 : * @see GDALRasterBand::GetMinimum()
3079 : */
3080 :
3081 348 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3082 :
3083 : {
3084 348 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3085 :
3086 348 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3087 348 : 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 5728 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3124 :
3125 : {
3126 5728 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3127 :
3128 5728 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3129 5728 : 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 1859 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3170 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3171 :
3172 : {
3173 1859 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3174 :
3175 1859 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3176 1859 : 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 1988 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3212 :
3213 : {
3214 1988 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3215 :
3216 1988 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3217 1988 : 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 274 : int GDALRasterBand::HasArbitraryOverviews()
3293 :
3294 : {
3295 274 : return FALSE;
3296 : }
3297 :
3298 : /************************************************************************/
3299 : /* GDALHasArbitraryOverviews() */
3300 : /************************************************************************/
3301 :
3302 : /**
3303 : * \brief Check for arbitrary overviews.
3304 : *
3305 : * @see GDALRasterBand::HasArbitraryOverviews()
3306 : */
3307 :
3308 195 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3309 :
3310 : {
3311 195 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3312 :
3313 195 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3314 195 : 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 1066450 : int GDALRasterBand::GetOverviewCount()
3330 :
3331 : {
3332 1723170 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3333 656717 : poDS->AreOverviewsEnabled())
3334 656717 : return poDS->oOvManager.GetOverviewCount(nBand);
3335 :
3336 409737 : 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 3306 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3350 :
3351 : {
3352 3306 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3353 :
3354 3306 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3355 3306 : 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 5645 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3393 :
3394 : {
3395 5645 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3396 :
3397 5645 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3398 5645 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3399 : }
3400 :
3401 : /************************************************************************/
3402 : /* GetRasterSampleOverview() */
3403 : /************************************************************************/
3404 :
3405 : /**
3406 : * \brief Fetch best sampling overview.
3407 : *
3408 : * Returns the most reduced overview of the given band that still satisfies
3409 : * the desired number of samples. This function can be used with zero
3410 : * as the number of desired samples to fetch the most reduced overview.
3411 : * The same band as was passed in will be returned if it has not overviews,
3412 : * or if none of the overviews have enough samples.
3413 : *
3414 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3415 : * and GDALGetRasterSampleOverviewEx().
3416 : *
3417 : * @param nDesiredSamples the returned band will have at least this many
3418 : * pixels.
3419 : *
3420 : * @return optimal overview or the band itself.
3421 : */
3422 :
3423 : GDALRasterBand *
3424 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3425 :
3426 : {
3427 2006 : GDALRasterBand *poBestBand = this;
3428 :
3429 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3430 :
3431 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3432 : {
3433 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3434 :
3435 2017 : if (poOBand == nullptr)
3436 0 : continue;
3437 :
3438 : const double dfOSamples =
3439 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3440 :
3441 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3442 : {
3443 2014 : dfBestSamples = dfOSamples;
3444 2014 : poBestBand = poOBand;
3445 : }
3446 : }
3447 :
3448 2006 : return poBestBand;
3449 : }
3450 :
3451 : /************************************************************************/
3452 : /* GDALGetRasterSampleOverview() */
3453 : /************************************************************************/
3454 :
3455 : /**
3456 : * \brief Fetch best sampling overview.
3457 : *
3458 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3459 : * billion samples.
3460 : *
3461 : * @see GDALRasterBand::GetRasterSampleOverview()
3462 : * @see GDALGetRasterSampleOverviewEx()
3463 : */
3464 :
3465 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3466 : int nDesiredSamples)
3467 :
3468 : {
3469 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3470 :
3471 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3472 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3473 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3474 : }
3475 :
3476 : /************************************************************************/
3477 : /* GDALGetRasterSampleOverviewEx() */
3478 : /************************************************************************/
3479 :
3480 : /**
3481 : * \brief Fetch best sampling overview.
3482 : *
3483 : * @see GDALRasterBand::GetRasterSampleOverview()
3484 : */
3485 :
3486 : GDALRasterBandH CPL_STDCALL
3487 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3488 :
3489 : {
3490 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3491 :
3492 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3493 2000 : return GDALRasterBand::ToHandle(
3494 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3495 : }
3496 :
3497 : /************************************************************************/
3498 : /* BuildOverviews() */
3499 : /************************************************************************/
3500 :
3501 : /**
3502 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3503 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3504 : *
3505 : * If the operation is unsupported for the indicated dataset, then
3506 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3507 : * CPLE_NotSupported.
3508 : *
3509 : * WARNING: Most formats don't support per-band overview computation, but
3510 : * require that overviews are computed for all bands of a dataset, using
3511 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3512 : * is the HFA driver which supports this method.
3513 : *
3514 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3515 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3516 : * applied.
3517 : * @param nOverviews number of overviews to build.
3518 : * @param panOverviewList the list of overview decimation factors to build.
3519 : * @param pfnProgress a function to call to report progress, or NULL.
3520 : * @param pProgressData application data to pass to the progress function.
3521 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3522 : * key=value pairs, or NULL
3523 : *
3524 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3525 : */
3526 :
3527 : /**/
3528 : /**/
3529 :
3530 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3531 : int /*nOverviews*/,
3532 : const int * /*panOverviewList*/,
3533 : GDALProgressFunc /*pfnProgress*/,
3534 : void * /*pProgressData*/,
3535 : CSLConstList /* papszOptions */)
3536 :
3537 : {
3538 0 : ReportError(CE_Failure, CPLE_NotSupported,
3539 : "BuildOverviews() not supported for this dataset.");
3540 :
3541 0 : return (CE_Failure);
3542 : }
3543 :
3544 : /************************************************************************/
3545 : /* GetOffset() */
3546 : /************************************************************************/
3547 :
3548 : /**
3549 : * \brief Fetch the raster value offset.
3550 : *
3551 : * This value (in combination with the GetScale() value) can be used to
3552 : * transform raw pixel values into the units returned by GetUnitType().
3553 : * For example this might be used to store elevations in GUInt16 bands
3554 : * with a precision of 0.1, and starting from -100.
3555 : *
3556 : * Units value = (raw value * scale) + offset
3557 : *
3558 : * Note that applying scale and offset is of the responsibility of the user,
3559 : * and is not done by methods such as RasterIO() or ReadBlock().
3560 : *
3561 : * For file formats that don't know this intrinsically a value of zero
3562 : * is returned.
3563 : *
3564 : * This method is the same as the C function GDALGetRasterOffset().
3565 : *
3566 : * @param pbSuccess pointer to a boolean to use to indicate if the
3567 : * returned value is meaningful or not. May be NULL (default).
3568 : *
3569 : * @return the raster offset.
3570 : */
3571 :
3572 445 : double GDALRasterBand::GetOffset(int *pbSuccess)
3573 :
3574 : {
3575 445 : if (pbSuccess != nullptr)
3576 336 : *pbSuccess = FALSE;
3577 :
3578 445 : return 0.0;
3579 : }
3580 :
3581 : /************************************************************************/
3582 : /* GDALGetRasterOffset() */
3583 : /************************************************************************/
3584 :
3585 : /**
3586 : * \brief Fetch the raster value offset.
3587 : *
3588 : * @see GDALRasterBand::GetOffset()
3589 : */
3590 :
3591 399 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3592 :
3593 : {
3594 399 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3595 :
3596 399 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3597 399 : 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 397 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3698 :
3699 : {
3700 397 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3701 :
3702 397 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3703 397 : 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 1486 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3790 :
3791 : {
3792 1486 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3793 :
3794 1486 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3795 1486 : return poBand->GetUnitType();
3796 : }
3797 :
3798 : /************************************************************************/
3799 : /* SetUnitType() */
3800 : /************************************************************************/
3801 :
3802 : /**
3803 : * \fn GDALRasterBand::SetUnitType(const char*)
3804 : * \brief Set unit type.
3805 : *
3806 : * Set the unit type for a raster band. Values should be one of
3807 : * "" (the default indicating it is unknown), "m" indicating meters,
3808 : * or "ft" indicating feet, though other nonstandard values are allowed.
3809 : *
3810 : * This method is the same as the C function GDALSetRasterUnitType().
3811 : *
3812 : * @param pszNewValue the new unit type value.
3813 : *
3814 : * @return CE_None on success or CE_Failure if not successful, or
3815 : * unsupported.
3816 : */
3817 :
3818 : /**/
3819 : /**/
3820 :
3821 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3822 :
3823 : {
3824 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3825 0 : ReportError(CE_Failure, CPLE_NotSupported,
3826 : "SetUnitType() not supported on this raster band.");
3827 0 : return CE_Failure;
3828 : }
3829 :
3830 : /************************************************************************/
3831 : /* GDALSetRasterUnitType() */
3832 : /************************************************************************/
3833 :
3834 : /**
3835 : * \brief Set unit type.
3836 : *
3837 : * @see GDALRasterBand::SetUnitType()
3838 : *
3839 : */
3840 :
3841 95 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842 : const char *pszNewValue)
3843 :
3844 : {
3845 95 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846 :
3847 95 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848 95 : return poBand->SetUnitType(pszNewValue);
3849 : }
3850 :
3851 : /************************************************************************/
3852 : /* GetXSize() */
3853 : /************************************************************************/
3854 :
3855 : /**
3856 : * \brief Fetch XSize of raster.
3857 : *
3858 : * This method is the same as the C function GDALGetRasterBandXSize().
3859 : *
3860 : * @return the width in pixels of this band.
3861 : */
3862 :
3863 8425320 : int GDALRasterBand::GetXSize() const
3864 :
3865 : {
3866 8425320 : return nRasterXSize;
3867 : }
3868 :
3869 : /************************************************************************/
3870 : /* GDALGetRasterBandXSize() */
3871 : /************************************************************************/
3872 :
3873 : /**
3874 : * \brief Fetch XSize of raster.
3875 : *
3876 : * @see GDALRasterBand::GetXSize()
3877 : */
3878 :
3879 57939 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3880 :
3881 : {
3882 57939 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3883 :
3884 57939 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3885 57939 : 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 4668040 : int GDALRasterBand::GetYSize() const
3901 :
3902 : {
3903 4668040 : return nRasterYSize;
3904 : }
3905 :
3906 : /************************************************************************/
3907 : /* GDALGetRasterBandYSize() */
3908 : /************************************************************************/
3909 :
3910 : /**
3911 : * \brief Fetch YSize of raster.
3912 : *
3913 : * @see GDALRasterBand::GetYSize()
3914 : */
3915 :
3916 56802 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3917 :
3918 : {
3919 56802 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3920 :
3921 56802 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3922 56802 : 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 150786 : int GDALRasterBand::GetBand() const
3943 :
3944 : {
3945 150786 : 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 5278380 : GDALDataset *GDALRasterBand::GetDataset() const
3984 :
3985 : {
3986 5278380 : return poDS;
3987 : }
3988 :
3989 : /************************************************************************/
3990 : /* GDALGetBandDataset() */
3991 : /************************************************************************/
3992 :
3993 : /**
3994 : * \brief Fetch the owning dataset handle.
3995 : *
3996 : * @see GDALRasterBand::GetDataset()
3997 : */
3998 :
3999 355 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
4000 :
4001 : {
4002 355 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
4003 :
4004 355 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4005 355 : return GDALDataset::ToHandle(poBand->GetDataset());
4006 : }
4007 :
4008 : /************************************************************************/
4009 : /* ComputeFloat16NoDataValue() */
4010 : /************************************************************************/
4011 :
4012 3013 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013 : double dfNoDataValue,
4014 : int &bGotNoDataValue,
4015 : GFloat16 &fNoDataValue,
4016 : bool &bGotFloat16NoDataValue)
4017 : {
4018 3013 : 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 3013 : }
4029 :
4030 : /************************************************************************/
4031 : /* ComputeFloatNoDataValue() */
4032 : /************************************************************************/
4033 :
4034 3013 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035 : double dfNoDataValue,
4036 : int &bGotNoDataValue,
4037 : float &fNoDataValue,
4038 : bool &bGotFloatNoDataValue)
4039 : {
4040 3013 : 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 3013 : }
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 3105 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4082 3105 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4083 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4084 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4085 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4086 3105 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4087 : {
4088 3105 : 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 3047 : 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 3013 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4123 3013 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4124 :
4125 3013 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4126 3013 : fNoDataValue, bGotFloatNoDataValue);
4127 :
4128 3013 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4129 3013 : hfNoDataValue, bGotFloat16NoDataValue);
4130 : }
4131 3105 : }
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_Byte)
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_Byte, 0, 0, nullptr) != CE_None)
4326 : {
4327 0 : CPLFree(pData);
4328 0 : CPLFree(pabyMaskData);
4329 0 : return CE_Failure;
4330 : }
4331 : }
4332 :
4333 : // This isn't the fastest way to do this, but is easier for now.
4334 0 : for (int iY = 0; iY < nYReduced; iY++)
4335 : {
4336 0 : for (int iX = 0; iX < nXReduced; iX++)
4337 : {
4338 0 : const int iOffset = iX + iY * nXReduced;
4339 0 : double dfValue = 0.0;
4340 :
4341 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4342 0 : continue;
4343 :
4344 0 : switch (eDataType)
4345 : {
4346 0 : case GDT_Byte:
4347 : {
4348 0 : if (bSignedByte)
4349 0 : dfValue =
4350 0 : static_cast<signed char *>(pData)[iOffset];
4351 : else
4352 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4353 0 : break;
4354 : }
4355 0 : case GDT_Int8:
4356 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357 0 : break;
4358 0 : case GDT_UInt16:
4359 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360 0 : break;
4361 0 : case GDT_Int16:
4362 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363 0 : break;
4364 0 : case GDT_UInt32:
4365 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366 0 : break;
4367 0 : case GDT_Int32:
4368 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369 0 : break;
4370 0 : case GDT_UInt64:
4371 0 : dfValue = static_cast<double>(
4372 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4373 0 : break;
4374 0 : case GDT_Int64:
4375 0 : dfValue = static_cast<double>(
4376 0 : static_cast<GInt64 *>(pData)[iOffset]);
4377 0 : break;
4378 0 : case GDT_Float16:
4379 : {
4380 : using namespace std;
4381 0 : const GFloat16 hfValue =
4382 0 : static_cast<GFloat16 *>(pData)[iOffset];
4383 0 : if (isnan(hfValue) ||
4384 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4385 0 : ARE_REAL_EQUAL(hfValue,
4386 : sNoDataValues.hfNoDataValue)))
4387 0 : continue;
4388 0 : dfValue = hfValue;
4389 0 : break;
4390 : }
4391 0 : case GDT_Float32:
4392 : {
4393 0 : const float fValue =
4394 0 : static_cast<float *>(pData)[iOffset];
4395 0 : if (std::isnan(fValue) ||
4396 0 : (sNoDataValues.bGotFloatNoDataValue &&
4397 0 : ARE_REAL_EQUAL(fValue,
4398 : sNoDataValues.fNoDataValue)))
4399 0 : continue;
4400 0 : dfValue = double(fValue);
4401 0 : break;
4402 : }
4403 0 : case GDT_Float64:
4404 0 : dfValue = static_cast<double *>(pData)[iOffset];
4405 0 : if (std::isnan(dfValue))
4406 0 : continue;
4407 0 : break;
4408 0 : case GDT_CInt16:
4409 : {
4410 0 : const double dfReal =
4411 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4412 0 : const double dfImag =
4413 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4414 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4415 0 : continue;
4416 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4417 : }
4418 0 : break;
4419 0 : case GDT_CInt32:
4420 : {
4421 0 : const double dfReal =
4422 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4423 0 : const double dfImag =
4424 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4425 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4426 0 : continue;
4427 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4428 : }
4429 0 : break;
4430 0 : case GDT_CFloat16:
4431 : {
4432 : const double dfReal =
4433 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4434 : const double dfImag =
4435 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4436 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4437 0 : continue;
4438 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4439 0 : break;
4440 : }
4441 0 : case GDT_CFloat32:
4442 : {
4443 0 : const double dfReal =
4444 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4445 0 : const double dfImag = double(
4446 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4447 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4448 0 : continue;
4449 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4450 0 : break;
4451 : }
4452 0 : case GDT_CFloat64:
4453 : {
4454 0 : const double dfReal =
4455 0 : static_cast<double *>(pData)[iOffset * 2];
4456 0 : const double dfImag =
4457 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4458 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4459 0 : continue;
4460 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4461 0 : break;
4462 : }
4463 0 : case GDT_Unknown:
4464 : case GDT_TypeCount:
4465 0 : CPLAssert(false);
4466 : }
4467 :
4468 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4469 0 : sNoDataValues.bGotNoDataValue &&
4470 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4471 0 : continue;
4472 :
4473 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4474 : // finite, the result of the multiplication cannot be NaN
4475 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4476 :
4477 0 : if (dfIndex < 0)
4478 : {
4479 0 : if (bIncludeOutOfRange)
4480 0 : panHistogram[0]++;
4481 : }
4482 0 : else if (dfIndex >= nBuckets)
4483 : {
4484 0 : if (bIncludeOutOfRange)
4485 0 : ++panHistogram[nBuckets - 1];
4486 : }
4487 : else
4488 : {
4489 0 : ++panHistogram[static_cast<int>(dfIndex)];
4490 : }
4491 : }
4492 : }
4493 :
4494 0 : CPLFree(pData);
4495 0 : CPLFree(pabyMaskData);
4496 : }
4497 : else // No arbitrary overviews.
4498 : {
4499 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_Byte,
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_Byte && !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_Byte:
4618 : {
4619 19716 : if (bSignedByte)
4620 0 : dfValue =
4621 0 : static_cast<signed char *>(pData)[iOffset];
4622 : else
4623 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4624 19716 : break;
4625 : }
4626 1 : case GDT_Int8:
4627 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4628 1 : break;
4629 16384 : case GDT_UInt16:
4630 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4631 16384 : break;
4632 3 : case GDT_Int16:
4633 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4634 3 : break;
4635 0 : case GDT_UInt32:
4636 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4637 0 : break;
4638 60 : case GDT_Int32:
4639 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4640 60 : break;
4641 0 : case GDT_UInt64:
4642 0 : dfValue = static_cast<double>(
4643 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4644 0 : break;
4645 0 : case GDT_Int64:
4646 0 : dfValue = static_cast<double>(
4647 0 : static_cast<GInt64 *>(pData)[iOffset]);
4648 0 : break;
4649 0 : case GDT_Float16:
4650 : {
4651 : using namespace std;
4652 0 : const GFloat16 hfValue =
4653 0 : static_cast<GFloat16 *>(pData)[iOffset];
4654 0 : if (isnan(hfValue) ||
4655 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4656 0 : ARE_REAL_EQUAL(hfValue,
4657 : sNoDataValues.hfNoDataValue)))
4658 0 : continue;
4659 0 : dfValue = hfValue;
4660 0 : break;
4661 : }
4662 3 : case GDT_Float32:
4663 : {
4664 3 : const float fValue =
4665 3 : static_cast<float *>(pData)[iOffset];
4666 6 : if (std::isnan(fValue) ||
4667 6 : (sNoDataValues.bGotFloatNoDataValue &&
4668 3 : ARE_REAL_EQUAL(fValue,
4669 : sNoDataValues.fNoDataValue)))
4670 0 : continue;
4671 3 : dfValue = double(fValue);
4672 3 : break;
4673 : }
4674 2 : case GDT_Float64:
4675 2 : dfValue = static_cast<double *>(pData)[iOffset];
4676 2 : if (std::isnan(dfValue))
4677 0 : continue;
4678 2 : break;
4679 0 : case GDT_CInt16:
4680 : {
4681 0 : double dfReal =
4682 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4683 0 : double dfImag =
4684 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4685 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686 0 : break;
4687 : }
4688 0 : case GDT_CInt32:
4689 : {
4690 0 : double dfReal =
4691 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4692 0 : double dfImag =
4693 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4694 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4695 0 : break;
4696 : }
4697 0 : case GDT_CFloat16:
4698 : {
4699 : double dfReal =
4700 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4701 : double dfImag =
4702 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4703 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4704 0 : continue;
4705 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4706 0 : break;
4707 : }
4708 0 : case GDT_CFloat32:
4709 : {
4710 0 : double dfReal = double(
4711 0 : static_cast<float *>(pData)[iOffset * 2]);
4712 0 : double dfImag = double(
4713 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4714 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4715 0 : continue;
4716 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4717 0 : break;
4718 : }
4719 0 : case GDT_CFloat64:
4720 : {
4721 0 : double dfReal =
4722 0 : static_cast<double *>(pData)[iOffset * 2];
4723 0 : double dfImag =
4724 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4725 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4726 0 : continue;
4727 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4728 0 : break;
4729 : }
4730 0 : case GDT_Unknown:
4731 : case GDT_TypeCount:
4732 0 : CPLAssert(false);
4733 : CPLFree(pabyMaskData);
4734 : return CE_Failure;
4735 : }
4736 :
4737 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4738 72338 : sNoDataValues.bGotNoDataValue &&
4739 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4740 0 : continue;
4741 :
4742 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4743 : // and finite, the result of the multiplication cannot be
4744 : // NaN
4745 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4746 :
4747 36169 : if (dfIndex < 0)
4748 : {
4749 1 : if (bIncludeOutOfRange)
4750 1 : panHistogram[0]++;
4751 : }
4752 36168 : else if (dfIndex >= nBuckets)
4753 : {
4754 7 : if (bIncludeOutOfRange)
4755 4 : ++panHistogram[nBuckets - 1];
4756 : }
4757 : else
4758 : {
4759 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4760 : }
4761 : }
4762 : }
4763 :
4764 39 : poBlock->DropLock();
4765 : }
4766 :
4767 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_Byte)
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_Byte && !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 InitBlockInfo().");
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 113829 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5129 : int /*nYSize*/, int /*nBufXSize*/,
5130 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5131 : char ** /*papszOptions*/)
5132 : {
5133 113829 : 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 670 : 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 1340 : if ((pdfMin == nullptr ||
5223 670 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5224 205 : (pdfMax == nullptr ||
5225 205 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5226 1545 : (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 472 : 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 472 : if (!bForce)
5270 189 : 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 318 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5287 : int bForce, double *pdfMin,
5288 : double *pdfMax, double *pdfMean,
5289 : double *pdfStdDev)
5290 :
5291 : {
5292 318 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5293 :
5294 318 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5295 318 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5296 318 : pdfStdDev);
5297 : }
5298 :
5299 : /************************************************************************/
5300 : /* GDALUInt128 */
5301 : /************************************************************************/
5302 :
5303 : #ifdef HAVE_UINT128_T
5304 : class GDALUInt128
5305 : {
5306 : __uint128_t val;
5307 :
5308 1161 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5309 : {
5310 1161 : }
5311 :
5312 : public:
5313 774 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5314 : {
5315 : // Evaluates to just a single mul on x86_64
5316 774 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5317 : }
5318 :
5319 387 : GDALUInt128 operator-(const GDALUInt128 &other) const
5320 : {
5321 387 : return GDALUInt128(val - other.val);
5322 : }
5323 :
5324 378 : operator double() const
5325 : {
5326 378 : 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 13727 : 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 13727 : int nOuterLoops = nXCheck / 65536;
5560 13727 : if (nXCheck % 65536)
5561 13727 : nOuterLoops++;
5562 :
5563 13727 : 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 3145 : 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 8430 : for (int iY = 0; iY < nYCheck; iY++)
5660 : {
5661 5317 : int iX = 0;
5662 10634 : for (int k = 0; k < nOuterLoops; k++)
5663 : {
5664 5317 : int iMax = iX + 65536;
5665 5317 : if (iMax > nXCheck)
5666 5317 : iMax = nXCheck;
5667 5317 : GUInt32 nSum32bit = 0;
5668 5317 : GUInt32 nSumSquare32bit = 0;
5669 284881 : for (; iX + 1 < iMax; iX += 2)
5670 : {
5671 279564 : const GPtrDiff_t iOffset =
5672 279564 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673 279564 : const GUInt32 nValue = pData[iOffset];
5674 279564 : const GUInt32 nValue2 = pData[iOffset + 1];
5675 279564 : if (nValue < nValue2)
5676 : {
5677 8058 : if (nValue < nMin)
5678 232 : nMin = nValue;
5679 8058 : if (nValue2 > nMax)
5680 222 : nMax = nValue2;
5681 : }
5682 : else
5683 : {
5684 271506 : if (nValue2 < nMin)
5685 361 : nMin = nValue2;
5686 271506 : if (nValue > nMax)
5687 829 : nMax = nValue;
5688 : }
5689 : if constexpr (COMPUTE_OTHER_STATS)
5690 : {
5691 257426 : nSum32bit += nValue;
5692 257426 : nSumSquare32bit += nValue * nValue;
5693 257426 : nSum32bit += nValue2;
5694 257426 : nSumSquare32bit += nValue2 * nValue2;
5695 : }
5696 : }
5697 : if constexpr (COMPUTE_OTHER_STATS)
5698 : {
5699 2130 : nSum += nSum32bit;
5700 2130 : nSumSquare += nSumSquare32bit;
5701 : }
5702 : }
5703 5317 : 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 916 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5724 916 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5725 : }
5726 : }
5727 13727 : }
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 30242 : 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 30242 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5922 30242 : 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 28750 : 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 12486 : 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 13727 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6158 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6159 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6160 : }
6161 30242 : }
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 15432100 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6336 : const void *pData, GPtrDiff_t iOffset,
6337 : const GDALNoDataValues &sNoDataValues,
6338 : bool &bValid)
6339 : {
6340 15432100 : bValid = true;
6341 15432100 : double dfValue = 0;
6342 15432100 : switch (eDataType)
6343 : {
6344 1400770 : case GDT_Byte:
6345 : {
6346 1400770 : if (bSignedByte)
6347 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6348 : else
6349 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6350 1400770 : break;
6351 : }
6352 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 13393800 : case GDT_Float32:
6391 : {
6392 13393800 : const float fValue = static_cast<const float *>(pData)[iOffset];
6393 26760800 : if (std::isnan(fValue) ||
6394 26635700 : (sNoDataValues.bGotFloatNoDataValue &&
6395 13268800 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6396 : {
6397 26879 : bValid = false;
6398 26879 : return 0.0;
6399 : }
6400 13367000 : dfValue = double(fValue);
6401 13367000 : return dfValue;
6402 : }
6403 150868 : case GDT_Float64:
6404 150868 : dfValue = static_cast<const double *>(pData)[iOffset];
6405 150868 : if (std::isnan(dfValue))
6406 : {
6407 6 : bValid = false;
6408 6 : return 0.0;
6409 : }
6410 150862 : 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 2293270 : if (sNoDataValues.bGotNoDataValue &&
6448 255049 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6449 : {
6450 4203 : bValid = false;
6451 4203 : return 0.0;
6452 : }
6453 2034020 : 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 534 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6473 : GUIntBig nValidCount)
6474 : {
6475 534 : if (nValidCount == 0)
6476 : {
6477 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6478 : }
6479 522 : else if (nValidCount == nSampleCount)
6480 : {
6481 464 : 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 534 : }
6503 :
6504 : //! @endcond
6505 :
6506 : #if (defined(__x86_64__) || defined(_M_X64))
6507 :
6508 : #ifdef __AVX2__
6509 :
6510 : #define setzero_si _mm256_setzero_si256
6511 : #define setzero_ps _mm256_setzero_ps
6512 : #define set1_ps _mm256_set1_ps
6513 : #define set1_epi32 _mm256_set1_epi32
6514 : #define add_epi32 _mm256_add_epi32
6515 : #define loadu_ps _mm256_loadu_ps
6516 : #define or_ps _mm256_or_ps
6517 : #define min_ps _mm256_min_ps
6518 : #define max_ps _mm256_max_ps
6519 : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
6520 : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
6521 : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
6522 : #define movemask_ps _mm256_movemask_ps
6523 : #define add_ps _mm256_add_ps
6524 : #define sub_ps _mm256_sub_ps
6525 : #define mul_ps _mm256_mul_ps
6526 : #define div_ps _mm256_div_ps
6527 : #define storeu_ps _mm256_storeu_ps
6528 : #define cvtepi32_ps _mm256_cvtepi32_ps
6529 : #define cvtsi_si32(x) _mm256_extract_epi32((x), 0)
6530 : #define blendv_ps _mm256_blendv_ps
6531 : #ifdef __FMA__
6532 : #define fmadd_ps _mm256_fmadd_ps
6533 : #else
6534 : #define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
6535 : #endif
6536 :
6537 : #else
6538 :
6539 : #define setzero_si _mm_setzero_si128
6540 : #define setzero_ps _mm_setzero_ps
6541 : #define set1_ps _mm_set1_ps
6542 : #define set1_epi32 _mm_set1_epi32
6543 : #define add_epi32 _mm_add_epi32
6544 : #define loadu_ps _mm_loadu_ps
6545 : #define or_ps _mm_or_ps
6546 : #define min_ps _mm_min_ps
6547 : #define max_ps _mm_max_ps
6548 : #define cmpeq_ps _mm_cmpeq_ps
6549 : #define cmpneq_ps _mm_cmpneq_ps
6550 : #define cmpunord_ps _mm_cmpunord_ps
6551 : #define movemask_ps _mm_movemask_ps
6552 : #define add_ps _mm_add_ps
6553 : #define sub_ps _mm_sub_ps
6554 : #define mul_ps _mm_mul_ps
6555 : #define div_ps _mm_div_ps
6556 : #define storeu_ps _mm_storeu_ps
6557 : #define cvtepi32_ps _mm_cvtepi32_ps
6558 : #define cvtsi_si32 _mm_cvtsi128_si32
6559 : #ifdef __FMA__
6560 : #define fmadd_ps _mm_fmadd_ps
6561 : #else
6562 : #define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
6563 : #endif
6564 :
6565 2065850 : inline __m128 blendv_ps(__m128 a, __m128 b, __m128 mask)
6566 : {
6567 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6568 : return _mm_blendv_ps(a, b, mask);
6569 : #else
6570 6197540 : return _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b));
6571 : #endif
6572 : }
6573 : #endif
6574 :
6575 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6576 : #if defined(__GNUC__)
6577 : __attribute__((noinline))
6578 : #endif
6579 : static int
6580 4889 : ComputeStatisticsFloat32_SSE2(const float *pafData,
6581 : [[maybe_unused]] float fNoDataValue, int iX,
6582 : int nCount, float &fMin, float &fMax,
6583 : float &fBlockMean, float &fBlockM2,
6584 : int &nBlockValidCount)
6585 : {
6586 4889 : auto vValidCount = setzero_si();
6587 4889 : const auto vOne = set1_epi32(1);
6588 4889 : [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
6589 :
6590 4889 : auto vMin_lo = set1_ps(fMin);
6591 9778 : auto vMax_lo = set1_ps(fMax);
6592 4889 : auto vMean_lo = setzero_ps();
6593 4889 : auto vM2_lo = setzero_ps();
6594 :
6595 4889 : auto vMin_hi = vMin_lo;
6596 4889 : auto vMax_hi = vMax_lo;
6597 4889 : auto vMean_hi = setzero_ps();
6598 4889 : auto vM2_hi = setzero_ps();
6599 :
6600 4889 : constexpr int VALS_PER_LOOP =
6601 : 2 * static_cast<int>(sizeof(vOne) / sizeof(float));
6602 590671 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6603 : {
6604 585783 : const auto vValues_lo = loadu_ps(pafData + iX);
6605 1171568 : const auto vValues_hi = loadu_ps(pafData + iX + VALS_PER_LOOP / 2);
6606 : // Check if there's at least one NaN in both vectors
6607 585783 : auto isNaNOrNoData = cmpunord_ps(vValues_lo, vValues_hi);
6608 : if constexpr (HAS_NODATA)
6609 : {
6610 : isNaNOrNoData =
6611 0 : or_ps(isNaNOrNoData, or_ps(cmpeq_ps(vValues_lo, vNoData),
6612 : cmpeq_ps(vValues_hi, vNoData)));
6613 : }
6614 585783 : if (movemask_ps(isNaNOrNoData))
6615 : {
6616 1 : break;
6617 : }
6618 :
6619 585782 : vValidCount = add_epi32(vValidCount, vOne);
6620 585782 : const auto vValidCountFloat32 = cvtepi32_ps(vValidCount);
6621 :
6622 585782 : vMin_lo = min_ps(vMin_lo, vValues_lo);
6623 585782 : vMax_lo = max_ps(vMax_lo, vValues_lo);
6624 585782 : const auto vDelta_lo = sub_ps(vValues_lo, vMean_lo);
6625 : const auto vNewMean_lo =
6626 1102213 : add_ps(vMean_lo, div_ps(vDelta_lo, vValidCountFloat32));
6627 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6628 : {
6629 516429 : const auto vMinNotSameAsMax_lo = cmpneq_ps(vMin_lo, vMax_lo);
6630 516429 : vMean_lo = blendv_ps(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6631 : const auto vNewM2_lo =
6632 1032860 : fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
6633 516429 : vM2_lo = blendv_ps(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6634 : }
6635 : else
6636 : {
6637 69353 : vMean_lo = vNewMean_lo;
6638 208059 : vM2_lo = fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
6639 : }
6640 :
6641 585782 : vMin_hi = min_ps(vMin_hi, vValues_hi);
6642 585782 : vMax_hi = max_ps(vMax_hi, vValues_hi);
6643 585782 : const auto vDelta_hi = sub_ps(vValues_hi, vMean_hi);
6644 : const auto vNewMean_hi =
6645 1102213 : add_ps(vMean_hi, div_ps(vDelta_hi, vValidCountFloat32));
6646 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6647 : {
6648 516429 : const auto vMinNotSameAsMax_hi = cmpneq_ps(vMin_hi, vMax_hi);
6649 516429 : vMean_hi = blendv_ps(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6650 : const auto vNewM2_hi =
6651 1032860 : fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
6652 516429 : vM2_hi = blendv_ps(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6653 : }
6654 : else
6655 : {
6656 69353 : vMean_hi = vNewMean_hi;
6657 208059 : vM2_hi = fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
6658 : }
6659 : }
6660 4889 : const int nValidVectorCount = cvtsi_si32(vValidCount);
6661 4889 : if (nValidVectorCount)
6662 : {
6663 : float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP], afMean[VALS_PER_LOOP],
6664 : afM2[VALS_PER_LOOP];
6665 : storeu_ps(afMin, vMin_lo);
6666 : storeu_ps(afMax, vMax_lo);
6667 : storeu_ps(afMean, vMean_lo);
6668 : storeu_ps(afM2, vM2_lo);
6669 4631 : storeu_ps(afMin + VALS_PER_LOOP / 2, vMin_hi);
6670 4631 : storeu_ps(afMax + VALS_PER_LOOP / 2, vMax_hi);
6671 4631 : storeu_ps(afMean + VALS_PER_LOOP / 2, vMean_hi);
6672 4631 : storeu_ps(afM2 + VALS_PER_LOOP / 2, vM2_hi);
6673 :
6674 41679 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6675 : {
6676 37048 : fMin = std::min(fMin, afMin[i]);
6677 37048 : fMax = std::max(fMax, afMax[i]);
6678 37048 : const auto nNewValidCount = nBlockValidCount + nValidVectorCount;
6679 37048 : if (afMean[i] != fBlockMean)
6680 : {
6681 17864 : const float fDelta = afMean[i] - fBlockMean;
6682 17864 : fBlockMean += fDelta * nValidVectorCount / nNewValidCount;
6683 17864 : fBlockM2 += afM2[i] + fDelta * fDelta * nBlockValidCount *
6684 17864 : nValidVectorCount / nNewValidCount;
6685 : }
6686 37048 : nBlockValidCount = nNewValidCount;
6687 : }
6688 : }
6689 :
6690 4889 : return iX;
6691 : }
6692 :
6693 : #ifdef __AVX2__
6694 :
6695 : #define setzero_pd _mm256_setzero_pd
6696 : #define set1_pd _mm256_set1_pd
6697 : #define loadu_pd _mm256_loadu_pd
6698 : #define or_pd _mm256_or_pd
6699 : #define min_pd _mm256_min_pd
6700 : #define max_pd _mm256_max_pd
6701 : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
6702 : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
6703 : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
6704 : #define movemask_pd _mm256_movemask_pd
6705 : #define add_pd _mm256_add_pd
6706 : #define sub_pd _mm256_sub_pd
6707 : #define mul_pd _mm256_mul_pd
6708 : #define div_pd _mm256_div_pd
6709 : #define storeu_pd _mm256_storeu_pd
6710 : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
6711 : #define blendv_pd _mm256_blendv_pd
6712 : #ifdef __FMA__
6713 : #define fmadd_pd _mm256_fmadd_pd
6714 : #else
6715 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6716 : #endif
6717 :
6718 : #else
6719 :
6720 : #define setzero_pd _mm_setzero_pd
6721 : #define set1_pd _mm_set1_pd
6722 : #define loadu_pd _mm_loadu_pd
6723 : #define or_pd _mm_or_pd
6724 : #define min_pd _mm_min_pd
6725 : #define max_pd _mm_max_pd
6726 : #define cmpeq_pd _mm_cmpeq_pd
6727 : #define cmpneq_pd _mm_cmpneq_pd
6728 : #define cmpunord_pd _mm_cmpunord_pd
6729 : #define movemask_pd _mm_movemask_pd
6730 : #define add_pd _mm_add_pd
6731 : #define sub_pd _mm_sub_pd
6732 : #define mul_pd _mm_mul_pd
6733 : #define div_pd _mm_div_pd
6734 : #define storeu_pd _mm_storeu_pd
6735 : #define cvtsd_f64 _mm_cvtsd_f64
6736 : #ifdef __FMA__
6737 : #define fmadd_pd _mm_fmadd_pd
6738 : #else
6739 : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
6740 : #endif
6741 :
6742 103928 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
6743 : {
6744 : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
6745 : return _mm_blendv_pd(a, b, mask);
6746 : #else
6747 311784 : return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
6748 : #endif
6749 : }
6750 : #endif
6751 :
6752 : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
6753 : #if defined(__GNUC__)
6754 : __attribute__((noinline))
6755 : #endif
6756 : static int
6757 1351 : ComputeStatisticsFloat64_SSE2(const double *padfData,
6758 : [[maybe_unused]] double dfNoDataValue, int iX,
6759 : int nCount, double &dfMin, double &dfMax,
6760 : double &dfBlockMean, double &dfBlockM2,
6761 : double &dfBlockValidCount)
6762 : {
6763 1351 : auto vValidCount = setzero_pd();
6764 1351 : const auto vOne = set1_pd(1);
6765 1351 : [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
6766 :
6767 1351 : auto vMin_lo = set1_pd(dfMin);
6768 2702 : auto vMax_lo = set1_pd(dfMax);
6769 1351 : auto vMean_lo = setzero_pd();
6770 1351 : auto vM2_lo = setzero_pd();
6771 :
6772 1351 : auto vMin_hi = vMin_lo;
6773 1351 : auto vMax_hi = vMax_lo;
6774 1351 : auto vMean_hi = setzero_pd();
6775 1351 : auto vM2_hi = setzero_pd();
6776 :
6777 1351 : constexpr int VALS_PER_LOOP =
6778 : 2 * static_cast<int>(sizeof(vOne) / sizeof(double));
6779 43687 : for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
6780 : {
6781 42379 : const auto vValues_lo = loadu_pd(padfData + iX);
6782 84758 : const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
6783 : // Check if there's at least one NaN in both vectors
6784 42379 : auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
6785 : if constexpr (HAS_NODATA)
6786 : {
6787 : isNaNOrNoData =
6788 103248 : or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
6789 : cmpeq_pd(vValues_hi, vNoData)));
6790 : }
6791 42379 : if (movemask_pd(isNaNOrNoData))
6792 : {
6793 43 : break;
6794 : }
6795 :
6796 42336 : vValidCount = add_pd(vValidCount, vOne);
6797 42336 : const auto vInvValidCount = div_pd(vOne, vValidCount);
6798 :
6799 42336 : vMin_lo = min_pd(vMin_lo, vValues_lo);
6800 42336 : vMax_lo = max_pd(vMax_lo, vValues_lo);
6801 42336 : const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
6802 68318 : const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
6803 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6804 : {
6805 25982 : const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
6806 25982 : vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
6807 : const auto vNewM2_lo =
6808 51964 : fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6809 25982 : vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
6810 : }
6811 : else
6812 : {
6813 16354 : vMean_lo = vNewMean_lo;
6814 49062 : vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
6815 : }
6816 :
6817 42336 : vMin_hi = min_pd(vMin_hi, vValues_hi);
6818 42336 : vMax_hi = max_pd(vMax_hi, vValues_hi);
6819 42336 : const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
6820 68318 : const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
6821 : if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
6822 : {
6823 25982 : const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
6824 25982 : vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
6825 : const auto vNewM2_hi =
6826 51964 : fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6827 25982 : vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
6828 : }
6829 : else
6830 : {
6831 16354 : vMean_hi = vNewMean_hi;
6832 49062 : vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
6833 : }
6834 : }
6835 1351 : const double dfValidVectorCount = cvtsd_f64(vValidCount);
6836 1351 : if (dfValidVectorCount > 0)
6837 : {
6838 : double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
6839 : adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
6840 : storeu_pd(adfMin, vMin_lo);
6841 : storeu_pd(adfMax, vMax_lo);
6842 : storeu_pd(adfMean, vMean_lo);
6843 : storeu_pd(adfM2, vM2_lo);
6844 801 : storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
6845 801 : storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
6846 801 : storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
6847 801 : storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
6848 :
6849 4005 : for (int i = 0; i < VALS_PER_LOOP; ++i)
6850 : {
6851 3204 : dfMin = std::min(dfMin, adfMin[i]);
6852 3204 : dfMax = std::max(dfMax, adfMax[i]);
6853 3204 : const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
6854 3204 : if (adfMean[i] != dfBlockMean)
6855 : {
6856 1874 : const double dfDelta = adfMean[i] - dfBlockMean;
6857 1874 : dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
6858 1874 : dfBlockM2 += adfM2[i] + dfDelta * dfDelta * dfBlockValidCount *
6859 1874 : dfValidVectorCount /
6860 : dfNewValidCount;
6861 : }
6862 3204 : dfBlockValidCount = dfNewValidCount;
6863 : }
6864 : }
6865 :
6866 1351 : return iX;
6867 : }
6868 :
6869 : #endif
6870 :
6871 : /************************************************************************/
6872 : /* ComputeStatistics() */
6873 : /************************************************************************/
6874 :
6875 : /**
6876 : * \brief Compute image statistics.
6877 : *
6878 : * Returns the minimum, maximum, mean and standard deviation of all
6879 : * pixel values in this band. If approximate statistics are sufficient,
6880 : * the bApproxOK flag can be set to true in which case overviews, or a
6881 : * subset of image tiles may be used in computing the statistics.
6882 : *
6883 : * Once computed, the statistics will generally be "set" back on the
6884 : * raster band using SetStatistics().
6885 : *
6886 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6887 : *
6888 : * This method is the same as the C function GDALComputeRasterStatistics().
6889 : *
6890 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6891 : * or a subset of all tiles.
6892 : *
6893 : * @param pdfMin Location into which to load image minimum (may be NULL).
6894 : *
6895 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6896 : *
6897 : * @param pdfMean Location into which to load image mean (may be NULL).
6898 : *
6899 : * @param pdfStdDev Location into which to load image standard deviation
6900 : * (may be NULL).
6901 : *
6902 : * @param pfnProgress a function to call to report progress, or NULL.
6903 : *
6904 : * @param pProgressData application data to pass to the progress function.
6905 : *
6906 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6907 : * is terminated by the user.
6908 : */
6909 :
6910 512 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6911 : double *pdfMax, double *pdfMean,
6912 : double *pdfStdDev,
6913 : GDALProgressFunc pfnProgress,
6914 : void *pProgressData)
6915 :
6916 : {
6917 512 : if (pfnProgress == nullptr)
6918 183 : pfnProgress = GDALDummyProgress;
6919 :
6920 : /* -------------------------------------------------------------------- */
6921 : /* If we have overview bands, use them for statistics. */
6922 : /* -------------------------------------------------------------------- */
6923 512 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6924 : {
6925 : GDALRasterBand *poBand =
6926 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6927 :
6928 3 : if (poBand != this)
6929 : {
6930 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6931 : pdfMean, pdfStdDev,
6932 3 : pfnProgress, pProgressData);
6933 3 : if (eErr == CE_None)
6934 : {
6935 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6936 : {
6937 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6938 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6939 : }
6940 :
6941 : /* transfer metadata from overview band to this */
6942 : const char *pszPercentValid =
6943 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6944 :
6945 3 : if (pszPercentValid != nullptr)
6946 : {
6947 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6948 3 : pszPercentValid);
6949 : }
6950 : }
6951 3 : return eErr;
6952 : }
6953 : }
6954 :
6955 509 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6956 : {
6957 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6958 0 : return CE_Failure;
6959 : }
6960 :
6961 : /* -------------------------------------------------------------------- */
6962 : /* Read actual data and compute statistics. */
6963 : /* -------------------------------------------------------------------- */
6964 : // Using Welford algorithm:
6965 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6966 : // to compute standard deviation in a more numerically robust way than
6967 : // the difference of the sum of square values with the square of the sum.
6968 : // dfMean and dfM2 are updated at each sample.
6969 : // dfM2 is the sum of square of differences to the current mean.
6970 509 : double dfMin = std::numeric_limits<double>::infinity();
6971 509 : double dfMax = -std::numeric_limits<double>::infinity();
6972 509 : double dfMean = 0.0;
6973 509 : double dfM2 = 0.0;
6974 :
6975 : GDALRasterIOExtraArg sExtraArg;
6976 509 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6977 :
6978 509 : GDALNoDataValues sNoDataValues(this, eDataType);
6979 509 : GDALRasterBand *poMaskBand = nullptr;
6980 509 : if (!sNoDataValues.bGotNoDataValue)
6981 : {
6982 476 : const int l_nMaskFlags = GetMaskFlags();
6983 522 : if (l_nMaskFlags != GMF_ALL_VALID &&
6984 46 : GetColorInterpretation() != GCI_AlphaBand)
6985 : {
6986 46 : poMaskBand = GetMaskBand();
6987 : }
6988 : }
6989 :
6990 509 : bool bSignedByte = false;
6991 509 : if (eDataType == GDT_Byte)
6992 : {
6993 212 : EnablePixelTypeSignedByteWarning(false);
6994 : const char *pszPixelType =
6995 212 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6996 212 : EnablePixelTypeSignedByteWarning(true);
6997 212 : bSignedByte =
6998 212 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6999 : }
7000 :
7001 509 : GUIntBig nSampleCount = 0;
7002 509 : GUIntBig nValidCount = 0;
7003 :
7004 509 : if (bApproxOK && HasArbitraryOverviews())
7005 : {
7006 : /* --------------------------------------------------------------------
7007 : */
7008 : /* Figure out how much the image should be reduced to get an */
7009 : /* approximate value. */
7010 : /* --------------------------------------------------------------------
7011 : */
7012 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7013 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7014 :
7015 0 : int nXReduced = nRasterXSize;
7016 0 : int nYReduced = nRasterYSize;
7017 0 : if (dfReduction > 1.0)
7018 : {
7019 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7020 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7021 :
7022 : // Catch the case of huge resizing ratios here
7023 0 : if (nXReduced == 0)
7024 0 : nXReduced = 1;
7025 0 : if (nYReduced == 0)
7026 0 : nYReduced = 1;
7027 : }
7028 :
7029 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
7030 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7031 :
7032 : const CPLErr eErr =
7033 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7034 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7035 0 : if (eErr != CE_None)
7036 : {
7037 0 : CPLFree(pData);
7038 0 : return eErr;
7039 : }
7040 :
7041 0 : GByte *pabyMaskData = nullptr;
7042 0 : if (poMaskBand)
7043 : {
7044 : pabyMaskData =
7045 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7046 0 : if (!pabyMaskData)
7047 : {
7048 0 : CPLFree(pData);
7049 0 : return CE_Failure;
7050 : }
7051 :
7052 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7053 : pabyMaskData, nXReduced, nYReduced,
7054 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7055 : {
7056 0 : CPLFree(pData);
7057 0 : CPLFree(pabyMaskData);
7058 0 : return CE_Failure;
7059 : }
7060 : }
7061 :
7062 : /* this isn't the fastest way to do this, but is easier for now */
7063 0 : for (int iY = 0; iY < nYReduced; iY++)
7064 : {
7065 0 : for (int iX = 0; iX < nXReduced; iX++)
7066 : {
7067 0 : const int iOffset = iX + iY * nXReduced;
7068 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7069 0 : continue;
7070 :
7071 0 : bool bValid = true;
7072 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7073 0 : iOffset, sNoDataValues, bValid);
7074 0 : if (!bValid)
7075 0 : continue;
7076 :
7077 0 : dfMin = std::min(dfMin, dfValue);
7078 0 : dfMax = std::max(dfMax, dfValue);
7079 :
7080 0 : nValidCount++;
7081 0 : if (dfMin == dfMax)
7082 : {
7083 0 : if (nValidCount == 1)
7084 0 : dfMean = dfMin;
7085 : }
7086 : else
7087 : {
7088 0 : const double dfDelta = dfValue - dfMean;
7089 0 : dfMean += dfDelta / nValidCount;
7090 0 : dfM2 += dfDelta * (dfValue - dfMean);
7091 : }
7092 : }
7093 : }
7094 :
7095 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
7096 :
7097 0 : CPLFree(pData);
7098 0 : CPLFree(pabyMaskData);
7099 : }
7100 :
7101 : else // No arbitrary overviews.
7102 : {
7103 509 : if (!InitBlockInfo())
7104 242 : return CE_Failure;
7105 :
7106 : /* --------------------------------------------------------------------
7107 : */
7108 : /* Figure out the ratio of blocks we will read to get an */
7109 : /* approximate value. */
7110 : /* --------------------------------------------------------------------
7111 : */
7112 509 : int nSampleRate = 1;
7113 509 : if (bApproxOK)
7114 : {
7115 43 : nSampleRate = static_cast<int>(std::max(
7116 86 : 1.0,
7117 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7118 : // We want to avoid probing only the first column of blocks for
7119 : // a square shaped raster, because it is not unlikely that it may
7120 : // be padding only (#6378)
7121 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7122 1 : nSampleRate += 1;
7123 : }
7124 509 : if (nSampleRate == 1)
7125 475 : bApproxOK = false;
7126 :
7127 : // Particular case for GDT_Byte and GUInt16 that only use integral types
7128 : // for each block, and possibly for the whole raster.
7129 509 : if (!poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7130 268 : eDataType == GDT_UInt16))
7131 : {
7132 : // We can do integer computation on the whole raster in the Byte case
7133 : // only if the number of pixels explored is lower than
7134 : // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
7135 : // Should be 99.99999% of cases.
7136 : // For GUInt16, this limits to raster of 4 giga pixels
7137 :
7138 : const bool bIntegerStats =
7139 437 : ((eDataType == GDT_Byte &&
7140 195 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7141 195 : nSampleRate <
7142 195 : GUINTBIG_MAX / (255U * 255U) /
7143 195 : (static_cast<GUInt64>(nBlockXSize) *
7144 195 : static_cast<GUInt64>(nBlockYSize))) ||
7145 47 : (eDataType == GDT_UInt16 &&
7146 47 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7147 47 : nSampleRate <
7148 47 : GUINTBIG_MAX / (65535U * 65535U) /
7149 47 : (static_cast<GUInt64>(nBlockXSize) *
7150 531 : static_cast<GUInt64>(nBlockYSize)))) &&
7151 : // Can be set to NO for easier debugging of the !bIntegerStats
7152 : // case which requires huge rasters to trigger
7153 242 : CPLTestBool(
7154 242 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7155 :
7156 242 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
7157 242 : GUInt32 nMin = nMaxValueType;
7158 242 : GUInt32 nMax = 0;
7159 242 : GUIntBig nSum = 0;
7160 242 : GUIntBig nSumSquare = 0;
7161 : // If no valid nodata, map to invalid value (256 for Byte)
7162 242 : const GUInt32 nNoDataValue =
7163 269 : (sNoDataValues.bGotNoDataValue &&
7164 27 : sNoDataValues.dfNoDataValue >= 0 &&
7165 27 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7166 27 : fabs(sNoDataValues.dfNoDataValue -
7167 27 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7168 : 1e-10)) < 1e-10)
7169 269 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7170 : : nMaxValueType + 1;
7171 :
7172 242 : for (GIntBig iSampleBlock = 0;
7173 13041 : iSampleBlock <
7174 13041 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7175 12799 : iSampleBlock += nSampleRate)
7176 : {
7177 12799 : const int iYBlock =
7178 12799 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7179 12799 : const int iXBlock =
7180 12799 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7181 :
7182 : GDALRasterBlock *const poBlock =
7183 12799 : GetLockedBlockRef(iXBlock, iYBlock);
7184 12819 : if (poBlock == nullptr)
7185 0 : return CE_Failure;
7186 :
7187 12819 : void *const pData = poBlock->GetDataRef();
7188 :
7189 12819 : int nXCheck = 0, nYCheck = 0;
7190 12819 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7191 :
7192 12819 : GUIntBig nBlockSum = 0;
7193 12819 : GUIntBig nBlockSumSquare = 0;
7194 12819 : GUIntBig nBlockSampleCount = 0;
7195 12819 : GUIntBig nBlockValidCount = 0;
7196 12819 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7197 12819 : GUIntBig &nBlockSumSquareRef =
7198 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7199 12819 : GUIntBig &nBlockSampleCountRef =
7200 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7201 12819 : GUIntBig &nBlockValidCountRef =
7202 : bIntegerStats ? nValidCount : nBlockValidCount;
7203 :
7204 12819 : if (eDataType == GDT_Byte)
7205 : {
7206 : ComputeStatisticsInternal<
7207 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7208 12137 : f(nXCheck, nBlockXSize, nYCheck,
7209 : static_cast<const GByte *>(pData),
7210 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7211 : nMax, nBlockSumRef, nBlockSumSquareRef,
7212 : nBlockSampleCountRef, nBlockValidCountRef);
7213 : }
7214 : else
7215 : {
7216 : ComputeStatisticsInternal<
7217 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7218 682 : f(nXCheck, nBlockXSize, nYCheck,
7219 : static_cast<const GUInt16 *>(pData),
7220 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7221 : nMax, nBlockSumRef, nBlockSumSquareRef,
7222 : nBlockSampleCountRef, nBlockValidCountRef);
7223 : }
7224 :
7225 12819 : poBlock->DropLock();
7226 :
7227 12819 : if (!bIntegerStats)
7228 : {
7229 169 : nSampleCount += nBlockSampleCount;
7230 169 : if (nBlockValidCount)
7231 : {
7232 : // Update the global mean and M2 (the difference of the
7233 : // square to the mean) from the values of the block
7234 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7235 169 : const double dfBlockValidCount =
7236 169 : static_cast<double>(nBlockValidCount);
7237 169 : const double dfBlockMean =
7238 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7239 : const double dfBlockM2 =
7240 169 : static_cast<double>(
7241 169 : GDALUInt128::Mul(nBlockSumSquare,
7242 169 : nBlockValidCount) -
7243 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7244 169 : dfBlockValidCount;
7245 169 : const double dfDelta = dfBlockMean - dfMean;
7246 169 : const auto nNewValidCount =
7247 169 : nValidCount + nBlockValidCount;
7248 169 : const double dfNewValidCount =
7249 : static_cast<double>(nNewValidCount);
7250 169 : dfMean +=
7251 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7252 169 : dfM2 +=
7253 169 : dfBlockM2 + dfDelta * dfDelta *
7254 169 : static_cast<double>(nValidCount) *
7255 169 : dfBlockValidCount / dfNewValidCount;
7256 169 : nValidCount = nNewValidCount;
7257 : }
7258 : }
7259 :
7260 12819 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7261 12819 : (static_cast<double>(nBlocksPerRow) *
7262 12819 : nBlocksPerColumn),
7263 : "Compute Statistics", pProgressData))
7264 : {
7265 20 : ReportError(CE_Failure, CPLE_UserInterrupt,
7266 : "User terminated");
7267 0 : return CE_Failure;
7268 : }
7269 : }
7270 :
7271 242 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7272 : {
7273 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7274 0 : return CE_Failure;
7275 : }
7276 :
7277 242 : double dfStdDev = 0;
7278 242 : if (bIntegerStats)
7279 : {
7280 218 : if (nValidCount)
7281 209 : dfMean = static_cast<double>(nSum) / nValidCount;
7282 :
7283 : // To avoid potential precision issues when doing the difference,
7284 : // we need to do that computation on 128 bit rather than casting
7285 : // to double
7286 : const GDALUInt128 nTmpForStdDev(
7287 218 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7288 436 : GDALUInt128::Mul(nSum, nSum));
7289 218 : dfStdDev =
7290 218 : nValidCount > 0
7291 218 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7292 : : 0.0;
7293 : }
7294 24 : else if (nValidCount > 0)
7295 : {
7296 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7297 : }
7298 :
7299 : /// Save computed information
7300 242 : if (nValidCount > 0)
7301 : {
7302 233 : if (bApproxOK)
7303 : {
7304 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7305 : }
7306 209 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7307 : {
7308 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7309 : }
7310 233 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7311 : }
7312 :
7313 242 : SetValidPercent(nSampleCount, nValidCount);
7314 :
7315 : /* --------------------------------------------------------------------
7316 : */
7317 : /* Record results. */
7318 : /* --------------------------------------------------------------------
7319 : */
7320 242 : if (pdfMin != nullptr)
7321 239 : *pdfMin = nValidCount ? nMin : 0;
7322 242 : if (pdfMax != nullptr)
7323 239 : *pdfMax = nValidCount ? nMax : 0;
7324 :
7325 242 : if (pdfMean != nullptr)
7326 235 : *pdfMean = dfMean;
7327 :
7328 242 : if (pdfStdDev != nullptr)
7329 235 : *pdfStdDev = dfStdDev;
7330 :
7331 242 : if (nValidCount > 0)
7332 233 : return CE_None;
7333 :
7334 9 : ReportError(CE_Failure, CPLE_AppDefined,
7335 : "Failed to compute statistics, no valid pixels found "
7336 : "in sampling.");
7337 9 : return CE_Failure;
7338 : }
7339 :
7340 267 : GByte *pabyMaskData = nullptr;
7341 267 : if (poMaskBand)
7342 : {
7343 : pabyMaskData = static_cast<GByte *>(
7344 46 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7345 46 : if (!pabyMaskData)
7346 : {
7347 0 : return CE_Failure;
7348 : }
7349 : }
7350 :
7351 267 : float fMin = std::numeric_limits<float>::infinity();
7352 267 : float fMax = -std::numeric_limits<float>::infinity();
7353 : const bool bFloat32Optim =
7354 44 : eDataType == GDT_Float32 && !pabyMaskData &&
7355 329 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7356 18 : CPLTestBool(
7357 267 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7358 :
7359 : #if (defined(__x86_64__) || defined(_M_X64))
7360 : const bool bFloat64Optim =
7361 13 : eDataType == GDT_Float64 && !pabyMaskData &&
7362 293 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7363 13 : CPLTestBool(
7364 267 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7365 : #endif
7366 :
7367 267 : for (GIntBig iSampleBlock = 0;
7368 5918 : iSampleBlock <
7369 5918 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7370 5651 : iSampleBlock += nSampleRate)
7371 : {
7372 5651 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7373 5651 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7374 :
7375 5651 : int nXCheck = 0, nYCheck = 0;
7376 5651 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7377 :
7378 6224 : if (poMaskBand &&
7379 573 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7380 573 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7381 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
7382 573 : 0, nBlockXSize, nullptr) != CE_None)
7383 : {
7384 0 : CPLFree(pabyMaskData);
7385 0 : return CE_Failure;
7386 : }
7387 :
7388 : GDALRasterBlock *const poBlock =
7389 5651 : GetLockedBlockRef(iXBlock, iYBlock);
7390 5651 : if (poBlock == nullptr)
7391 : {
7392 0 : CPLFree(pabyMaskData);
7393 0 : return CE_Failure;
7394 : }
7395 :
7396 5651 : const void *const pData = poBlock->GetDataRef();
7397 :
7398 5651 : if (bFloat32Optim)
7399 : {
7400 2330 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7401 0 : !std::isnan(sNoDataValues.fNoDataValue);
7402 2330 : float fBlockMean = 0.0f;
7403 2330 : float fBlockM2 = 0.0f;
7404 2330 : int nBlockValidCount = 0;
7405 7219 : for (int iY = 0; iY < nYCheck; iY++)
7406 : {
7407 4889 : const int iOffset = iY * nBlockXSize;
7408 4889 : if (nBlockValidCount && fMin != fMax)
7409 : {
7410 2432 : int iX = 0;
7411 : #if (defined(__x86_64__) || defined(_M_X64))
7412 2432 : if (bHasNoData)
7413 : {
7414 : iX = ComputeStatisticsFloat32_SSE2<
7415 : /* bCheckMinEqMax = */ false,
7416 0 : /* bHasNoData = */ true>(
7417 0 : static_cast<const float *>(pData) + iOffset,
7418 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7419 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7420 : }
7421 : else
7422 : {
7423 : iX = ComputeStatisticsFloat32_SSE2<
7424 : /* bCheckMinEqMax = */ false,
7425 2432 : /* bHasNoData = */ false>(
7426 2432 : static_cast<const float *>(pData) + iOffset,
7427 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7428 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7429 : }
7430 : #endif
7431 2961 : for (; iX < nXCheck; iX++)
7432 : {
7433 529 : const float fValue =
7434 529 : static_cast<const float *>(pData)[iOffset + iX];
7435 529 : if (std::isnan(fValue) ||
7436 0 : (bHasNoData &&
7437 0 : fValue == sNoDataValues.fNoDataValue))
7438 11 : continue;
7439 518 : fMin = std::min(fMin, fValue);
7440 518 : fMax = std::max(fMax, fValue);
7441 518 : ++nBlockValidCount;
7442 518 : const float fDelta = fValue - fBlockMean;
7443 518 : fBlockMean +=
7444 518 : fDelta / static_cast<float>(nBlockValidCount);
7445 518 : fBlockM2 += fDelta * (fValue - fBlockMean);
7446 2432 : }
7447 : }
7448 : else
7449 : {
7450 2457 : int iX = 0;
7451 2457 : if (nBlockValidCount == 0)
7452 : {
7453 2330 : for (; iX < nXCheck; iX++)
7454 : {
7455 2330 : const float fValue = static_cast<const float *>(
7456 2330 : pData)[iOffset + iX];
7457 2330 : if (std::isnan(fValue) ||
7458 0 : (bHasNoData &&
7459 0 : fValue == sNoDataValues.fNoDataValue))
7460 0 : continue;
7461 2330 : fMin = std::min(fMin, fValue);
7462 2330 : fMax = std::max(fMax, fValue);
7463 2330 : nBlockValidCount = 1;
7464 2330 : fBlockMean = fValue;
7465 2330 : iX++;
7466 2330 : break;
7467 : }
7468 : }
7469 : #if (defined(__x86_64__) || defined(_M_X64))
7470 2457 : if (bHasNoData)
7471 : {
7472 : iX = ComputeStatisticsFloat32_SSE2<
7473 : /* bCheckMinEqMax = */ true,
7474 0 : /* bHasNoData = */ true>(
7475 0 : static_cast<const float *>(pData) + iOffset,
7476 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7477 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7478 : }
7479 : else
7480 : {
7481 : iX = ComputeStatisticsFloat32_SSE2<
7482 : /* bCheckMinEqMax = */ true,
7483 2457 : /* bHasNoData = */ false>(
7484 2457 : static_cast<const float *>(pData) + iOffset,
7485 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7486 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7487 : }
7488 : #endif
7489 17534 : for (; iX < nXCheck; iX++)
7490 : {
7491 15077 : const float fValue =
7492 15077 : static_cast<const float *>(pData)[iOffset + iX];
7493 15077 : if (std::isnan(fValue) ||
7494 0 : (bHasNoData &&
7495 0 : fValue == sNoDataValues.fNoDataValue))
7496 1 : continue;
7497 15076 : fMin = std::min(fMin, fValue);
7498 15076 : fMax = std::max(fMax, fValue);
7499 15076 : ++nBlockValidCount;
7500 15076 : if (fMin != fMax)
7501 : {
7502 7123 : const float fDelta = fValue - fBlockMean;
7503 7123 : fBlockMean += fDelta / static_cast<float>(
7504 : nBlockValidCount);
7505 7123 : fBlockM2 += fDelta * (fValue - fBlockMean);
7506 : }
7507 : }
7508 : }
7509 : }
7510 :
7511 2330 : if (nBlockValidCount)
7512 : {
7513 : // Update the global mean and M2 (the difference of the
7514 : // square to the mean) from the values of the block
7515 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7516 2330 : const auto nNewValidCount = nValidCount + nBlockValidCount;
7517 2330 : const double dfBlockMean = static_cast<double>(fBlockMean);
7518 2330 : if (dfBlockMean != dfMean)
7519 : {
7520 1066 : const double dfBlockM2 = static_cast<double>(fBlockM2);
7521 1066 : if (nValidCount == 0)
7522 : {
7523 13 : dfMean = dfBlockMean;
7524 13 : dfM2 = dfBlockM2;
7525 : }
7526 : else
7527 : {
7528 1053 : const double dfBlockValidCount =
7529 1053 : static_cast<double>(nBlockValidCount);
7530 1053 : const double dfDelta = dfBlockMean - dfMean;
7531 1053 : const double dfNewValidCount =
7532 : static_cast<double>(nNewValidCount);
7533 1053 : dfMean +=
7534 1053 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7535 1053 : dfM2 += dfBlockM2 +
7536 1053 : dfDelta * dfDelta *
7537 1053 : static_cast<double>(nValidCount) *
7538 1053 : dfBlockValidCount / dfNewValidCount;
7539 : }
7540 : }
7541 2330 : nValidCount = nNewValidCount;
7542 : }
7543 : }
7544 :
7545 : #if (defined(__x86_64__) || defined(_M_X64))
7546 3321 : else if (bFloat64Optim)
7547 : {
7548 : const bool bHasNoData =
7549 545 : sNoDataValues.bGotNoDataValue &&
7550 263 : !std::isnan(sNoDataValues.dfNoDataValue);
7551 282 : double dfBlockMean = 0;
7552 282 : double dfBlockM2 = 0;
7553 282 : double dfBlockValidCount = 0;
7554 1633 : for (int iY = 0; iY < nYCheck; iY++)
7555 : {
7556 1351 : const int iOffset = iY * nBlockXSize;
7557 1351 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7558 : {
7559 813 : int iX = 0;
7560 813 : if (bHasNoData)
7561 : {
7562 : iX = ComputeStatisticsFloat64_SSE2<
7563 : /* bCheckMinEqMax = */ false,
7564 381 : /* bHasNoData = */ true>(
7565 381 : static_cast<const double *>(pData) + iOffset,
7566 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7567 : dfMax, dfBlockMean, dfBlockM2,
7568 : dfBlockValidCount);
7569 : }
7570 : else
7571 : {
7572 : iX = ComputeStatisticsFloat64_SSE2<
7573 : /* bCheckMinEqMax = */ false,
7574 432 : /* bHasNoData = */ false>(
7575 432 : static_cast<const double *>(pData) + iOffset,
7576 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7577 : dfMax, dfBlockMean, dfBlockM2,
7578 : dfBlockValidCount);
7579 : }
7580 1931 : for (; iX < nXCheck; iX++)
7581 : {
7582 1118 : const double dfValue = static_cast<const double *>(
7583 1118 : pData)[iOffset + iX];
7584 1625 : if (std::isnan(dfValue) ||
7585 507 : (bHasNoData &&
7586 507 : dfValue == sNoDataValues.dfNoDataValue))
7587 53 : continue;
7588 1065 : dfMin = std::min(dfMin, dfValue);
7589 1065 : dfMax = std::max(dfMax, dfValue);
7590 1065 : dfBlockValidCount += 1.0;
7591 1065 : const double dfDelta = dfValue - dfBlockMean;
7592 1065 : dfBlockMean += dfDelta / dfBlockValidCount;
7593 1065 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7594 813 : }
7595 : }
7596 : else
7597 : {
7598 538 : int iX = 0;
7599 538 : if (dfBlockValidCount == 0)
7600 : {
7601 7661 : for (; iX < nXCheck; iX++)
7602 : {
7603 7627 : const double dfValue =
7604 : static_cast<const double *>(
7605 7627 : pData)[iOffset + iX];
7606 15235 : if (std::isnan(dfValue) ||
7607 7608 : (bHasNoData &&
7608 7608 : dfValue == sNoDataValues.dfNoDataValue))
7609 7377 : continue;
7610 250 : dfMin = std::min(dfMin, dfValue);
7611 250 : dfMax = std::max(dfMax, dfValue);
7612 250 : dfBlockValidCount = 1;
7613 250 : dfBlockMean = dfValue;
7614 250 : iX++;
7615 250 : break;
7616 : }
7617 : }
7618 538 : if (bHasNoData)
7619 : {
7620 : iX = ComputeStatisticsFloat64_SSE2<
7621 : /* bCheckMinEqMax = */ true,
7622 392 : /* bHasNoData = */ true>(
7623 392 : static_cast<const double *>(pData) + iOffset,
7624 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7625 : dfMax, dfBlockMean, dfBlockM2,
7626 : dfBlockValidCount);
7627 : }
7628 : else
7629 : {
7630 : iX = ComputeStatisticsFloat64_SSE2<
7631 : /* bCheckMinEqMax = */ true,
7632 146 : /* bHasNoData = */ false>(
7633 146 : static_cast<const double *>(pData) + iOffset,
7634 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7635 : dfMax, dfBlockMean, dfBlockM2,
7636 : dfBlockValidCount);
7637 : }
7638 1081 : for (; iX < nXCheck; iX++)
7639 : {
7640 543 : const double dfValue = static_cast<const double *>(
7641 543 : pData)[iOffset + iX];
7642 1065 : if (std::isnan(dfValue) ||
7643 522 : (bHasNoData &&
7644 522 : dfValue == sNoDataValues.dfNoDataValue))
7645 140 : continue;
7646 403 : dfMin = std::min(dfMin, dfValue);
7647 403 : dfMax = std::max(dfMax, dfValue);
7648 403 : dfBlockValidCount += 1.0;
7649 403 : if (dfMin != dfMax)
7650 : {
7651 128 : const double dfDelta = dfValue - dfBlockMean;
7652 128 : dfBlockMean += dfDelta / dfBlockValidCount;
7653 128 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7654 : }
7655 : }
7656 : }
7657 : }
7658 :
7659 282 : if (dfBlockValidCount > 0)
7660 : {
7661 : // Update the global mean and M2 (the difference of the
7662 : // square to the mean) from the values of the block
7663 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7664 250 : const auto nNewValidCount =
7665 250 : nValidCount + static_cast<int>(dfBlockValidCount);
7666 250 : if (dfBlockMean != dfMean)
7667 : {
7668 237 : if (nValidCount == 0)
7669 : {
7670 11 : dfMean = dfBlockMean;
7671 11 : dfM2 = dfBlockM2;
7672 : }
7673 : else
7674 : {
7675 226 : const double dfDelta = dfBlockMean - dfMean;
7676 226 : const double dfNewValidCount =
7677 : static_cast<double>(nNewValidCount);
7678 226 : dfMean +=
7679 226 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7680 226 : dfM2 += dfBlockM2 +
7681 226 : dfDelta * dfDelta *
7682 226 : static_cast<double>(nValidCount) *
7683 226 : dfBlockValidCount / dfNewValidCount;
7684 : }
7685 : }
7686 250 : nValidCount = nNewValidCount;
7687 : }
7688 : }
7689 : #endif // (defined(__x86_64__) || defined(_M_X64))
7690 :
7691 : else
7692 : {
7693 : // This isn't the fastest way to do this, but is easier for now.
7694 8754 : for (int iY = 0; iY < nYCheck; iY++)
7695 : {
7696 5715 : if (nValidCount && dfMin != dfMax)
7697 : {
7698 212546 : for (int iX = 0; iX < nXCheck; iX++)
7699 : {
7700 209962 : const GPtrDiff_t iOffset =
7701 209962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7702 209962 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7703 9635 : continue;
7704 :
7705 200339 : bool bValid = true;
7706 : double dfValue =
7707 200339 : GetPixelValue(eDataType, bSignedByte, pData,
7708 200339 : iOffset, sNoDataValues, bValid);
7709 :
7710 200339 : if (!bValid)
7711 12 : continue;
7712 :
7713 200327 : dfMin = std::min(dfMin, dfValue);
7714 200327 : dfMax = std::max(dfMax, dfValue);
7715 :
7716 200327 : nValidCount++;
7717 200327 : const double dfDelta = dfValue - dfMean;
7718 200327 : dfMean += dfDelta / nValidCount;
7719 200327 : dfM2 += dfDelta * (dfValue - dfMean);
7720 2584 : }
7721 : }
7722 : else
7723 : {
7724 3131 : int iX = 0;
7725 3131 : if (nValidCount == 0)
7726 : {
7727 94577 : for (; iX < nXCheck; iX++)
7728 : {
7729 94520 : const GPtrDiff_t iOffset =
7730 94520 : iX +
7731 94520 : static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7732 94520 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7733 94282 : continue;
7734 :
7735 239 : bool bValid = true;
7736 239 : double dfValue = GetPixelValue(
7737 : eDataType, bSignedByte, pData, iOffset,
7738 : sNoDataValues, bValid);
7739 :
7740 239 : if (!bValid)
7741 1 : continue;
7742 :
7743 238 : dfMin = dfValue;
7744 238 : dfMax = dfValue;
7745 238 : dfMean = dfValue;
7746 238 : nValidCount = 1;
7747 238 : iX++;
7748 238 : break;
7749 : }
7750 : }
7751 227675 : for (; iX < nXCheck; iX++)
7752 : {
7753 224544 : const GPtrDiff_t iOffset =
7754 224544 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7755 224544 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7756 358 : continue;
7757 :
7758 224187 : bool bValid = true;
7759 : double dfValue =
7760 224187 : GetPixelValue(eDataType, bSignedByte, pData,
7761 224187 : iOffset, sNoDataValues, bValid);
7762 :
7763 224187 : if (!bValid)
7764 1 : continue;
7765 :
7766 224186 : dfMin = std::min(dfMin, dfValue);
7767 224186 : dfMax = std::max(dfMax, dfValue);
7768 :
7769 224186 : nValidCount++;
7770 224186 : if (dfMin != dfMax)
7771 : {
7772 2170 : const double dfDelta = dfValue - dfMean;
7773 2170 : dfMean += dfDelta / nValidCount;
7774 2170 : dfM2 += dfDelta * (dfValue - dfMean);
7775 : }
7776 : }
7777 : }
7778 : }
7779 : }
7780 :
7781 5651 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
7782 :
7783 5651 : poBlock->DropLock();
7784 :
7785 5651 : if (!pfnProgress(
7786 5651 : static_cast<double>(iSampleBlock) /
7787 5651 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
7788 : "Compute Statistics", pProgressData))
7789 : {
7790 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7791 0 : CPLFree(pabyMaskData);
7792 0 : return CE_Failure;
7793 : }
7794 : }
7795 :
7796 267 : if (bFloat32Optim)
7797 : {
7798 17 : dfMin = static_cast<double>(fMin);
7799 17 : dfMax = static_cast<double>(fMax);
7800 : }
7801 267 : CPLFree(pabyMaskData);
7802 : }
7803 :
7804 267 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7805 : {
7806 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7807 0 : return CE_Failure;
7808 : }
7809 :
7810 : /* -------------------------------------------------------------------- */
7811 : /* Save computed information. */
7812 : /* -------------------------------------------------------------------- */
7813 267 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7814 :
7815 267 : if (nValidCount > 0)
7816 : {
7817 266 : if (bApproxOK)
7818 : {
7819 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7820 : }
7821 258 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7822 : {
7823 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7824 : }
7825 266 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7826 : }
7827 : else
7828 : {
7829 1 : dfMin = 0.0;
7830 1 : dfMax = 0.0;
7831 : }
7832 :
7833 267 : SetValidPercent(nSampleCount, nValidCount);
7834 :
7835 : /* -------------------------------------------------------------------- */
7836 : /* Record results. */
7837 : /* -------------------------------------------------------------------- */
7838 267 : if (pdfMin != nullptr)
7839 264 : *pdfMin = dfMin;
7840 267 : if (pdfMax != nullptr)
7841 264 : *pdfMax = dfMax;
7842 :
7843 267 : if (pdfMean != nullptr)
7844 261 : *pdfMean = dfMean;
7845 :
7846 267 : if (pdfStdDev != nullptr)
7847 261 : *pdfStdDev = dfStdDev;
7848 :
7849 267 : if (nValidCount > 0)
7850 266 : return CE_None;
7851 :
7852 1 : ReportError(
7853 : CE_Failure, CPLE_AppDefined,
7854 : "Failed to compute statistics, no valid pixels found in sampling.");
7855 1 : return CE_Failure;
7856 : }
7857 :
7858 : /************************************************************************/
7859 : /* GDALComputeRasterStatistics() */
7860 : /************************************************************************/
7861 :
7862 : /**
7863 : * \brief Compute image statistics.
7864 : *
7865 : * @see GDALRasterBand::ComputeStatistics()
7866 : */
7867 :
7868 169 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7869 : int bApproxOK, double *pdfMin,
7870 : double *pdfMax, double *pdfMean,
7871 : double *pdfStdDev,
7872 : GDALProgressFunc pfnProgress,
7873 : void *pProgressData)
7874 :
7875 : {
7876 169 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7877 :
7878 169 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7879 :
7880 169 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7881 169 : pdfStdDev, pfnProgress, pProgressData);
7882 : }
7883 :
7884 : /************************************************************************/
7885 : /* SetStatistics() */
7886 : /************************************************************************/
7887 :
7888 : /**
7889 : * \brief Set statistics on band.
7890 : *
7891 : * This method can be used to store min/max/mean/standard deviation
7892 : * statistics on a raster band.
7893 : *
7894 : * The default implementation stores them as metadata, and will only work
7895 : * on formats that can save arbitrary metadata. This method cannot detect
7896 : * whether metadata will be properly saved and so may return CE_None even
7897 : * if the statistics will never be saved.
7898 : *
7899 : * This method is the same as the C function GDALSetRasterStatistics().
7900 : *
7901 : * @param dfMin minimum pixel value.
7902 : *
7903 : * @param dfMax maximum pixel value.
7904 : *
7905 : * @param dfMean mean (average) of all pixel values.
7906 : *
7907 : * @param dfStdDev Standard deviation of all pixel values.
7908 : *
7909 : * @return CE_None on success or CE_Failure on failure.
7910 : */
7911 :
7912 532 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7913 : double dfStdDev)
7914 :
7915 : {
7916 532 : char szValue[128] = {0};
7917 :
7918 532 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7919 532 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7920 :
7921 532 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7922 532 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7923 :
7924 532 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7925 532 : SetMetadataItem("STATISTICS_MEAN", szValue);
7926 :
7927 532 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7928 532 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7929 :
7930 532 : return CE_None;
7931 : }
7932 :
7933 : /************************************************************************/
7934 : /* GDALSetRasterStatistics() */
7935 : /************************************************************************/
7936 :
7937 : /**
7938 : * \brief Set statistics on band.
7939 : *
7940 : * @see GDALRasterBand::SetStatistics()
7941 : */
7942 :
7943 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7944 : double dfMax, double dfMean,
7945 : double dfStdDev)
7946 :
7947 : {
7948 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7949 :
7950 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7951 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7952 : }
7953 :
7954 : /************************************************************************/
7955 : /* ComputeRasterMinMax() */
7956 : /************************************************************************/
7957 :
7958 : template <class T, bool HAS_NODATA>
7959 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7960 : T *pMax)
7961 : {
7962 2 : T min0 = *pMin;
7963 2 : T max0 = *pMax;
7964 2 : T min1 = *pMin;
7965 2 : T max1 = *pMax;
7966 : size_t i;
7967 2 : for (i = 0; i + 1 < nElts; i += 2)
7968 : {
7969 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
7970 : {
7971 0 : min0 = std::min(min0, buffer[i]);
7972 0 : max0 = std::max(max0, buffer[i]);
7973 : }
7974 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7975 : {
7976 0 : min1 = std::min(min1, buffer[i + 1]);
7977 0 : max1 = std::max(max1, buffer[i + 1]);
7978 : }
7979 : }
7980 2 : T min = std::min(min0, min1);
7981 2 : T max = std::max(max0, max1);
7982 2 : if (i < nElts)
7983 : {
7984 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
7985 : {
7986 2 : min = std::min(min, buffer[i]);
7987 2 : max = std::max(max, buffer[i]);
7988 : }
7989 : }
7990 2 : *pMin = min;
7991 2 : *pMax = max;
7992 2 : }
7993 :
7994 : template <GDALDataType eDataType, bool bSignedByte>
7995 : static void
7996 6703 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7997 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7998 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7999 : {
8000 6703 : double dfLocalMin = dfMin;
8001 6703 : double dfLocalMax = dfMax;
8002 :
8003 22051 : for (int iY = 0; iY < nYCheck; iY++)
8004 : {
8005 14858421 : for (int iX = 0; iX < nXCheck; iX++)
8006 : {
8007 14843085 : const GPtrDiff_t iOffset =
8008 14843085 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8009 14843085 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8010 109836 : continue;
8011 14760102 : bool bValid = true;
8012 14760102 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8013 : iOffset, sNoDataValues, bValid);
8014 14760102 : if (!bValid)
8015 26871 : continue;
8016 :
8017 14733202 : dfLocalMin = std::min(dfLocalMin, dfValue);
8018 14733202 : dfLocalMax = std::max(dfLocalMax, dfValue);
8019 : }
8020 : }
8021 :
8022 6703 : dfMin = dfLocalMin;
8023 6703 : dfMax = dfLocalMax;
8024 6703 : }
8025 :
8026 6703 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8027 : bool bSignedByte, int nXCheck, int nYCheck,
8028 : int nBlockXSize,
8029 : const GDALNoDataValues &sNoDataValues,
8030 : const GByte *pabyMaskData, double &dfMin,
8031 : double &dfMax)
8032 : {
8033 6703 : switch (eDataType)
8034 : {
8035 0 : case GDT_Unknown:
8036 0 : CPLAssert(false);
8037 : break;
8038 660 : case GDT_Byte:
8039 660 : if (bSignedByte)
8040 : {
8041 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
8042 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8043 : pabyMaskData, dfMin, dfMax);
8044 : }
8045 : else
8046 : {
8047 657 : ComputeMinMaxGeneric<GDT_Byte, false>(
8048 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8049 : pabyMaskData, dfMin, dfMax);
8050 : }
8051 660 : break;
8052 4 : case GDT_Int8:
8053 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8054 : nBlockXSize, sNoDataValues,
8055 : pabyMaskData, dfMin, dfMax);
8056 4 : break;
8057 969 : case GDT_UInt16:
8058 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8059 : nBlockXSize, sNoDataValues,
8060 : pabyMaskData, dfMin, dfMax);
8061 969 : break;
8062 2 : case GDT_Int16:
8063 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8064 : nBlockXSize, sNoDataValues,
8065 : pabyMaskData, dfMin, dfMax);
8066 2 : break;
8067 3 : case GDT_UInt32:
8068 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8069 : nBlockXSize, sNoDataValues,
8070 : pabyMaskData, dfMin, dfMax);
8071 3 : break;
8072 3 : case GDT_Int32:
8073 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8074 : nBlockXSize, sNoDataValues,
8075 : pabyMaskData, dfMin, dfMax);
8076 3 : break;
8077 4 : case GDT_UInt64:
8078 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8079 : nBlockXSize, sNoDataValues,
8080 : pabyMaskData, dfMin, dfMax);
8081 4 : break;
8082 4 : case GDT_Int64:
8083 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8084 : nBlockXSize, sNoDataValues,
8085 : pabyMaskData, dfMin, dfMax);
8086 4 : break;
8087 2 : case GDT_Float16:
8088 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8089 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8090 : pabyMaskData, dfMin, dfMax);
8091 2 : break;
8092 4941 : case GDT_Float32:
8093 4941 : ComputeMinMaxGeneric<GDT_Float32, false>(
8094 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8095 : pabyMaskData, dfMin, dfMax);
8096 4941 : break;
8097 1 : case GDT_Float64:
8098 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8099 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8100 : pabyMaskData, dfMin, dfMax);
8101 1 : break;
8102 9 : case GDT_CInt16:
8103 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8104 : nBlockXSize, sNoDataValues,
8105 : pabyMaskData, dfMin, dfMax);
8106 9 : break;
8107 9 : case GDT_CInt32:
8108 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8109 : nBlockXSize, sNoDataValues,
8110 : pabyMaskData, dfMin, dfMax);
8111 9 : break;
8112 0 : case GDT_CFloat16:
8113 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8114 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8115 : pabyMaskData, dfMin, dfMax);
8116 0 : break;
8117 75 : case GDT_CFloat32:
8118 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8119 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8120 : pabyMaskData, dfMin, dfMax);
8121 75 : break;
8122 17 : case GDT_CFloat64:
8123 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8124 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8125 : pabyMaskData, dfMin, dfMax);
8126 17 : break;
8127 0 : case GDT_TypeCount:
8128 0 : CPLAssert(false);
8129 : break;
8130 : }
8131 6703 : }
8132 :
8133 189 : static bool ComputeMinMaxGenericIterBlocks(
8134 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8135 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8136 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8137 : double &dfMin, double &dfMax)
8138 :
8139 : {
8140 189 : GByte *pabyMaskData = nullptr;
8141 : int nBlockXSize, nBlockYSize;
8142 189 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8143 :
8144 189 : if (poMaskBand)
8145 : {
8146 : pabyMaskData =
8147 125 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8148 125 : if (!pabyMaskData)
8149 : {
8150 0 : return false;
8151 : }
8152 : }
8153 :
8154 6892 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8155 6703 : iSampleBlock += nSampleRate)
8156 : {
8157 6703 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8158 6703 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8159 :
8160 6703 : int nXCheck = 0, nYCheck = 0;
8161 6703 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8162 :
8163 13283 : if (poMaskBand &&
8164 6580 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8165 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8166 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
8167 : nBlockXSize, nullptr) != CE_None)
8168 : {
8169 0 : CPLFree(pabyMaskData);
8170 0 : return false;
8171 : }
8172 :
8173 6703 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8174 6703 : if (poBlock == nullptr)
8175 : {
8176 0 : CPLFree(pabyMaskData);
8177 0 : return false;
8178 : }
8179 :
8180 6703 : void *const pData = poBlock->GetDataRef();
8181 :
8182 6703 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8183 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8184 : dfMax);
8185 :
8186 6703 : poBlock->DropLock();
8187 : }
8188 :
8189 189 : CPLFree(pabyMaskData);
8190 189 : return true;
8191 : }
8192 :
8193 : /**
8194 : * \brief Compute the min/max values for a band.
8195 : *
8196 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8197 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8198 : * get an approximate min/max. If the band has a nodata value it will
8199 : * be excluded from the minimum and maximum.
8200 : *
8201 : * If bApprox is FALSE, then all pixels will be read and used to compute
8202 : * an exact range.
8203 : *
8204 : * This method is the same as the C function GDALComputeRasterMinMax().
8205 : *
8206 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8207 : * FALSE.
8208 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8209 : * maximum (adfMinMax[1]) are returned.
8210 : *
8211 : * @return CE_None on success or CE_Failure on failure.
8212 : */
8213 :
8214 1814 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8215 : {
8216 : /* -------------------------------------------------------------------- */
8217 : /* Does the driver already know the min/max? */
8218 : /* -------------------------------------------------------------------- */
8219 1814 : if (bApproxOK)
8220 : {
8221 23 : int bSuccessMin = FALSE;
8222 23 : int bSuccessMax = FALSE;
8223 :
8224 23 : double dfMin = GetMinimum(&bSuccessMin);
8225 23 : double dfMax = GetMaximum(&bSuccessMax);
8226 :
8227 23 : if (bSuccessMin && bSuccessMax)
8228 : {
8229 1 : adfMinMax[0] = dfMin;
8230 1 : adfMinMax[1] = dfMax;
8231 1 : return CE_None;
8232 : }
8233 : }
8234 :
8235 : /* -------------------------------------------------------------------- */
8236 : /* If we have overview bands, use them for min/max. */
8237 : /* -------------------------------------------------------------------- */
8238 : // cppcheck-suppress knownConditionTrueFalse
8239 1813 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8240 : {
8241 : GDALRasterBand *poBand =
8242 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8243 :
8244 0 : if (poBand != this)
8245 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8246 : }
8247 :
8248 : /* -------------------------------------------------------------------- */
8249 : /* Read actual data and compute minimum and maximum. */
8250 : /* -------------------------------------------------------------------- */
8251 1813 : GDALNoDataValues sNoDataValues(this, eDataType);
8252 1813 : GDALRasterBand *poMaskBand = nullptr;
8253 1813 : if (!sNoDataValues.bGotNoDataValue)
8254 : {
8255 1551 : const int l_nMaskFlags = GetMaskFlags();
8256 1676 : if (l_nMaskFlags != GMF_ALL_VALID &&
8257 125 : GetColorInterpretation() != GCI_AlphaBand)
8258 : {
8259 125 : poMaskBand = GetMaskBand();
8260 : }
8261 : }
8262 :
8263 1813 : if (!bApproxOK &&
8264 1791 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8265 1653 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8266 1450 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8267 1404 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8268 1791 : eDataType == GDT_Float64) &&
8269 : !poMaskBand)
8270 : {
8271 1464 : CPLErr eErr = ComputeRasterMinMaxLocation(
8272 732 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8273 732 : if (eErr == CE_Warning)
8274 : {
8275 9 : ReportError(CE_Failure, CPLE_AppDefined,
8276 : "Failed to compute min/max, no valid pixels found in "
8277 : "sampling.");
8278 9 : eErr = CE_Failure;
8279 : }
8280 732 : return eErr;
8281 : }
8282 :
8283 1081 : bool bSignedByte = false;
8284 1081 : if (eDataType == GDT_Byte)
8285 : {
8286 781 : EnablePixelTypeSignedByteWarning(false);
8287 : const char *pszPixelType =
8288 781 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8289 781 : EnablePixelTypeSignedByteWarning(true);
8290 781 : bSignedByte =
8291 781 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8292 : }
8293 :
8294 : GDALRasterIOExtraArg sExtraArg;
8295 1081 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8296 :
8297 2162 : GUInt32 nMin = (eDataType == GDT_Byte)
8298 1081 : ? 255
8299 : : 65535; // used for GByte & GUInt16 cases
8300 1081 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8301 1081 : GInt16 nMinInt16 =
8302 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8303 1081 : GInt16 nMaxInt16 =
8304 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8305 1081 : double dfMin =
8306 : std::numeric_limits<double>::infinity(); // used for generic code path
8307 1081 : double dfMax =
8308 : -std::numeric_limits<double>::infinity(); // used for generic code path
8309 1081 : const bool bUseOptimizedPath =
8310 1287 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
8311 206 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8312 :
8313 : const auto ComputeMinMaxForBlock =
8314 19520 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8315 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8316 113020 : int nYCheck)
8317 : {
8318 19520 : if (eDataType == GDT_Byte && !bSignedByte)
8319 : {
8320 : const bool bHasNoData =
8321 11562 : sNoDataValues.bGotNoDataValue &&
8322 29667 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8323 11562 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8324 11562 : sNoDataValues.dfNoDataValue;
8325 18105 : const GUInt32 nNoDataValue =
8326 18105 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8327 : : 0;
8328 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8329 : ComputeStatisticsInternal<GByte,
8330 : /* COMPUTE_OTHER_STATS = */ false>::
8331 18105 : f(nXCheck, nBufferWidth, nYCheck,
8332 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8333 18105 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8334 : }
8335 1415 : else if (eDataType == GDT_UInt16)
8336 : {
8337 : const bool bHasNoData =
8338 84 : sNoDataValues.bGotNoDataValue &&
8339 1497 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8340 84 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8341 84 : sNoDataValues.dfNoDataValue;
8342 1413 : const GUInt32 nNoDataValue =
8343 1413 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8344 : : 0;
8345 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8346 : ComputeStatisticsInternal<GUInt16,
8347 : /* COMPUTE_OTHER_STATS = */ false>::
8348 1413 : f(nXCheck, nBufferWidth, nYCheck,
8349 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8350 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8351 : }
8352 2 : else if (eDataType == GDT_Int16)
8353 : {
8354 : const bool bHasNoData =
8355 0 : sNoDataValues.bGotNoDataValue &&
8356 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8357 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8358 0 : sNoDataValues.dfNoDataValue;
8359 2 : if (bHasNoData)
8360 : {
8361 0 : const int16_t nNoDataValue =
8362 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8363 0 : for (int iY = 0; iY < nYCheck; iY++)
8364 : {
8365 0 : ComputeMinMax<int16_t, true>(
8366 0 : static_cast<const int16_t *>(pData) +
8367 0 : static_cast<size_t>(iY) * nBufferWidth,
8368 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8369 : }
8370 : }
8371 : else
8372 : {
8373 4 : for (int iY = 0; iY < nYCheck; iY++)
8374 : {
8375 2 : ComputeMinMax<int16_t, false>(
8376 2 : static_cast<const int16_t *>(pData) +
8377 2 : static_cast<size_t>(iY) * nBufferWidth,
8378 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8379 : }
8380 : }
8381 : }
8382 19520 : };
8383 :
8384 1081 : if (bApproxOK && HasArbitraryOverviews())
8385 : {
8386 : /* --------------------------------------------------------------------
8387 : */
8388 : /* Figure out how much the image should be reduced to get an */
8389 : /* approximate value. */
8390 : /* --------------------------------------------------------------------
8391 : */
8392 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8393 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8394 :
8395 0 : int nXReduced = nRasterXSize;
8396 0 : int nYReduced = nRasterYSize;
8397 0 : if (dfReduction > 1.0)
8398 : {
8399 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8400 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8401 :
8402 : // Catch the case of huge resizing ratios here
8403 0 : if (nXReduced == 0)
8404 0 : nXReduced = 1;
8405 0 : if (nYReduced == 0)
8406 0 : nYReduced = 1;
8407 : }
8408 :
8409 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8410 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8411 :
8412 : const CPLErr eErr =
8413 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8414 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8415 0 : if (eErr != CE_None)
8416 : {
8417 0 : CPLFree(pData);
8418 0 : return eErr;
8419 : }
8420 :
8421 0 : GByte *pabyMaskData = nullptr;
8422 0 : if (poMaskBand)
8423 : {
8424 : pabyMaskData =
8425 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8426 0 : if (!pabyMaskData)
8427 : {
8428 0 : CPLFree(pData);
8429 0 : return CE_Failure;
8430 : }
8431 :
8432 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8433 : pabyMaskData, nXReduced, nYReduced,
8434 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
8435 : {
8436 0 : CPLFree(pData);
8437 0 : CPLFree(pabyMaskData);
8438 0 : return CE_Failure;
8439 : }
8440 : }
8441 :
8442 0 : if (bUseOptimizedPath)
8443 : {
8444 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8445 : }
8446 : else
8447 : {
8448 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8449 : nYReduced, nXReduced, sNoDataValues,
8450 : pabyMaskData, dfMin, dfMax);
8451 : }
8452 :
8453 0 : CPLFree(pData);
8454 0 : CPLFree(pabyMaskData);
8455 : }
8456 :
8457 : else // No arbitrary overviews
8458 : {
8459 1081 : if (!InitBlockInfo())
8460 0 : return CE_Failure;
8461 :
8462 : /* --------------------------------------------------------------------
8463 : */
8464 : /* Figure out the ratio of blocks we will read to get an */
8465 : /* approximate value. */
8466 : /* --------------------------------------------------------------------
8467 : */
8468 1081 : int nSampleRate = 1;
8469 :
8470 1081 : if (bApproxOK)
8471 : {
8472 22 : nSampleRate = static_cast<int>(std::max(
8473 44 : 1.0,
8474 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8475 : // We want to avoid probing only the first column of blocks for
8476 : // a square shaped raster, because it is not unlikely that it may
8477 : // be padding only (#6378).
8478 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8479 0 : nSampleRate += 1;
8480 : }
8481 :
8482 1081 : if (bUseOptimizedPath)
8483 : {
8484 892 : for (GIntBig iSampleBlock = 0;
8485 20338 : iSampleBlock <
8486 20338 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8487 19446 : iSampleBlock += nSampleRate)
8488 : {
8489 19522 : const int iYBlock =
8490 19522 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8491 19522 : const int iXBlock =
8492 19522 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8493 :
8494 19522 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8495 19522 : if (poBlock == nullptr)
8496 2 : return CE_Failure;
8497 :
8498 19520 : void *const pData = poBlock->GetDataRef();
8499 :
8500 19520 : int nXCheck = 0, nYCheck = 0;
8501 19520 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8502 :
8503 19520 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8504 :
8505 19520 : poBlock->DropLock();
8506 :
8507 19520 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
8508 4110 : nMax == 255)
8509 74 : break;
8510 : }
8511 : }
8512 : else
8513 : {
8514 189 : const GIntBig nTotalBlocks =
8515 189 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8516 189 : if (!ComputeMinMaxGenericIterBlocks(
8517 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8518 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8519 : {
8520 0 : return CE_Failure;
8521 : }
8522 : }
8523 : }
8524 :
8525 1079 : if (bUseOptimizedPath)
8526 : {
8527 890 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
8528 : {
8529 889 : dfMin = nMin;
8530 889 : dfMax = nMax;
8531 : }
8532 1 : else if (eDataType == GDT_Int16)
8533 : {
8534 1 : dfMin = nMinInt16;
8535 1 : dfMax = nMaxInt16;
8536 : }
8537 : }
8538 :
8539 1079 : if (dfMin > dfMax)
8540 : {
8541 23 : adfMinMax[0] = 0;
8542 23 : adfMinMax[1] = 0;
8543 23 : ReportError(
8544 : CE_Failure, CPLE_AppDefined,
8545 : "Failed to compute min/max, no valid pixels found in sampling.");
8546 23 : return CE_Failure;
8547 : }
8548 :
8549 1056 : adfMinMax[0] = dfMin;
8550 1056 : adfMinMax[1] = dfMax;
8551 :
8552 1056 : return CE_None;
8553 : }
8554 :
8555 : /************************************************************************/
8556 : /* GDALComputeRasterMinMax() */
8557 : /************************************************************************/
8558 :
8559 : /**
8560 : * \brief Compute the min/max values for a band.
8561 : *
8562 : * @see GDALRasterBand::ComputeRasterMinMax()
8563 : *
8564 : * @note Prior to GDAL 3.6, this function returned void
8565 : */
8566 :
8567 1663 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8568 : double adfMinMax[2])
8569 :
8570 : {
8571 1663 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8572 :
8573 1663 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8574 1663 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8575 : }
8576 :
8577 : /************************************************************************/
8578 : /* ComputeRasterMinMaxLocation() */
8579 : /************************************************************************/
8580 :
8581 : /**
8582 : * \brief Compute the min/max values for a band, and their location.
8583 : *
8584 : * Pixels whose value matches the nodata value or are masked by the mask
8585 : * band are ignored.
8586 : *
8587 : * If the minimum or maximum value is hit in several locations, it is not
8588 : * specified which one will be returned.
8589 : *
8590 : * @param[out] pdfMin Pointer to the minimum value.
8591 : * @param[out] pdfMax Pointer to the maximum value.
8592 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8593 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8594 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8595 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8596 : *
8597 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8598 : * CE_Failure in case of error.
8599 : *
8600 : * @since GDAL 3.11
8601 : */
8602 :
8603 748 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8604 : double *pdfMax, int *pnMinX,
8605 : int *pnMinY, int *pnMaxX,
8606 : int *pnMaxY)
8607 : {
8608 748 : int nMinX = -1;
8609 748 : int nMinY = -1;
8610 748 : int nMaxX = -1;
8611 748 : int nMaxY = -1;
8612 748 : double dfMin = std::numeric_limits<double>::infinity();
8613 748 : double dfMax = -std::numeric_limits<double>::infinity();
8614 748 : if (pdfMin)
8615 745 : *pdfMin = dfMin;
8616 748 : if (pdfMax)
8617 745 : *pdfMax = dfMax;
8618 748 : if (pnMinX)
8619 14 : *pnMinX = nMinX;
8620 748 : if (pnMinY)
8621 14 : *pnMinY = nMinY;
8622 748 : if (pnMaxX)
8623 14 : *pnMaxX = nMaxX;
8624 748 : if (pnMaxY)
8625 14 : *pnMaxY = nMaxY;
8626 :
8627 748 : if (GDALDataTypeIsComplex(eDataType))
8628 : {
8629 0 : CPLError(CE_Failure, CPLE_NotSupported,
8630 : "Complex data type not supported");
8631 0 : return CE_Failure;
8632 : }
8633 :
8634 748 : if (!InitBlockInfo())
8635 0 : return CE_Failure;
8636 :
8637 748 : GDALNoDataValues sNoDataValues(this, eDataType);
8638 748 : GDALRasterBand *poMaskBand = nullptr;
8639 748 : if (!sNoDataValues.bGotNoDataValue)
8640 : {
8641 575 : const int l_nMaskFlags = GetMaskFlags();
8642 576 : if (l_nMaskFlags != GMF_ALL_VALID &&
8643 1 : GetColorInterpretation() != GCI_AlphaBand)
8644 : {
8645 1 : poMaskBand = GetMaskBand();
8646 : }
8647 : }
8648 :
8649 748 : bool bSignedByte = false;
8650 748 : if (eDataType == GDT_Byte)
8651 : {
8652 7 : EnablePixelTypeSignedByteWarning(false);
8653 : const char *pszPixelType =
8654 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8655 7 : EnablePixelTypeSignedByteWarning(true);
8656 7 : bSignedByte =
8657 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8658 : }
8659 :
8660 748 : GByte *pabyMaskData = nullptr;
8661 748 : if (poMaskBand)
8662 : {
8663 : pabyMaskData =
8664 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8665 1 : if (!pabyMaskData)
8666 : {
8667 0 : return CE_Failure;
8668 : }
8669 : }
8670 :
8671 748 : const GIntBig nTotalBlocks =
8672 748 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8673 748 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8674 748 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8675 7842 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8676 : {
8677 7097 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8678 7097 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8679 :
8680 7097 : int nXCheck = 0, nYCheck = 0;
8681 7097 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8682 :
8683 7099 : if (poMaskBand &&
8684 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8685 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8686 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
8687 2 : nBlockXSize, nullptr) != CE_None)
8688 : {
8689 0 : CPLFree(pabyMaskData);
8690 0 : return CE_Failure;
8691 : }
8692 :
8693 7097 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8694 7097 : if (poBlock == nullptr)
8695 : {
8696 0 : CPLFree(pabyMaskData);
8697 0 : return CE_Failure;
8698 : }
8699 :
8700 7097 : void *const pData = poBlock->GetDataRef();
8701 :
8702 7097 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8703 : {
8704 5059 : for (int iY = 0; iY < nYCheck; ++iY)
8705 : {
8706 238290 : for (int iX = 0; iX < nXCheck; ++iX)
8707 : {
8708 233478 : const GPtrDiff_t iOffset =
8709 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8710 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8711 2 : continue;
8712 233476 : bool bValid = true;
8713 : double dfValue =
8714 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8715 : sNoDataValues, bValid);
8716 233476 : if (!bValid)
8717 0 : continue;
8718 233476 : if (dfValue < dfMin)
8719 : {
8720 606 : dfMin = dfValue;
8721 606 : nMinX = iXBlock * nBlockXSize + iX;
8722 606 : nMinY = iYBlock * nBlockYSize + iY;
8723 : }
8724 233476 : if (dfValue > dfMax)
8725 : {
8726 1515 : dfMax = dfValue;
8727 1515 : nMaxX = iXBlock * nBlockXSize + iX;
8728 1515 : nMaxY = iYBlock * nBlockYSize + iY;
8729 : }
8730 : }
8731 247 : }
8732 : }
8733 : else
8734 : {
8735 6850 : size_t pos_min = 0;
8736 6850 : size_t pos_max = 0;
8737 6850 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8738 6850 : if (bNeedsMin && bNeedsMax)
8739 : {
8740 13692 : std::tie(pos_min, pos_max) = gdal::minmax_element(
8741 6846 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8742 6846 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8743 13692 : sNoDataValues.dfNoDataValue);
8744 : }
8745 4 : else if (bNeedsMin)
8746 : {
8747 1 : pos_min = gdal::min_element(
8748 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8749 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8750 : sNoDataValues.dfNoDataValue);
8751 : }
8752 3 : else if (bNeedsMax)
8753 : {
8754 2 : pos_max = gdal::max_element(
8755 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8756 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8757 : sNoDataValues.dfNoDataValue);
8758 : }
8759 :
8760 6850 : if (bNeedsMin)
8761 : {
8762 6847 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8763 6847 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8764 6847 : bool bValid = true;
8765 : const double dfMinValueBlock =
8766 6847 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
8767 : sNoDataValues, bValid);
8768 6847 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
8769 : {
8770 1039 : dfMin = dfMinValueBlock;
8771 1039 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
8772 1039 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
8773 : }
8774 : }
8775 :
8776 6850 : if (bNeedsMax)
8777 : {
8778 6848 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
8779 6848 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
8780 6848 : bool bValid = true;
8781 : const double dfMaxValueBlock =
8782 6848 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
8783 : sNoDataValues, bValid);
8784 6848 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
8785 : {
8786 954 : dfMax = dfMaxValueBlock;
8787 954 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
8788 954 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
8789 : }
8790 : }
8791 : }
8792 :
8793 7097 : poBlock->DropLock();
8794 :
8795 7097 : if (eDataType == GDT_Byte)
8796 : {
8797 10 : if (bNeedsMin && dfMin == 0)
8798 : {
8799 1 : bNeedsMin = false;
8800 : }
8801 10 : if (bNeedsMax && dfMax == 255)
8802 : {
8803 4 : bNeedsMax = false;
8804 : }
8805 10 : if (!bNeedsMin && !bNeedsMax)
8806 : {
8807 3 : break;
8808 : }
8809 : }
8810 : }
8811 :
8812 748 : CPLFree(pabyMaskData);
8813 :
8814 748 : if (pdfMin)
8815 745 : *pdfMin = dfMin;
8816 748 : if (pdfMax)
8817 745 : *pdfMax = dfMax;
8818 748 : if (pnMinX)
8819 14 : *pnMinX = nMinX;
8820 748 : if (pnMinY)
8821 14 : *pnMinY = nMinY;
8822 748 : if (pnMaxX)
8823 14 : *pnMaxX = nMaxX;
8824 748 : if (pnMaxY)
8825 14 : *pnMaxY = nMaxY;
8826 748 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8827 748 : : CE_None;
8828 : }
8829 :
8830 : /************************************************************************/
8831 : /* GDALComputeRasterMinMaxLocation() */
8832 : /************************************************************************/
8833 :
8834 : /**
8835 : * \brief Compute the min/max values for a band, and their location.
8836 : *
8837 : * @see GDALRasterBand::ComputeRasterMinMax()
8838 : * @since GDAL 3.11
8839 : */
8840 :
8841 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8842 : double *pdfMax, int *pnMinX, int *pnMinY,
8843 : int *pnMaxX, int *pnMaxY)
8844 :
8845 : {
8846 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8847 :
8848 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8849 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8850 14 : pnMaxX, pnMaxY);
8851 : }
8852 :
8853 : /************************************************************************/
8854 : /* SetDefaultHistogram() */
8855 : /************************************************************************/
8856 :
8857 : /* FIXME : add proper documentation */
8858 : /**
8859 : * \brief Set default histogram.
8860 : *
8861 : * This method is the same as the C function GDALSetDefaultHistogram() and
8862 : * GDALSetDefaultHistogramEx()
8863 : */
8864 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8865 : double /* dfMax */,
8866 : int /* nBuckets */,
8867 : GUIntBig * /* panHistogram */)
8868 :
8869 : {
8870 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8871 0 : ReportError(CE_Failure, CPLE_NotSupported,
8872 : "SetDefaultHistogram() not implemented for this format.");
8873 :
8874 0 : return CE_Failure;
8875 : }
8876 :
8877 : /************************************************************************/
8878 : /* GDALSetDefaultHistogram() */
8879 : /************************************************************************/
8880 :
8881 : /**
8882 : * \brief Set default histogram.
8883 : *
8884 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8885 : * 2 billion.
8886 : *
8887 : * @see GDALRasterBand::SetDefaultHistogram()
8888 : * @see GDALSetRasterHistogramEx()
8889 : */
8890 :
8891 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8892 : double dfMax, int nBuckets,
8893 : int *panHistogram)
8894 :
8895 : {
8896 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8897 :
8898 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8899 :
8900 : GUIntBig *panHistogramTemp =
8901 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8902 0 : if (panHistogramTemp == nullptr)
8903 : {
8904 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8905 : "Out of memory in GDALSetDefaultHistogram().");
8906 0 : return CE_Failure;
8907 : }
8908 :
8909 0 : for (int i = 0; i < nBuckets; ++i)
8910 : {
8911 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8912 : }
8913 :
8914 : const CPLErr eErr =
8915 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8916 :
8917 0 : CPLFree(panHistogramTemp);
8918 :
8919 0 : return eErr;
8920 : }
8921 :
8922 : /************************************************************************/
8923 : /* GDALSetDefaultHistogramEx() */
8924 : /************************************************************************/
8925 :
8926 : /**
8927 : * \brief Set default histogram.
8928 : *
8929 : * @see GDALRasterBand::SetDefaultHistogram()
8930 : *
8931 : */
8932 :
8933 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8934 : double dfMin, double dfMax,
8935 : int nBuckets,
8936 : GUIntBig *panHistogram)
8937 :
8938 : {
8939 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8940 :
8941 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8942 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8943 : }
8944 :
8945 : /************************************************************************/
8946 : /* GetDefaultRAT() */
8947 : /************************************************************************/
8948 :
8949 : /**
8950 : * \brief Fetch default Raster Attribute Table.
8951 : *
8952 : * A RAT will be returned if there is a default one associated with the
8953 : * band, otherwise NULL is returned. The returned RAT is owned by the
8954 : * band and should not be deleted by the application.
8955 : *
8956 : * This method is the same as the C function GDALGetDefaultRAT().
8957 : *
8958 : * @return NULL, or a pointer to an internal RAT owned by the band.
8959 : */
8960 :
8961 180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8962 :
8963 : {
8964 180 : return nullptr;
8965 : }
8966 :
8967 : /************************************************************************/
8968 : /* GDALGetDefaultRAT() */
8969 : /************************************************************************/
8970 :
8971 : /**
8972 : * \brief Fetch default Raster Attribute Table.
8973 : *
8974 : * @see GDALRasterBand::GetDefaultRAT()
8975 : */
8976 :
8977 1157 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8978 :
8979 : {
8980 1157 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8981 :
8982 1157 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8983 1157 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8984 : }
8985 :
8986 : /************************************************************************/
8987 : /* SetDefaultRAT() */
8988 : /************************************************************************/
8989 :
8990 : /**
8991 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8992 : * \brief Set default Raster Attribute Table.
8993 : *
8994 : * Associates a default RAT with the band. If not implemented for the
8995 : * format a CPLE_NotSupported error will be issued. If successful a copy
8996 : * of the RAT is made, the original remains owned by the caller.
8997 : *
8998 : * This method is the same as the C function GDALSetDefaultRAT().
8999 : *
9000 : * @param poRAT the RAT to assign to the band.
9001 : *
9002 : * @return CE_None on success or CE_Failure if unsupported or otherwise
9003 : * failing.
9004 : */
9005 :
9006 : /**/
9007 : /**/
9008 :
9009 : CPLErr
9010 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9011 : {
9012 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9013 : {
9014 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
9015 0 : ReportError(CE_Failure, CPLE_NotSupported,
9016 : "SetDefaultRAT() not implemented for this format.");
9017 0 : CPLPopErrorHandler();
9018 : }
9019 0 : return CE_Failure;
9020 : }
9021 :
9022 : /************************************************************************/
9023 : /* GDALSetDefaultRAT() */
9024 : /************************************************************************/
9025 :
9026 : /**
9027 : * \brief Set default Raster Attribute Table.
9028 : *
9029 : * @see GDALRasterBand::GDALSetDefaultRAT()
9030 : */
9031 :
9032 25 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9033 : GDALRasterAttributeTableH hRAT)
9034 :
9035 : {
9036 25 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9037 :
9038 25 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9039 :
9040 25 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9041 : }
9042 :
9043 : /************************************************************************/
9044 : /* GetMaskBand() */
9045 : /************************************************************************/
9046 :
9047 : /**
9048 : * \brief Return the mask band associated with the band.
9049 : *
9050 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9051 : * that returns one of four default implementations :
9052 : * <ul>
9053 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9054 : * </li>
9055 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9056 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9057 : * GMF_NODATA | GMF_PER_DATASET.
9058 : * </li>
9059 : * <li>If the band has a nodata value set, an instance of the new
9060 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9061 : * GMF_NODATA.
9062 : * </li>
9063 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9064 : * to apply to this band (specific rules yet to be determined) and that is of
9065 : * type GDT_Byte then that alpha band will be returned, and the flags
9066 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9067 : * </li>
9068 : * <li>If neither of the above apply, an instance of the new
9069 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9070 : * pixels. The null flags will return GMF_ALL_VALID.
9071 : * </li>
9072 : * </ul>
9073 : *
9074 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9075 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9076 : *
9077 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9078 : * dataset, with the same name as the main dataset and suffixed with .msk,
9079 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9080 : * main dataset.
9081 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9082 : * level, where xx matches the band number of a band of the main dataset. The
9083 : * value of those items is a combination of the flags GMF_ALL_VALID,
9084 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9085 : * a band, then the other rules explained above will be used to generate a
9086 : * on-the-fly mask band.
9087 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9088 : *
9089 : * This method is the same as the C function GDALGetMaskBand().
9090 : *
9091 : * @return a valid mask band.
9092 : *
9093 : *
9094 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9095 : *
9096 : */
9097 796995 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9098 :
9099 : {
9100 396927 : const auto HasNoData = [this]()
9101 : {
9102 131987 : int bHaveNoDataRaw = FALSE;
9103 131987 : bool bHaveNoData = false;
9104 131987 : if (eDataType == GDT_Int64)
9105 : {
9106 204 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
9107 204 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9108 : }
9109 131783 : else if (eDataType == GDT_UInt64)
9110 : {
9111 152 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9112 152 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9113 : }
9114 : else
9115 : {
9116 131631 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
9117 131636 : if (bHaveNoDataRaw &&
9118 131636 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9119 : {
9120 1125 : bHaveNoData = true;
9121 : }
9122 : }
9123 131998 : return bHaveNoData;
9124 796995 : };
9125 :
9126 796995 : if (poMask != nullptr)
9127 : {
9128 707269 : if (poMask.IsOwned())
9129 : {
9130 330362 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9131 : {
9132 33597 : if (HasNoData())
9133 : {
9134 9 : InvalidateMaskBand();
9135 : }
9136 : }
9137 297673 : else if (auto poNoDataMaskBand =
9138 297542 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9139 : {
9140 396 : int bHaveNoDataRaw = FALSE;
9141 396 : bool bIsSame = false;
9142 396 : if (eDataType == GDT_Int64)
9143 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9144 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9145 10 : bHaveNoDataRaw;
9146 379 : else if (eDataType == GDT_UInt64)
9147 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9148 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9149 10 : bHaveNoDataRaw;
9150 : else
9151 : {
9152 : const double dfNoDataValue =
9153 362 : GetNoDataValue(&bHaveNoDataRaw);
9154 362 : if (bHaveNoDataRaw)
9155 : {
9156 359 : bIsSame =
9157 359 : std::isnan(dfNoDataValue)
9158 359 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9159 324 : : poNoDataMaskBand->m_dfNoDataValue ==
9160 : dfNoDataValue;
9161 : }
9162 : }
9163 396 : if (!bIsSame)
9164 23 : InvalidateMaskBand();
9165 : }
9166 : }
9167 :
9168 709698 : if (poMask)
9169 706124 : return poMask.get();
9170 : }
9171 :
9172 : /* -------------------------------------------------------------------- */
9173 : /* Check for a mask in a .msk file. */
9174 : /* -------------------------------------------------------------------- */
9175 98501 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9176 : {
9177 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9178 47 : if (poMask != nullptr)
9179 : {
9180 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9181 45 : return poMask.get();
9182 : }
9183 : }
9184 :
9185 : /* -------------------------------------------------------------------- */
9186 : /* Check for NODATA_VALUES metadata. */
9187 : /* -------------------------------------------------------------------- */
9188 98456 : if (poDS != nullptr)
9189 : {
9190 : const char *pszGDALNoDataValues =
9191 98440 : poDS->GetMetadataItem("NODATA_VALUES");
9192 98440 : if (pszGDALNoDataValues != nullptr)
9193 : {
9194 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9195 : pszGDALNoDataValues, " ", FALSE, FALSE);
9196 :
9197 : // Make sure we have as many values as bands.
9198 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9199 68 : poDS->GetRasterCount() != 0)
9200 : {
9201 : // Make sure that all bands have the same data type
9202 : // This is clearly not a fundamental condition, just a
9203 : // condition to make implementation easier.
9204 68 : GDALDataType eDT = GDT_Unknown;
9205 68 : int i = 0; // Used after for.
9206 270 : for (; i < poDS->GetRasterCount(); ++i)
9207 : {
9208 202 : if (i == 0)
9209 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9210 134 : else if (eDT !=
9211 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9212 : {
9213 0 : break;
9214 : }
9215 : }
9216 68 : if (i == poDS->GetRasterCount())
9217 : {
9218 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9219 : try
9220 : {
9221 68 : poMask.reset(
9222 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9223 : }
9224 0 : catch (const std::bad_alloc &)
9225 : {
9226 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9227 0 : poMask.reset();
9228 : }
9229 68 : CSLDestroy(papszGDALNoDataValues);
9230 68 : return poMask.get();
9231 : }
9232 : else
9233 : {
9234 0 : ReportError(CE_Warning, CPLE_AppDefined,
9235 : "All bands should have the same type in "
9236 : "order the NODATA_VALUES metadata item "
9237 : "to be used as a mask.");
9238 : }
9239 : }
9240 : else
9241 : {
9242 0 : ReportError(
9243 : CE_Warning, CPLE_AppDefined,
9244 : "NODATA_VALUES metadata item doesn't have the same number "
9245 : "of values as the number of bands. "
9246 : "Ignoring it for mask.");
9247 : }
9248 :
9249 0 : CSLDestroy(papszGDALNoDataValues);
9250 : }
9251 : }
9252 :
9253 : /* -------------------------------------------------------------------- */
9254 : /* Check for nodata case. */
9255 : /* -------------------------------------------------------------------- */
9256 98388 : if (HasNoData())
9257 : {
9258 1151 : nMaskFlags = GMF_NODATA;
9259 : try
9260 : {
9261 1151 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9262 : }
9263 0 : catch (const std::bad_alloc &)
9264 : {
9265 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9266 0 : poMask.reset();
9267 : }
9268 1151 : return poMask.get();
9269 : }
9270 :
9271 : /* -------------------------------------------------------------------- */
9272 : /* Check for alpha case. */
9273 : /* -------------------------------------------------------------------- */
9274 97222 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9275 195058 : this == poDS->GetRasterBand(1) &&
9276 599 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9277 : {
9278 231 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
9279 : {
9280 187 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9281 187 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9282 187 : return poMask.get();
9283 : }
9284 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9285 : {
9286 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9287 : try
9288 : {
9289 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9290 46 : poDS->GetRasterBand(2)));
9291 : }
9292 0 : catch (const std::bad_alloc &)
9293 : {
9294 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9295 0 : poMask.reset();
9296 : }
9297 23 : return poMask.get();
9298 : }
9299 : }
9300 :
9301 97012 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9302 3135 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9303 194776 : this == poDS->GetRasterBand(3)) &&
9304 2449 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9305 : {
9306 1573 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
9307 : {
9308 1517 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9309 1517 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9310 1517 : return poMask.get();
9311 : }
9312 56 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9313 : {
9314 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9315 : try
9316 : {
9317 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9318 84 : poDS->GetRasterBand(4)));
9319 : }
9320 0 : catch (const std::bad_alloc &)
9321 : {
9322 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9323 0 : poMask.reset();
9324 : }
9325 42 : return poMask.get();
9326 : }
9327 : }
9328 :
9329 : /* -------------------------------------------------------------------- */
9330 : /* Fallback to all valid case. */
9331 : /* -------------------------------------------------------------------- */
9332 95468 : nMaskFlags = GMF_ALL_VALID;
9333 : try
9334 : {
9335 95468 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9336 : }
9337 0 : catch (const std::bad_alloc &)
9338 : {
9339 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9340 0 : poMask.reset();
9341 : }
9342 :
9343 95468 : return poMask.get();
9344 : }
9345 :
9346 : /************************************************************************/
9347 : /* GDALGetMaskBand() */
9348 : /************************************************************************/
9349 :
9350 : /**
9351 : * \brief Return the mask band associated with the band.
9352 : *
9353 : * @see GDALRasterBand::GetMaskBand()
9354 : */
9355 :
9356 11042 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9357 :
9358 : {
9359 11042 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9360 :
9361 11042 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9362 11042 : return poBand->GetMaskBand();
9363 : }
9364 :
9365 : /************************************************************************/
9366 : /* GetMaskFlags() */
9367 : /************************************************************************/
9368 :
9369 : /**
9370 : * \brief Return the status flags of the mask band associated with the band.
9371 : *
9372 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9373 : * the following available definitions that may be extended in the future:
9374 : * <ul>
9375 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9376 : * 255. When used this will normally be the only flag set.
9377 : * </li>
9378 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9379 : * dataset.
9380 : * </li>
9381 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9382 : * and may have values other than 0 and 255.
9383 : * </li>
9384 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9385 : * nodata values. (mutually exclusive of GMF_ALPHA)
9386 : * </li>
9387 : * </ul>
9388 : *
9389 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9390 : * that returns one of four default implementations:
9391 : * <ul>
9392 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9393 : * </li>
9394 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9395 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9396 : * GMF_NODATA | GMF_PER_DATASET.
9397 : * </li>
9398 : * <li>If the band has a nodata value set, an instance of the new
9399 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9400 : * GMF_NODATA.
9401 : * </li>
9402 : * <li>If there is no nodata value, but the dataset has an alpha band that
9403 : * seems to apply to this band (specific rules yet to be determined) and that is
9404 : * of type GDT_Byte then that alpha band will be returned, and the flags
9405 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9406 : * </li>
9407 : * <li>If neither of the above apply, an instance of the new
9408 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9409 : * pixels. The null flags will return GMF_ALL_VALID.
9410 : * </li>
9411 : * </ul>
9412 : *
9413 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9414 : * dataset, with the same name as the main dataset and suffixed with .msk,
9415 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9416 : * main dataset.
9417 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9418 : * level, where xx matches the band number of a band of the main dataset. The
9419 : * value of those items is a combination of the flags GMF_ALL_VALID,
9420 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9421 : * a band, then the other rules explained above will be used to generate a
9422 : * on-the-fly mask band.
9423 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9424 : *
9425 : * This method is the same as the C function GDALGetMaskFlags().
9426 : *
9427 : *
9428 : * @return a valid mask band.
9429 : *
9430 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9431 : *
9432 : */
9433 157678 : int GDALRasterBand::GetMaskFlags()
9434 :
9435 : {
9436 : // If we don't have a band yet, force this now so that the masks value
9437 : // will be initialized.
9438 :
9439 157678 : if (poMask == nullptr)
9440 96780 : GetMaskBand();
9441 :
9442 157686 : return nMaskFlags;
9443 : }
9444 :
9445 : /************************************************************************/
9446 : /* GDALGetMaskFlags() */
9447 : /************************************************************************/
9448 :
9449 : /**
9450 : * \brief Return the status flags of the mask band associated with the band.
9451 : *
9452 : * @see GDALRasterBand::GetMaskFlags()
9453 : */
9454 :
9455 8835 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9456 :
9457 : {
9458 8835 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9459 :
9460 8835 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9461 8835 : return poBand->GetMaskFlags();
9462 : }
9463 :
9464 : /************************************************************************/
9465 : /* InvalidateMaskBand() */
9466 : /************************************************************************/
9467 :
9468 : //! @cond Doxygen_Suppress
9469 1850090 : void GDALRasterBand::InvalidateMaskBand()
9470 : {
9471 1850090 : poMask.reset();
9472 1850090 : nMaskFlags = 0;
9473 1850090 : }
9474 :
9475 : //! @endcond
9476 :
9477 : /************************************************************************/
9478 : /* CreateMaskBand() */
9479 : /************************************************************************/
9480 :
9481 : /**
9482 : * \brief Adds a mask band to the current band
9483 : *
9484 : * The default implementation of the CreateMaskBand() method is implemented
9485 : * based on similar rules to the .ovr handling implemented using the
9486 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9487 : * be created with the same basename as the original file, and it will have
9488 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9489 : * The mask images will be deflate compressed tiled images with the same
9490 : * block size as the original image if possible.
9491 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9492 : * level, where xx matches the band number of a band of the main dataset. The
9493 : * value of those items will be the one of the nFlagsIn parameter.
9494 : *
9495 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9496 : * it might be invalidated by CreateMaskBand(). So you have to call
9497 : * GetMaskBand() again.
9498 : *
9499 : * This method is the same as the C function GDALCreateMaskBand().
9500 : *
9501 : *
9502 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9503 : *
9504 : * @return CE_None on success or CE_Failure on an error.
9505 : *
9506 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9507 : * @see GDALDataset::CreateMaskBand()
9508 : *
9509 : */
9510 :
9511 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9512 :
9513 : {
9514 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9515 : {
9516 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9517 10 : if (eErr != CE_None)
9518 1 : return eErr;
9519 :
9520 9 : InvalidateMaskBand();
9521 :
9522 9 : return CE_None;
9523 : }
9524 :
9525 0 : ReportError(CE_Failure, CPLE_NotSupported,
9526 : "CreateMaskBand() not supported for this band.");
9527 :
9528 0 : return CE_Failure;
9529 : }
9530 :
9531 : /************************************************************************/
9532 : /* GDALCreateMaskBand() */
9533 : /************************************************************************/
9534 :
9535 : /**
9536 : * \brief Adds a mask band to the current band
9537 : *
9538 : * @see GDALRasterBand::CreateMaskBand()
9539 : */
9540 :
9541 34 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9542 :
9543 : {
9544 34 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9545 :
9546 34 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9547 34 : return poBand->CreateMaskBand(nFlags);
9548 : }
9549 :
9550 : /************************************************************************/
9551 : /* IsMaskBand() */
9552 : /************************************************************************/
9553 :
9554 : /**
9555 : * \brief Returns whether a band is a mask band.
9556 : *
9557 : * Mask band must be understood in the broad term: it can be a per-dataset
9558 : * mask band, an alpha band, or an implicit mask band.
9559 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9560 : *
9561 : * This method is the same as the C function GDALIsMaskBand().
9562 : *
9563 : * @return true if the band is a mask band.
9564 : *
9565 : * @see GDALDataset::CreateMaskBand()
9566 : *
9567 : * @since GDAL 3.5.0
9568 : *
9569 : */
9570 :
9571 444 : bool GDALRasterBand::IsMaskBand() const
9572 : {
9573 : // The GeoTIFF driver, among others, override this method to
9574 : // also handle external .msk bands.
9575 444 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9576 444 : GCI_AlphaBand;
9577 : }
9578 :
9579 : /************************************************************************/
9580 : /* GDALIsMaskBand() */
9581 : /************************************************************************/
9582 :
9583 : /**
9584 : * \brief Returns whether a band is a mask band.
9585 : *
9586 : * Mask band must be understood in the broad term: it can be a per-dataset
9587 : * mask band, an alpha band, or an implicit mask band.
9588 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9589 : *
9590 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9591 : *
9592 : * @return true if the band is a mask band.
9593 : *
9594 : * @see GDALRasterBand::IsMaskBand()
9595 : *
9596 : * @since GDAL 3.5.0
9597 : *
9598 : */
9599 :
9600 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9601 :
9602 : {
9603 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9604 :
9605 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9606 37 : return poBand->IsMaskBand();
9607 : }
9608 :
9609 : /************************************************************************/
9610 : /* GetMaskValueRange() */
9611 : /************************************************************************/
9612 :
9613 : /**
9614 : * \brief Returns the range of values that a mask band can take.
9615 : *
9616 : * @return the range of values that a mask band can take.
9617 : *
9618 : * @since GDAL 3.5.0
9619 : *
9620 : */
9621 :
9622 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9623 : {
9624 0 : return GMVR_UNKNOWN;
9625 : }
9626 :
9627 : /************************************************************************/
9628 : /* GetIndexColorTranslationTo() */
9629 : /************************************************************************/
9630 :
9631 : /**
9632 : * \brief Compute translation table for color tables.
9633 : *
9634 : * When the raster band has a palette index, it may be useful to compute
9635 : * the "translation" of this palette to the palette of another band.
9636 : * The translation tries to do exact matching first, and then approximate
9637 : * matching if no exact matching is possible.
9638 : * This method returns a table such that table[i] = j where i is an index
9639 : * of the 'this' rasterband and j the corresponding index for the reference
9640 : * rasterband.
9641 : *
9642 : * This method is thought as internal to GDAL and is used for drivers
9643 : * like RPFTOC.
9644 : *
9645 : * The implementation only supports 1-byte palette rasterbands.
9646 : *
9647 : * @param poReferenceBand the raster band
9648 : * @param pTranslationTable an already allocated translation table (at least 256
9649 : * bytes), or NULL to let the method allocate it
9650 : * @param pApproximateMatching a pointer to a flag that is set if the matching
9651 : * is approximate. May be NULL.
9652 : *
9653 : * @return a translation table if the two bands are palette index and that they
9654 : * do not match or NULL in other cases. The table must be freed with CPLFree if
9655 : * NULL was passed for pTranslationTable.
9656 : */
9657 :
9658 : unsigned char *
9659 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9660 : unsigned char *pTranslationTable,
9661 : int *pApproximateMatching)
9662 : {
9663 4 : if (poReferenceBand == nullptr)
9664 0 : return nullptr;
9665 :
9666 : // cppcheck-suppress knownConditionTrueFalse
9667 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9668 : // cppcheck-suppress knownConditionTrueFalse
9669 4 : GetColorInterpretation() == GCI_PaletteIndex &&
9670 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
9671 4 : GetRasterDataType() == GDT_Byte)
9672 : {
9673 4 : const GDALColorTable *srcColorTable = GetColorTable();
9674 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9675 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
9676 : {
9677 4 : const int nEntries = srcColorTable->GetColorEntryCount();
9678 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
9679 :
9680 4 : int bHasNoDataValueSrc = FALSE;
9681 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9682 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9683 4 : dfNoDataValueSrc <= 255 &&
9684 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9685 0 : bHasNoDataValueSrc = FALSE;
9686 4 : const int noDataValueSrc =
9687 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
9688 :
9689 4 : int bHasNoDataValueRef = FALSE;
9690 : const double dfNoDataValueRef =
9691 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
9692 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
9693 3 : dfNoDataValueRef <= 255 &&
9694 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
9695 1 : bHasNoDataValueRef = FALSE;
9696 4 : const int noDataValueRef =
9697 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
9698 :
9699 4 : bool samePalette = false;
9700 :
9701 4 : if (pApproximateMatching)
9702 3 : *pApproximateMatching = FALSE;
9703 :
9704 4 : if (nEntries == nRefEntries &&
9705 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
9706 3 : (bHasNoDataValueSrc == FALSE ||
9707 : noDataValueSrc == noDataValueRef))
9708 : {
9709 3 : samePalette = true;
9710 654 : for (int i = 0; i < nEntries; ++i)
9711 : {
9712 651 : if (noDataValueSrc == i)
9713 3 : continue;
9714 : const GDALColorEntry *entry =
9715 648 : srcColorTable->GetColorEntry(i);
9716 : const GDALColorEntry *entryRef =
9717 648 : destColorTable->GetColorEntry(i);
9718 648 : if (entry->c1 != entryRef->c1 ||
9719 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
9720 : {
9721 0 : samePalette = false;
9722 : }
9723 : }
9724 : }
9725 :
9726 4 : if (!samePalette)
9727 : {
9728 1 : if (pTranslationTable == nullptr)
9729 : {
9730 : pTranslationTable = static_cast<unsigned char *>(
9731 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
9732 1 : if (pTranslationTable == nullptr)
9733 1 : return nullptr;
9734 : }
9735 :
9736 : // Trying to remap the product palette on the subdataset
9737 : // palette.
9738 5 : for (int i = 0; i < nEntries; ++i)
9739 : {
9740 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
9741 : noDataValueSrc == i)
9742 0 : continue;
9743 : const GDALColorEntry *entry =
9744 4 : srcColorTable->GetColorEntry(i);
9745 4 : bool bMatchFound = false;
9746 13 : for (int j = 0; j < nRefEntries; ++j)
9747 : {
9748 10 : if (bHasNoDataValueRef && noDataValueRef == j)
9749 0 : continue;
9750 : const GDALColorEntry *entryRef =
9751 10 : destColorTable->GetColorEntry(j);
9752 10 : if (entry->c1 == entryRef->c1 &&
9753 2 : entry->c2 == entryRef->c2 &&
9754 2 : entry->c3 == entryRef->c3)
9755 : {
9756 1 : pTranslationTable[i] =
9757 : static_cast<unsigned char>(j);
9758 1 : bMatchFound = true;
9759 1 : break;
9760 : }
9761 : }
9762 4 : if (!bMatchFound)
9763 : {
9764 : // No exact match. Looking for closest color now.
9765 3 : int best_j = 0;
9766 3 : int best_distance = 0;
9767 3 : if (pApproximateMatching)
9768 0 : *pApproximateMatching = TRUE;
9769 12 : for (int j = 0; j < nRefEntries; ++j)
9770 : {
9771 : const GDALColorEntry *entryRef =
9772 9 : destColorTable->GetColorEntry(j);
9773 9 : int distance = (entry->c1 - entryRef->c1) *
9774 9 : (entry->c1 - entryRef->c1) +
9775 9 : (entry->c2 - entryRef->c2) *
9776 9 : (entry->c2 - entryRef->c2) +
9777 9 : (entry->c3 - entryRef->c3) *
9778 9 : (entry->c3 - entryRef->c3);
9779 9 : if (j == 0 || distance < best_distance)
9780 : {
9781 7 : best_j = j;
9782 7 : best_distance = distance;
9783 : }
9784 : }
9785 3 : pTranslationTable[i] =
9786 : static_cast<unsigned char>(best_j);
9787 : }
9788 : }
9789 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
9790 0 : pTranslationTable[noDataValueSrc] =
9791 : static_cast<unsigned char>(noDataValueRef);
9792 :
9793 1 : return pTranslationTable;
9794 : }
9795 : }
9796 : }
9797 3 : return nullptr;
9798 : }
9799 :
9800 : /************************************************************************/
9801 : /* SetFlushBlockErr() */
9802 : /************************************************************************/
9803 :
9804 : /**
9805 : * \brief Store that an error occurred while writing a dirty block.
9806 : *
9807 : * This function stores the fact that an error occurred while writing a dirty
9808 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
9809 : * flushed when the block cache get full, it is not convenient/possible to
9810 : * report that a dirty block could not be written correctly. This function
9811 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
9812 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
9813 : * places where the user can easily match the error with the relevant dataset.
9814 : */
9815 :
9816 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
9817 : {
9818 0 : eFlushBlockErr = eErr;
9819 0 : }
9820 :
9821 : /************************************************************************/
9822 : /* IncDirtyBlocks() */
9823 : /************************************************************************/
9824 :
9825 : /**
9826 : * \brief Increment/decrement the number of dirty blocks
9827 : */
9828 :
9829 796662 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9830 : {
9831 796662 : if (poBandBlockCache)
9832 796662 : poBandBlockCache->IncDirtyBlocks(nInc);
9833 796662 : }
9834 :
9835 : /************************************************************************/
9836 : /* ReportError() */
9837 : /************************************************************************/
9838 :
9839 : #ifndef DOXYGEN_XML
9840 : /**
9841 : * \brief Emits an error related to a raster band.
9842 : *
9843 : * This function is a wrapper for regular CPLError(). The only difference
9844 : * with CPLError() is that it prepends the error message with the dataset
9845 : * name and the band number.
9846 : *
9847 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9848 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9849 : * @param fmt a printf() style format string. Any additional arguments
9850 : * will be treated as arguments to fill in this format in a manner
9851 : * similar to printf().
9852 : *
9853 : */
9854 :
9855 2499 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9856 : const char *fmt, ...) const
9857 : {
9858 : va_list args;
9859 :
9860 2499 : va_start(args, fmt);
9861 :
9862 2499 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9863 2499 : pszDSName = CPLGetFilename(pszDSName);
9864 2499 : if (pszDSName[0] != '\0')
9865 : {
9866 2404 : CPLError(eErrClass, err_no, "%s",
9867 4808 : CPLString()
9868 2404 : .Printf("%s, band %d: ", pszDSName, GetBand())
9869 4808 : .append(CPLString().vPrintf(fmt, args))
9870 : .c_str());
9871 : }
9872 : else
9873 : {
9874 95 : CPLErrorV(eErrClass, err_no, fmt, args);
9875 : }
9876 :
9877 2499 : va_end(args);
9878 2499 : }
9879 : #endif
9880 :
9881 : /************************************************************************/
9882 : /* GetVirtualMemAuto() */
9883 : /************************************************************************/
9884 :
9885 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9886 : *
9887 : * Only supported on Linux and Unix systems with mmap() for now.
9888 : *
9889 : * This method allows creating a virtual memory object for a GDALRasterBand,
9890 : * that exposes the whole image data as a virtual array.
9891 : *
9892 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9893 : * specialized implementation, such as for raw files, may also directly use
9894 : * mechanisms of the operating system to create a view of the underlying file
9895 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9896 : *
9897 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9898 : * offer a specialized implementation with direct file mapping, provided that
9899 : * some requirements are met :
9900 : * - for all drivers, the dataset must be backed by a "real" file in the file
9901 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9902 : * must match the native ordering of the CPU.
9903 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9904 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9905 : * the file in sequential order, and be equally spaced (which is generally the
9906 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9907 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9908 : *
9909 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9910 : * CPLVirtualMemFree() must be called before the raster band object is
9911 : * destroyed.
9912 : *
9913 : * If p is such a pointer and base_type the type matching
9914 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9915 : * accessed with
9916 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9917 : *
9918 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9919 : *
9920 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9921 : * read/write the band.
9922 : *
9923 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9924 : * one pixel value in the buffer to the start of the next pixel value within a
9925 : * scanline.
9926 : *
9927 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9928 : * one scanline in the buffer to the start of the next.
9929 : *
9930 : * @param papszOptions NULL terminated list of options.
9931 : * If a specialized implementation exists, defining
9932 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9933 : * used. On the contrary, defining
9934 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9935 : * being used (thus only allowing efficient implementations to be used). When
9936 : * requiring or falling back to the default implementation, the following
9937 : * options are available : CACHE_SIZE (in bytes, defaults to
9938 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9939 : * to FALSE)
9940 : *
9941 : * @return a virtual memory object that must be unreferenced by
9942 : * CPLVirtualMemFree(), or NULL in case of failure.
9943 : *
9944 : */
9945 :
9946 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9947 : int *pnPixelSpace,
9948 : GIntBig *pnLineSpace,
9949 : char **papszOptions)
9950 : {
9951 9 : const char *pszImpl = CSLFetchNameValueDef(
9952 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9953 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9954 8 : EQUAL(pszImpl, "FALSE"))
9955 : {
9956 1 : return nullptr;
9957 : }
9958 :
9959 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9960 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9961 8 : if (pnPixelSpace)
9962 8 : *pnPixelSpace = nPixelSpace;
9963 8 : if (pnLineSpace)
9964 8 : *pnLineSpace = nLineSpace;
9965 : const size_t nCacheSize =
9966 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9967 : const size_t nPageSizeHint =
9968 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9969 8 : const bool bSingleThreadUsage = CPLTestBool(
9970 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9971 8 : return GDALRasterBandGetVirtualMem(
9972 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9973 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9974 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9975 8 : papszOptions);
9976 : }
9977 :
9978 : /************************************************************************/
9979 : /* GDALGetVirtualMemAuto() */
9980 : /************************************************************************/
9981 :
9982 : /**
9983 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9984 : *
9985 : * @see GDALRasterBand::GetVirtualMemAuto()
9986 : */
9987 :
9988 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9989 : int *pnPixelSpace, GIntBig *pnLineSpace,
9990 : CSLConstList papszOptions)
9991 : {
9992 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9993 :
9994 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9995 :
9996 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9997 31 : const_cast<char **>(papszOptions));
9998 : }
9999 :
10000 : /************************************************************************/
10001 : /* GDALGetDataCoverageStatus() */
10002 : /************************************************************************/
10003 :
10004 : /**
10005 : * \brief Get the coverage status of a sub-window of the raster.
10006 : *
10007 : * Returns whether a sub-window of the raster contains only data, only empty
10008 : * blocks or a mix of both. This function can be used to determine quickly
10009 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10010 : * be sparse.
10011 : *
10012 : * Empty blocks are blocks that are generally not physically present in the
10013 : * file, and when read through GDAL, contain only pixels whose value is the
10014 : * nodata value when it is set, or whose value is 0 when the nodata value is
10015 : * not set.
10016 : *
10017 : * The query is done in an efficient way without reading the actual pixel
10018 : * values. If not possible, or not implemented at all by the driver,
10019 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10020 : * be returned.
10021 : *
10022 : * The values that can be returned by the function are the following,
10023 : * potentially combined with the binary or operator :
10024 : * <ul>
10025 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10026 : * GetDataCoverageStatus(). This flag should be returned together with
10027 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10028 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10029 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10030 : * the queried window. This is typically identified by the concept of missing
10031 : * block in formats that supports it.
10032 : * </li>
10033 : * </ul>
10034 : *
10035 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10036 : * should be interpreted more as hint of potential presence of data. For example
10037 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10038 : * nodata value), instead of using the missing block mechanism,
10039 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10040 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10041 : *
10042 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10043 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10044 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10045 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10046 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10047 : * the function will exit, so that you can potentially refine the requested area
10048 : * to find which particular region(s) have missing blocks.
10049 : *
10050 : * @see GDALRasterBand::GetDataCoverageStatus()
10051 : *
10052 : * @param hBand raster band
10053 : *
10054 : * @param nXOff The pixel offset to the top left corner of the region
10055 : * of the band to be queried. This would be zero to start from the left side.
10056 : *
10057 : * @param nYOff The line offset to the top left corner of the region
10058 : * of the band to be queried. This would be zero to start from the top.
10059 : *
10060 : * @param nXSize The width of the region of the band to be queried in pixels.
10061 : *
10062 : * @param nYSize The height of the region of the band to be queried in lines.
10063 : *
10064 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10065 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10066 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10067 : * as the computation of the coverage matches the mask, the computation will be
10068 : * stopped. *pdfDataPct will not be valid in that case.
10069 : *
10070 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10071 : * to the (approximate) percentage in [0,100] of pixels in the queried
10072 : * sub-window that have valid values. The implementation might not always be
10073 : * able to compute it, in which case it will be set to a negative value.
10074 : *
10075 : * @return a binary-or'ed combination of possible values
10076 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10077 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10078 : */
10079 :
10080 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10081 : int nYOff, int nXSize, int nYSize,
10082 : int nMaskFlagStop, double *pdfDataPct)
10083 : {
10084 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10085 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10086 :
10087 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10088 :
10089 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10090 29 : nMaskFlagStop, pdfDataPct);
10091 : }
10092 :
10093 : /************************************************************************/
10094 : /* GetDataCoverageStatus() */
10095 : /************************************************************************/
10096 :
10097 : /**
10098 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10099 : * int nYOff,
10100 : * int nXSize,
10101 : * int nYSize,
10102 : * int nMaskFlagStop,
10103 : * double* pdfDataPct)
10104 : * \brief Get the coverage status of a sub-window of the raster.
10105 : *
10106 : * Returns whether a sub-window of the raster contains only data, only empty
10107 : * blocks or a mix of both. This function can be used to determine quickly
10108 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10109 : * be sparse.
10110 : *
10111 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10112 : * value when it is set, or whose value is 0 when the nodata value is not set.
10113 : *
10114 : * The query is done in an efficient way without reading the actual pixel
10115 : * values. If not possible, or not implemented at all by the driver,
10116 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10117 : * be returned.
10118 : *
10119 : * The values that can be returned by the function are the following,
10120 : * potentially combined with the binary or operator :
10121 : * <ul>
10122 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10123 : * GetDataCoverageStatus(). This flag should be returned together with
10124 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10125 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10126 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10127 : * the queried window. This is typically identified by the concept of missing
10128 : * block in formats that supports it.
10129 : * </li>
10130 : * </ul>
10131 : *
10132 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10133 : * should be interpreted more as hint of potential presence of data. For example
10134 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10135 : * nodata value), instead of using the missing block mechanism,
10136 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10137 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10138 : *
10139 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10140 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10141 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10142 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10143 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10144 : * the function will exit, so that you can potentially refine the requested area
10145 : * to find which particular region(s) have missing blocks.
10146 : *
10147 : * @see GDALGetDataCoverageStatus()
10148 : *
10149 : * @param nXOff The pixel offset to the top left corner of the region
10150 : * of the band to be queried. This would be zero to start from the left side.
10151 : *
10152 : * @param nYOff The line offset to the top left corner of the region
10153 : * of the band to be queried. This would be zero to start from the top.
10154 : *
10155 : * @param nXSize The width of the region of the band to be queried in pixels.
10156 : *
10157 : * @param nYSize The height of the region of the band to be queried in lines.
10158 : *
10159 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10160 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10161 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10162 : * as the computation of the coverage matches the mask, the computation will be
10163 : * stopped. *pdfDataPct will not be valid in that case.
10164 : *
10165 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10166 : * to the (approximate) percentage in [0,100] of pixels in the queried
10167 : * sub-window that have valid values. The implementation might not always be
10168 : * able to compute it, in which case it will be set to a negative value.
10169 : *
10170 : * @return a binary-or'ed combination of possible values
10171 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10172 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10173 : */
10174 :
10175 : /**
10176 : * \brief Get the coverage status of a sub-window of the raster.
10177 : *
10178 : * Returns whether a sub-window of the raster contains only data, only empty
10179 : * blocks or a mix of both. This function can be used to determine quickly
10180 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10181 : * be sparse.
10182 : *
10183 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10184 : * value when it is set, or whose value is 0 when the nodata value is not set.
10185 : *
10186 : * The query is done in an efficient way without reading the actual pixel
10187 : * values. If not possible, or not implemented at all by the driver,
10188 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10189 : * be returned.
10190 : *
10191 : * The values that can be returned by the function are the following,
10192 : * potentially combined with the binary or operator :
10193 : * <ul>
10194 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10195 : * GetDataCoverageStatus(). This flag should be returned together with
10196 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10197 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10198 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10199 : * the queried window. This is typically identified by the concept of missing
10200 : * block in formats that supports it.
10201 : * </li>
10202 : * </ul>
10203 : *
10204 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10205 : * should be interpreted more as hint of potential presence of data. For example
10206 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10207 : * nodata value), instead of using the missing block mechanism,
10208 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10209 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10210 : *
10211 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10212 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10213 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10214 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10215 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10216 : * the function will exit, so that you can potentially refine the requested area
10217 : * to find which particular region(s) have missing blocks.
10218 : *
10219 : * @see GDALGetDataCoverageStatus()
10220 : *
10221 : * @param nXOff The pixel offset to the top left corner of the region
10222 : * of the band to be queried. This would be zero to start from the left side.
10223 : *
10224 : * @param nYOff The line offset to the top left corner of the region
10225 : * of the band to be queried. This would be zero to start from the top.
10226 : *
10227 : * @param nXSize The width of the region of the band to be queried in pixels.
10228 : *
10229 : * @param nYSize The height of the region of the band to be queried in lines.
10230 : *
10231 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10232 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10233 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10234 : * as the computation of the coverage matches the mask, the computation will be
10235 : * stopped. *pdfDataPct will not be valid in that case.
10236 : *
10237 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10238 : * to the (approximate) percentage in [0,100] of pixels in the queried
10239 : * sub-window that have valid values. The implementation might not always be
10240 : * able to compute it, in which case it will be set to a negative value.
10241 : *
10242 : * @return a binary-or'ed combination of possible values
10243 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10244 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10245 : */
10246 :
10247 4702 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10248 : int nYSize, int nMaskFlagStop,
10249 : double *pdfDataPct)
10250 : {
10251 4702 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
10252 4702 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
10253 4702 : nYOff + nYSize > nRasterYSize)
10254 : {
10255 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10256 0 : if (pdfDataPct)
10257 0 : *pdfDataPct = 0.0;
10258 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10259 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10260 : }
10261 4702 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10262 4702 : pdfDataPct);
10263 : }
10264 :
10265 : /************************************************************************/
10266 : /* IGetDataCoverageStatus() */
10267 : /************************************************************************/
10268 :
10269 685 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10270 : int /*nXSize*/, int /*nYSize*/,
10271 : int /*nMaskFlagStop*/,
10272 : double *pdfDataPct)
10273 : {
10274 685 : if (pdfDataPct != nullptr)
10275 0 : *pdfDataPct = 100.0;
10276 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10277 685 : GDAL_DATA_COVERAGE_STATUS_DATA;
10278 : }
10279 :
10280 : //! @cond Doxygen_Suppress
10281 : /************************************************************************/
10282 : /* EnterReadWrite() */
10283 : /************************************************************************/
10284 :
10285 7798300 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10286 : {
10287 7798300 : if (poDS != nullptr)
10288 7033580 : return poDS->EnterReadWrite(eRWFlag);
10289 764719 : return FALSE;
10290 : }
10291 :
10292 : /************************************************************************/
10293 : /* LeaveReadWrite() */
10294 : /************************************************************************/
10295 :
10296 1129180 : void GDALRasterBand::LeaveReadWrite()
10297 : {
10298 1129180 : if (poDS != nullptr)
10299 1129190 : poDS->LeaveReadWrite();
10300 1129160 : }
10301 :
10302 : /************************************************************************/
10303 : /* InitRWLock() */
10304 : /************************************************************************/
10305 :
10306 3978300 : void GDALRasterBand::InitRWLock()
10307 : {
10308 3978300 : if (poDS != nullptr)
10309 3977890 : poDS->InitRWLock();
10310 3978300 : }
10311 :
10312 : //! @endcond
10313 :
10314 : // clang-format off
10315 :
10316 : /**
10317 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10318 : * \brief Set metadata.
10319 : *
10320 : * CAUTION: depending on the format, older values of the updated information
10321 : * might still be found in the file in a "ghost" state, even if no longer
10322 : * accessible through the GDAL API. This is for example the case of the GTiff
10323 : * format (this is not a exhaustive list)
10324 : *
10325 : * The C function GDALSetMetadata() does the same thing as this method.
10326 : *
10327 : * @param papszMetadata the metadata in name=value string list format to
10328 : * apply.
10329 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10330 : * domain.
10331 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10332 : * metadata has been accepted, but is likely not maintained persistently
10333 : * by the underlying object between sessions.
10334 : */
10335 :
10336 : /**
10337 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10338 : * \brief Set single metadata item.
10339 : *
10340 : * CAUTION: depending on the format, older values of the updated information
10341 : * might still be found in the file in a "ghost" state, even if no longer
10342 : * accessible through the GDAL API. This is for example the case of the GTiff
10343 : * format (this is not a exhaustive list)
10344 : *
10345 : * The C function GDALSetMetadataItem() does the same thing as this method.
10346 : *
10347 : * @param pszName the key for the metadata item to fetch.
10348 : * @param pszValue the value to assign to the key.
10349 : * @param pszDomain the domain to set within, use NULL for the default domain.
10350 : *
10351 : * @return CE_None on success, or an error code on failure.
10352 : */
10353 :
10354 : // clang-format on
10355 :
10356 : //! @cond Doxygen_Suppress
10357 : /************************************************************************/
10358 : /* EnablePixelTypeSignedByteWarning() */
10359 : /************************************************************************/
10360 :
10361 157189 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10362 : {
10363 157189 : m_bEnablePixelTypeSignedByteWarning = b;
10364 157189 : }
10365 :
10366 4904 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10367 : {
10368 4904 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10369 4904 : }
10370 :
10371 : //! @endcond
10372 :
10373 : /************************************************************************/
10374 : /* GetMetadataItem() */
10375 : /************************************************************************/
10376 :
10377 621303 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10378 : const char *pszDomain)
10379 : {
10380 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10381 621303 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
10382 462644 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10383 322017 : EQUAL(pszName, "PIXELTYPE"))
10384 : {
10385 2 : CPLError(CE_Warning, CPLE_AppDefined,
10386 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10387 : "used to signal signed 8-bit raster. Change your code to "
10388 : "test for the new GDT_Int8 data type instead.");
10389 : }
10390 621303 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10391 : }
10392 :
10393 : /************************************************************************/
10394 : /* WindowIterator */
10395 : /************************************************************************/
10396 :
10397 : //! @cond Doxygen_Suppress
10398 :
10399 576 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10400 : int nRasterYSize,
10401 : int nBlockXSize, int nBlockYSize,
10402 576 : int nRow, int nCol)
10403 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10404 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10405 576 : m_col(nCol)
10406 : {
10407 576 : }
10408 :
10409 784 : bool GDALRasterBand::WindowIterator::operator==(
10410 : const WindowIterator &other) const
10411 : {
10412 259 : return m_row == other.m_row && m_col == other.m_col &&
10413 259 : m_nRasterXSize == other.m_nRasterXSize &&
10414 259 : m_nRasterYSize == other.m_nRasterYSize &&
10415 1302 : m_nBlockXSize == other.m_nBlockXSize &&
10416 1043 : m_nBlockYSize == other.m_nBlockYSize;
10417 : }
10418 :
10419 758 : bool GDALRasterBand::WindowIterator::operator!=(
10420 : const WindowIterator &other) const
10421 : {
10422 758 : return !(*this == other);
10423 : }
10424 :
10425 : GDALRasterBand::WindowIterator::value_type
10426 524 : GDALRasterBand::WindowIterator::operator*() const
10427 : {
10428 : GDALRasterWindow ret;
10429 524 : ret.nXOff = m_col * m_nBlockXSize;
10430 524 : ret.nYOff = m_row * m_nBlockYSize;
10431 524 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10432 524 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10433 :
10434 524 : return ret;
10435 : }
10436 :
10437 522 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10438 : {
10439 522 : m_col++;
10440 522 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10441 : {
10442 438 : m_col = 0;
10443 438 : m_row++;
10444 : }
10445 522 : return *this;
10446 : }
10447 :
10448 305 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10449 305 : const GDALRasterBand &band, size_t maxSize)
10450 305 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
10451 305 : m_nBlockXSize(-1), m_nBlockYSize(-1)
10452 : {
10453 : #ifdef CSA_BUILD
10454 : assert(this);
10455 : #endif
10456 : int nXSize, nYSize;
10457 :
10458 305 : CPLErrorStateBackuper state(CPLQuietErrorHandler);
10459 305 : band.GetBlockSize(&nXSize, &nYSize);
10460 305 : if (nXSize < 1 || nYSize < 0)
10461 : {
10462 : // If invalid block size is reported, assume scanlines
10463 4 : nXSize = m_nRasterXSize;
10464 4 : nYSize = 1;
10465 : }
10466 :
10467 305 : if (maxSize == 0)
10468 : {
10469 234 : m_nBlockXSize = nXSize;
10470 234 : m_nBlockYSize = nYSize;
10471 234 : return;
10472 : }
10473 :
10474 71 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10475 71 : const double dfBlocksPerChunk =
10476 71 : static_cast<double>(maxSize) /
10477 71 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10478 :
10479 71 : if (dfBlocksPerChunk < dfBlocksPerRow)
10480 : {
10481 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10482 14 : m_nRasterXSize,
10483 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10484 14 : m_nBlockYSize = nYSize;
10485 : }
10486 : else
10487 : {
10488 57 : m_nBlockXSize = m_nRasterXSize;
10489 57 : m_nBlockYSize = static_cast<int>(std::min<double>(
10490 57 : m_nRasterYSize,
10491 57 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10492 : }
10493 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10494 : {
10495 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10496 : {
10497 : nXSize = m_nRasterXSize;
10498 : nYSize = 1;
10499 : }
10500 : }
10501 : }
10502 :
10503 : GDALRasterBand::WindowIterator
10504 274 : GDALRasterBand::WindowIteratorWrapper::begin() const
10505 : {
10506 274 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10507 274 : m_nBlockYSize, 0, 0);
10508 : }
10509 :
10510 : GDALRasterBand::WindowIterator
10511 274 : GDALRasterBand::WindowIteratorWrapper::end() const
10512 : {
10513 274 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10514 274 : m_nBlockYSize,
10515 274 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10516 : }
10517 :
10518 63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10519 : {
10520 63 : return static_cast<uint64_t>(
10521 63 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10522 63 : static_cast<uint64_t>(
10523 63 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10524 : }
10525 :
10526 : //! @endcond
10527 :
10528 : /** Return an object whose begin() and end() methods can be used to iterate
10529 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10530 : * band. The iteration order is from left to right, then from top to bottom.
10531 : *
10532 : \code{.cpp}
10533 : std::vector<double> pixelValues;
10534 : for (const auto& window : poBand->IterateWindows()) {
10535 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10536 : window.nXSize, window.nYSize);
10537 : // check eErr
10538 : }
10539 : \endcode
10540 : *
10541 : *
10542 : * @param maxSize The maximum number of pixels in each window. If set to
10543 : * zero (the default), or a number smaller than the block size,
10544 : * the window size will be the same as the block size.
10545 : * @since GDAL 3.12
10546 : */
10547 : GDALRasterBand::WindowIteratorWrapper
10548 305 : GDALRasterBand::IterateWindows(size_t maxSize) const
10549 : {
10550 305 : return WindowIteratorWrapper(*this, maxSize);
10551 : }
10552 :
10553 : /************************************************************************/
10554 : /* GDALMDArrayFromRasterBand */
10555 : /************************************************************************/
10556 :
10557 : class GDALMDArrayFromRasterBand final : public GDALMDArray
10558 : {
10559 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10560 :
10561 : GDALDataset *m_poDS;
10562 : GDALRasterBand *m_poBand;
10563 : GDALExtendedDataType m_dt;
10564 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10565 : std::string m_osUnit;
10566 : std::vector<GByte> m_pabyNoData{};
10567 : std::shared_ptr<GDALMDArray> m_varX{};
10568 : std::shared_ptr<GDALMDArray> m_varY{};
10569 : std::string m_osFilename{};
10570 :
10571 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10572 : const size_t *count, const GInt64 *arrayStep,
10573 : const GPtrDiff_t *bufferStride,
10574 : const GDALExtendedDataType &bufferDataType,
10575 : void *pBuffer) const;
10576 :
10577 : protected:
10578 34 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10579 68 : : GDALAbstractMDArray(std::string(),
10580 68 : std::string(poDS->GetDescription()) +
10581 : CPLSPrintf(" band %d", poBand->GetBand())),
10582 68 : GDALMDArray(std::string(),
10583 68 : std::string(poDS->GetDescription()) +
10584 : CPLSPrintf(" band %d", poBand->GetBand())),
10585 : m_poDS(poDS), m_poBand(poBand),
10586 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10587 170 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10588 : {
10589 34 : m_poDS->Reference();
10590 :
10591 34 : int bHasNoData = false;
10592 34 : if (m_poBand->GetRasterDataType() == GDT_Int64)
10593 : {
10594 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10595 0 : if (bHasNoData)
10596 : {
10597 0 : m_pabyNoData.resize(m_dt.GetSize());
10598 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10599 : m_dt.GetNumericDataType(), 0, 1);
10600 : }
10601 : }
10602 34 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10603 : {
10604 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10605 0 : if (bHasNoData)
10606 : {
10607 0 : m_pabyNoData.resize(m_dt.GetSize());
10608 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10609 : m_dt.GetNumericDataType(), 0, 1);
10610 : }
10611 : }
10612 : else
10613 : {
10614 34 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10615 34 : if (bHasNoData)
10616 : {
10617 1 : m_pabyNoData.resize(m_dt.GetSize());
10618 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10619 : m_dt.GetNumericDataType(), 0, 1);
10620 : }
10621 : }
10622 :
10623 34 : const int nXSize = poBand->GetXSize();
10624 34 : const int nYSize = poBand->GetYSize();
10625 :
10626 34 : auto poSRS = m_poDS->GetSpatialRef();
10627 68 : std::string osTypeY;
10628 68 : std::string osTypeX;
10629 68 : std::string osDirectionY;
10630 68 : std::string osDirectionX;
10631 34 : if (poSRS && poSRS->GetAxesCount() == 2)
10632 : {
10633 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10634 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
10635 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
10636 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
10637 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
10638 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10639 : {
10640 8 : if (mapping == std::vector<int>{1, 2})
10641 : {
10642 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10643 8 : osDirectionY = "NORTH";
10644 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10645 8 : osDirectionX = "EAST";
10646 : }
10647 : }
10648 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
10649 : {
10650 16 : if (mapping == std::vector<int>{2, 1})
10651 : {
10652 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10653 16 : osDirectionY = "NORTH";
10654 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10655 16 : osDirectionX = "EAST";
10656 : }
10657 : }
10658 : }
10659 :
10660 170 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
10661 : "/", "Y", osTypeY, osDirectionY, nYSize),
10662 68 : std::make_shared<GDALDimensionWeakIndexingVar>(
10663 102 : "/", "X", osTypeX, osDirectionX, nXSize)};
10664 :
10665 34 : GDALGeoTransform gt;
10666 34 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
10667 : {
10668 50 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
10669 50 : gt[0], gt[1], 0.5);
10670 25 : m_dims[1]->SetIndexingVariable(m_varX);
10671 :
10672 50 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
10673 50 : gt[3], gt[5], 0.5);
10674 25 : m_dims[0]->SetIndexingVariable(m_varY);
10675 : }
10676 34 : }
10677 :
10678 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
10679 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10680 : const GDALExtendedDataType &bufferDataType,
10681 : void *pDstBuffer) const override;
10682 :
10683 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
10684 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10685 : const GDALExtendedDataType &bufferDataType,
10686 : const void *pSrcBuffer) override
10687 : {
10688 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
10689 : bufferStride, bufferDataType,
10690 1 : const_cast<void *>(pSrcBuffer));
10691 : }
10692 :
10693 : public:
10694 68 : ~GDALMDArrayFromRasterBand() override
10695 34 : {
10696 34 : m_poDS->ReleaseRef();
10697 68 : }
10698 :
10699 34 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
10700 : GDALRasterBand *poBand)
10701 : {
10702 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
10703 68 : new GDALMDArrayFromRasterBand(poDS, poBand)));
10704 34 : array->SetSelf(array);
10705 68 : return array;
10706 : }
10707 :
10708 5 : bool IsWritable() const override
10709 : {
10710 5 : return m_poDS->GetAccess() == GA_Update;
10711 : }
10712 :
10713 122 : const std::string &GetFilename() const override
10714 : {
10715 122 : return m_osFilename;
10716 : }
10717 :
10718 : const std::vector<std::shared_ptr<GDALDimension>> &
10719 343 : GetDimensions() const override
10720 : {
10721 343 : return m_dims;
10722 : }
10723 :
10724 158 : const GDALExtendedDataType &GetDataType() const override
10725 : {
10726 158 : return m_dt;
10727 : }
10728 :
10729 5 : const std::string &GetUnit() const override
10730 : {
10731 5 : return m_osUnit;
10732 : }
10733 :
10734 32 : const void *GetRawNoDataValue() const override
10735 : {
10736 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
10737 : }
10738 :
10739 4 : double GetOffset(bool *pbHasOffset,
10740 : GDALDataType *peStorageType) const override
10741 : {
10742 4 : int bHasOffset = false;
10743 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
10744 4 : if (pbHasOffset)
10745 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
10746 4 : if (peStorageType)
10747 1 : *peStorageType = GDT_Unknown;
10748 4 : return dfRes;
10749 : }
10750 :
10751 4 : double GetScale(bool *pbHasScale,
10752 : GDALDataType *peStorageType) const override
10753 : {
10754 4 : int bHasScale = false;
10755 4 : double dfRes = m_poBand->GetScale(&bHasScale);
10756 4 : if (pbHasScale)
10757 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
10758 4 : if (peStorageType)
10759 1 : *peStorageType = GDT_Unknown;
10760 4 : return dfRes;
10761 : }
10762 :
10763 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
10764 : {
10765 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
10766 88 : if (!poSrcSRS)
10767 2 : return nullptr;
10768 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
10769 :
10770 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
10771 86 : constexpr int iYDim = 0;
10772 86 : constexpr int iXDim = 1;
10773 258 : for (auto &m : axisMapping)
10774 : {
10775 172 : if (m == 1)
10776 86 : m = iXDim + 1;
10777 86 : else if (m == 2)
10778 86 : m = iYDim + 1;
10779 : else
10780 0 : m = 0;
10781 : }
10782 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
10783 86 : return poSRS;
10784 : }
10785 :
10786 32 : std::vector<GUInt64> GetBlockSize() const override
10787 : {
10788 32 : int nBlockXSize = 0;
10789 32 : int nBlockYSize = 0;
10790 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
10791 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
10792 32 : static_cast<GUInt64>(nBlockXSize)};
10793 : }
10794 :
10795 : std::vector<std::shared_ptr<GDALAttribute>>
10796 23 : GetAttributes(CSLConstList) const override
10797 : {
10798 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
10799 23 : auto papszMD = m_poBand->GetMetadata();
10800 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
10801 : {
10802 2 : char *pszKey = nullptr;
10803 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
10804 2 : if (pszKey && pszValue)
10805 : {
10806 : res.emplace_back(
10807 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
10808 : }
10809 2 : CPLFree(pszKey);
10810 : }
10811 23 : return res;
10812 : }
10813 : };
10814 :
10815 39 : bool GDALMDArrayFromRasterBand::IRead(
10816 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
10817 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
10818 : void *pDstBuffer) const
10819 : {
10820 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
10821 39 : bufferDataType, pDstBuffer);
10822 : }
10823 :
10824 : /************************************************************************/
10825 : /* ReadWrite() */
10826 : /************************************************************************/
10827 :
10828 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
10829 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10830 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10831 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10832 : {
10833 40 : constexpr size_t iDimX = 1;
10834 40 : constexpr size_t iDimY = 0;
10835 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10836 : arrayStartIdx, count, arrayStep, bufferStride,
10837 40 : bufferDataType, pBuffer);
10838 : }
10839 :
10840 : /************************************************************************/
10841 : /* GDALMDRasterIOFromBand() */
10842 : /************************************************************************/
10843 :
10844 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10845 : size_t iDimX, size_t iDimY,
10846 : const GUInt64 *arrayStartIdx, const size_t *count,
10847 : const GInt64 *arrayStep,
10848 : const GPtrDiff_t *bufferStride,
10849 : const GDALExtendedDataType &bufferDataType,
10850 : void *pBuffer)
10851 : {
10852 73 : const auto eDT(bufferDataType.GetNumericDataType());
10853 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10854 73 : const int nX =
10855 73 : arrayStep[iDimX] > 0
10856 73 : ? static_cast<int>(arrayStartIdx[iDimX])
10857 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10858 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10859 73 : const int nY =
10860 73 : arrayStep[iDimY] > 0
10861 73 : ? static_cast<int>(arrayStartIdx[iDimY])
10862 6 : : static_cast<int>(arrayStartIdx[iDimY] -
10863 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10864 73 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10865 73 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10866 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10867 73 : int nStrideXSign = 1;
10868 73 : if (arrayStep[iDimX] < 0)
10869 : {
10870 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10871 2 : nStrideXSign = -1;
10872 : }
10873 73 : int nStrideYSign = 1;
10874 73 : if (arrayStep[iDimY] < 0)
10875 : {
10876 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10877 6 : nStrideYSign = -1;
10878 : }
10879 :
10880 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10881 73 : static_cast<int>(count[iDimX]),
10882 73 : static_cast<int>(count[iDimY]), eDT,
10883 : static_cast<GSpacing>(
10884 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10885 : static_cast<GSpacing>(
10886 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10887 73 : nullptr) == CE_None;
10888 : }
10889 :
10890 : /************************************************************************/
10891 : /* AsMDArray() */
10892 : /************************************************************************/
10893 :
10894 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10895 : *
10896 : * The band must be linked to a GDALDataset. If this dataset is not already
10897 : * marked as shared, it will be, so that the returned array holds a reference
10898 : * to it.
10899 : *
10900 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10901 : * returned array will have an associated indexing variable.
10902 : *
10903 : * This is the same as the C function GDALRasterBandAsMDArray().
10904 : *
10905 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10906 : *
10907 : * @return a new array, or nullptr.
10908 : *
10909 : * @since GDAL 3.1
10910 : */
10911 34 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10912 : {
10913 34 : if (!poDS)
10914 : {
10915 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10916 0 : return nullptr;
10917 : }
10918 34 : if (!poDS->GetShared())
10919 : {
10920 33 : poDS->MarkAsShared();
10921 : }
10922 : return GDALMDArrayFromRasterBand::Create(
10923 34 : poDS, const_cast<GDALRasterBand *>(this));
10924 : }
10925 :
10926 : /************************************************************************/
10927 : /* InterpolateAtPoint() */
10928 : /************************************************************************/
10929 :
10930 : /**
10931 : * \brief Interpolates the value between pixels using a resampling algorithm,
10932 : * taking pixel/line coordinates as input.
10933 : *
10934 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10935 : * @param dfLine line coordinate as a double, where interpolation should be done.
10936 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10937 : * @param pdfRealValue pointer to real part of interpolated value
10938 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10939 : *
10940 : * @return CE_None on success, or an error code on failure.
10941 : * @since GDAL 3.10
10942 : */
10943 :
10944 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10945 : GDALRIOResampleAlg eInterpolation,
10946 : double *pdfRealValue,
10947 : double *pdfImagValue) const
10948 : {
10949 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10950 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10951 : eInterpolation != GRIORA_CubicSpline)
10952 : {
10953 2 : CPLError(CE_Failure, CPLE_AppDefined,
10954 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10955 : "methods "
10956 : "allowed");
10957 :
10958 2 : return CE_Failure;
10959 : }
10960 :
10961 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10962 165 : if (!m_poPointsCache)
10963 85 : m_poPointsCache = new GDALDoublePointsCache();
10964 :
10965 : const bool res =
10966 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10967 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10968 :
10969 165 : return res ? CE_None : CE_Failure;
10970 : }
10971 :
10972 : /************************************************************************/
10973 : /* GDALRasterInterpolateAtPoint() */
10974 : /************************************************************************/
10975 :
10976 : /**
10977 : * \brief Interpolates the value between pixels using
10978 : * a resampling algorithm
10979 : *
10980 : * @see GDALRasterBand::InterpolateAtPoint()
10981 : * @since GDAL 3.10
10982 : */
10983 :
10984 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10985 : double dfLine,
10986 : GDALRIOResampleAlg eInterpolation,
10987 : double *pdfRealValue, double *pdfImagValue)
10988 : {
10989 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10990 :
10991 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10992 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10993 144 : pdfRealValue, pdfImagValue);
10994 : }
10995 :
10996 : /************************************************************************/
10997 : /* InterpolateAtGeolocation() */
10998 : /************************************************************************/
10999 :
11000 : /**
11001 : * \brief Interpolates the value between pixels using a resampling algorithm,
11002 : * taking georeferenced coordinates as input.
11003 : *
11004 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11005 : * must be in the "natural" SRS of the dataset, that is the one returned by
11006 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11007 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11008 : * array (generally WGS 84) if there is a geolocation array.
11009 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11010 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11011 : * be a easting, and dfGeolocY a northing.
11012 : *
11013 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11014 : * expressed in that CRS, and that tuple must be conformant with the
11015 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11016 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11017 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11018 : * before calling this method, and in that case, dfGeolocX must be a longitude
11019 : * or an easting value, and dfGeolocX a latitude or a northing value.
11020 : *
11021 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11022 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11023 : * it for details on how that transformation is done.
11024 : *
11025 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11026 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11027 : * where interpolation should be done.
11028 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11029 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11030 : * where interpolation should be done.
11031 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11032 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11033 : * @param pdfRealValue pointer to real part of interpolated value
11034 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11035 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11036 : *
11037 : * @return CE_None on success, or an error code on failure.
11038 : * @since GDAL 3.11
11039 : */
11040 :
11041 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11042 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11043 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11044 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11045 : {
11046 : double dfPixel;
11047 : double dfLine;
11048 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11049 : &dfLine,
11050 15 : papszTransformerOptions) != CE_None)
11051 : {
11052 1 : return CE_Failure;
11053 : }
11054 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11055 14 : pdfImagValue);
11056 : }
11057 :
11058 : /************************************************************************/
11059 : /* GDALRasterInterpolateAtGeolocation() */
11060 : /************************************************************************/
11061 :
11062 : /**
11063 : * \brief Interpolates the value between pixels using a resampling algorithm,
11064 : * taking georeferenced coordinates as input.
11065 : *
11066 : * @see GDALRasterBand::InterpolateAtGeolocation()
11067 : * @since GDAL 3.11
11068 : */
11069 :
11070 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11071 : double dfGeolocX, double dfGeolocY,
11072 : OGRSpatialReferenceH hSRS,
11073 : GDALRIOResampleAlg eInterpolation,
11074 : double *pdfRealValue,
11075 : double *pdfImagValue,
11076 : CSLConstList papszTransformerOptions)
11077 : {
11078 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11079 :
11080 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11081 15 : return poBand->InterpolateAtGeolocation(
11082 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11083 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11084 : }
11085 :
11086 : /************************************************************************/
11087 : /* GDALRasterBand::SplitRasterIO() */
11088 : /************************************************************************/
11089 :
11090 : //! @cond Doxygen_Suppress
11091 :
11092 : /** Implements IRasterIO() by dividing the request in 2.
11093 : *
11094 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11095 : *
11096 : * Return CE_Warning if the split could not be done, CE_None in case of
11097 : * success and CE_Failure in case of error.
11098 : *
11099 : * @since 3.12
11100 : */
11101 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11102 : [[maybe_unused]] int nXSize,
11103 : [[maybe_unused]] int nYSize, void *pData,
11104 : int nBufXSize, int nBufYSize,
11105 : GDALDataType eBufType,
11106 : GSpacing nPixelSpace, GSpacing nLineSpace,
11107 : GDALRasterIOExtraArg *psExtraArg)
11108 : {
11109 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11110 :
11111 999 : GByte *pabyData = static_cast<GByte *>(pData);
11112 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11113 : {
11114 : GDALRasterIOExtraArg sArg;
11115 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11116 499 : const int nHalfHeight = nBufYSize / 2;
11117 :
11118 499 : sArg.pfnProgress = GDALScaledProgress;
11119 499 : sArg.pProgressData = GDALCreateScaledProgress(
11120 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11121 499 : if (sArg.pProgressData == nullptr)
11122 499 : sArg.pfnProgress = nullptr;
11123 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11124 : pabyData, nBufXSize, nHalfHeight, eBufType,
11125 499 : nPixelSpace, nLineSpace, &sArg);
11126 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11127 :
11128 499 : if (eErr == CE_None)
11129 : {
11130 499 : sArg.pfnProgress = GDALScaledProgress;
11131 499 : sArg.pProgressData = GDALCreateScaledProgress(
11132 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11133 499 : if (sArg.pProgressData == nullptr)
11134 499 : sArg.pfnProgress = nullptr;
11135 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11136 : nBufYSize - nHalfHeight,
11137 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11138 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11139 499 : nLineSpace, &sArg);
11140 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11141 : }
11142 499 : return eErr;
11143 : }
11144 500 : else if (nBufXSize >= 2)
11145 : {
11146 : GDALRasterIOExtraArg sArg;
11147 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11148 500 : const int nHalfWidth = nBufXSize / 2;
11149 :
11150 500 : sArg.pfnProgress = GDALScaledProgress;
11151 500 : sArg.pProgressData = GDALCreateScaledProgress(
11152 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11153 500 : if (sArg.pProgressData == nullptr)
11154 500 : sArg.pfnProgress = nullptr;
11155 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11156 : pabyData, nHalfWidth, nBufYSize, eBufType,
11157 500 : nPixelSpace, nLineSpace, &sArg);
11158 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11159 :
11160 500 : if (eErr == CE_None)
11161 : {
11162 500 : sArg.pfnProgress = GDALScaledProgress;
11163 500 : sArg.pProgressData = GDALCreateScaledProgress(
11164 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11165 500 : if (sArg.pProgressData == nullptr)
11166 500 : sArg.pfnProgress = nullptr;
11167 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11168 : nBufXSize - nHalfWidth, nBufYSize,
11169 500 : pabyData + nHalfWidth * nPixelSpace,
11170 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11171 500 : nPixelSpace, nLineSpace, &sArg);
11172 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11173 : }
11174 500 : return eErr;
11175 : }
11176 :
11177 0 : return CE_Warning;
11178 : }
11179 :
11180 : //! @endcond
11181 :
11182 : /************************************************************************/
11183 : /* ThrowIfNotSameDimensions() */
11184 : /************************************************************************/
11185 :
11186 : //! @cond Doxygen_Suppress
11187 : /* static */
11188 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11189 : const GDALRasterBand &second)
11190 : {
11191 320 : if (first.GetXSize() != second.GetXSize() ||
11192 151 : first.GetYSize() != second.GetYSize())
11193 : {
11194 36 : throw std::runtime_error("Bands do not have the same dimensions");
11195 : }
11196 133 : }
11197 :
11198 : //! @endcond
11199 :
11200 : /************************************************************************/
11201 : /* GDALRasterBandUnaryOp() */
11202 : /************************************************************************/
11203 :
11204 : /** Apply a unary operation on this band.
11205 : *
11206 : * The resulting band is lazy evaluated. A reference is taken on the input
11207 : * dataset.
11208 : *
11209 : * @since 3.12
11210 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11211 : */
11212 : GDALComputedRasterBandH
11213 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11214 : GDALRasterAlgebraUnaryOperation eOp)
11215 : {
11216 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11217 6 : GDALComputedRasterBand::Operation cppOp{};
11218 6 : switch (eOp)
11219 : {
11220 2 : case GRAUO_LOGICAL_NOT:
11221 : return new GDALComputedRasterBand(
11222 : GDALComputedRasterBand::Operation::OP_NE,
11223 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11224 1 : case GRAUO_ABS:
11225 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11226 1 : break;
11227 1 : case GRAUO_SQRT:
11228 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11229 1 : break;
11230 1 : case GRAUO_LOG:
11231 : #ifndef HAVE_MUPARSER
11232 : CPLError(
11233 : CE_Failure, CPLE_NotSupported,
11234 : "log(band) not available on a GDAL build without muparser");
11235 : return nullptr;
11236 : #else
11237 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11238 1 : break;
11239 : #endif
11240 1 : case GRAUO_LOG10:
11241 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11242 1 : break;
11243 : }
11244 : return new GDALComputedRasterBand(cppOp,
11245 4 : *(GDALRasterBand::FromHandle(hBand)));
11246 : }
11247 :
11248 : /************************************************************************/
11249 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11250 : /************************************************************************/
11251 :
11252 : static GDALComputedRasterBand::Operation
11253 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11254 : GDALRasterAlgebraBinaryOperation eOp)
11255 : {
11256 120 : switch (eOp)
11257 : {
11258 26 : case GRABO_ADD:
11259 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11260 2 : case GRABO_SUB:
11261 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11262 24 : case GRABO_MUL:
11263 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11264 3 : case GRABO_DIV:
11265 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11266 6 : case GRABO_GT:
11267 6 : return GDALComputedRasterBand::Operation::OP_GT;
11268 8 : case GRABO_GE:
11269 8 : return GDALComputedRasterBand::Operation::OP_GE;
11270 6 : case GRABO_LT:
11271 6 : return GDALComputedRasterBand::Operation::OP_LT;
11272 6 : case GRABO_LE:
11273 6 : return GDALComputedRasterBand::Operation::OP_LE;
11274 6 : case GRABO_EQ:
11275 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11276 6 : case GRABO_NE:
11277 6 : break;
11278 12 : case GRABO_LOGICAL_AND:
11279 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11280 12 : case GRABO_LOGICAL_OR:
11281 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11282 3 : case GRABO_POW:
11283 3 : return GDALComputedRasterBand::Operation::OP_POW;
11284 : }
11285 6 : return GDALComputedRasterBand::Operation::OP_NE;
11286 : }
11287 :
11288 : /************************************************************************/
11289 : /* GDALRasterBandBinaryOpBand() */
11290 : /************************************************************************/
11291 :
11292 : /** Apply a binary operation on this band with another one.
11293 : *
11294 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11295 : * "hBand1 - hBand2".
11296 : *
11297 : * The resulting band is lazy evaluated. A reference is taken on both input
11298 : * datasets.
11299 : *
11300 : * @since 3.12
11301 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11302 : */
11303 : GDALComputedRasterBandH
11304 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11305 : GDALRasterAlgebraBinaryOperation eOp,
11306 : GDALRasterBandH hOtherBand)
11307 : {
11308 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11309 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11310 : #ifndef HAVE_MUPARSER
11311 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11312 : {
11313 : CPLError(
11314 : CE_Failure, CPLE_NotSupported,
11315 : "Band comparison operators not available on a GDAL build without "
11316 : "muparser");
11317 : return nullptr;
11318 : }
11319 : else if (eOp == GRABO_POW)
11320 : {
11321 : CPLError(
11322 : CE_Failure, CPLE_NotSupported,
11323 : "pow(band, band) not available on a GDAL build without muparser");
11324 : return nullptr;
11325 : }
11326 : #endif
11327 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11328 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11329 : try
11330 : {
11331 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11332 : }
11333 13 : catch (const std::exception &e)
11334 : {
11335 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11336 13 : return nullptr;
11337 : }
11338 : return new GDALComputedRasterBand(
11339 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11340 44 : secondBand);
11341 : }
11342 :
11343 : /************************************************************************/
11344 : /* GDALRasterBandBinaryOpDouble() */
11345 : /************************************************************************/
11346 :
11347 : /** Apply a binary operation on this band with a constant
11348 : *
11349 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11350 : * "hBand - constant".
11351 : *
11352 : * The resulting band is lazy evaluated. A reference is taken on the input
11353 : * dataset.
11354 : *
11355 : * @since 3.12
11356 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11357 : */
11358 : GDALComputedRasterBandH
11359 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11360 : GDALRasterAlgebraBinaryOperation eOp,
11361 : double constant)
11362 : {
11363 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11364 : #ifndef HAVE_MUPARSER
11365 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11366 : {
11367 : CPLError(
11368 : CE_Failure, CPLE_NotSupported,
11369 : "Band comparison operators not available on a GDAL build without "
11370 : "muparser");
11371 : return nullptr;
11372 : }
11373 : #endif
11374 : return new GDALComputedRasterBand(
11375 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11376 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11377 : }
11378 :
11379 : /************************************************************************/
11380 : /* GDALRasterBandBinaryOpDoubleToBand() */
11381 : /************************************************************************/
11382 :
11383 : /** Apply a binary operation on the constant with this band
11384 : *
11385 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11386 : * "constant - hBand".
11387 : *
11388 : * The resulting band is lazy evaluated. A reference is taken on the input
11389 : * dataset.
11390 : *
11391 : * @since 3.12
11392 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11393 : */
11394 : GDALComputedRasterBandH
11395 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11396 : GDALRasterAlgebraBinaryOperation eOp,
11397 : GDALRasterBandH hBand)
11398 : {
11399 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11400 : #ifndef HAVE_MUPARSER
11401 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11402 : {
11403 : CPLError(
11404 : CE_Failure, CPLE_NotSupported,
11405 : "Band comparison operators not available on a GDAL build without "
11406 : "muparser");
11407 : return nullptr;
11408 : }
11409 : #endif
11410 18 : switch (eOp)
11411 : {
11412 15 : case GRABO_ADD:
11413 : case GRABO_MUL:
11414 : {
11415 : return new GDALComputedRasterBand(
11416 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11417 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11418 : }
11419 :
11420 2 : case GRABO_DIV:
11421 : case GRABO_GT:
11422 : case GRABO_GE:
11423 : case GRABO_LT:
11424 : case GRABO_LE:
11425 : case GRABO_EQ:
11426 : case GRABO_NE:
11427 : case GRABO_LOGICAL_AND:
11428 : case GRABO_LOGICAL_OR:
11429 : case GRABO_POW:
11430 : {
11431 : return new GDALComputedRasterBand(
11432 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11433 2 : *(GDALRasterBand::FromHandle(hBand)));
11434 : }
11435 :
11436 1 : case GRABO_SUB:
11437 : {
11438 1 : break;
11439 : }
11440 : }
11441 :
11442 : return new GDALComputedRasterBand(
11443 : GDALComputedRasterBand::Operation::OP_ADD,
11444 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11445 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11446 1 : constant);
11447 : }
11448 :
11449 : /************************************************************************/
11450 : /* operator+() */
11451 : /************************************************************************/
11452 :
11453 : /** Add this band with another one.
11454 : *
11455 : * The resulting band is lazy evaluated. A reference is taken on both input
11456 : * datasets.
11457 : *
11458 : * @since 3.12
11459 : * @throw std::runtime_error if both bands do not have the same dimensions.
11460 : */
11461 : GDALComputedRasterBand
11462 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11463 : {
11464 8 : ThrowIfNotSameDimensions(*this, other);
11465 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11466 7 : *this, other);
11467 : }
11468 :
11469 : /************************************************************************/
11470 : /* operator+() */
11471 : /************************************************************************/
11472 :
11473 : /** Add this band with a constant.
11474 : *
11475 : * The resulting band is lazy evaluated. A reference is taken on the input
11476 : * dataset.
11477 : *
11478 : * @since 3.12
11479 : */
11480 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11481 : {
11482 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11483 13 : *this, constant);
11484 : }
11485 :
11486 : /************************************************************************/
11487 : /* operator+() */
11488 : /************************************************************************/
11489 :
11490 : /** Add a band with a constant.
11491 : *
11492 : * The resulting band is lazy evaluated. A reference is taken on the input
11493 : * dataset.
11494 : *
11495 : * @since 3.12
11496 : */
11497 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11498 : {
11499 1 : return other + constant;
11500 : }
11501 :
11502 : /************************************************************************/
11503 : /* operator-() */
11504 : /************************************************************************/
11505 :
11506 : /** Return a band whose value is the opposite value of the band for each
11507 : * pixel.
11508 : *
11509 : * The resulting band is lazy evaluated. A reference is taken on the input
11510 : * dataset.
11511 : *
11512 : * @since 3.12
11513 : */
11514 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
11515 : {
11516 2 : return 0 - *this;
11517 : }
11518 :
11519 : /************************************************************************/
11520 : /* operator-() */
11521 : /************************************************************************/
11522 :
11523 : /** Subtract this band with another one.
11524 : *
11525 : * The resulting band is lazy evaluated. A reference is taken on both input
11526 : * datasets.
11527 : *
11528 : * @since 3.12
11529 : * @throw std::runtime_error if both bands do not have the same dimensions.
11530 : */
11531 : GDALComputedRasterBand
11532 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
11533 : {
11534 2 : ThrowIfNotSameDimensions(*this, other);
11535 : return GDALComputedRasterBand(
11536 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11537 : }
11538 :
11539 : /************************************************************************/
11540 : /* operator-() */
11541 : /************************************************************************/
11542 :
11543 : /** Subtract this band with a constant.
11544 : *
11545 : * The resulting band is lazy evaluated. A reference is taken on the input
11546 : * dataset.
11547 : *
11548 : * @since 3.12
11549 : */
11550 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11551 : {
11552 : return GDALComputedRasterBand(
11553 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11554 : }
11555 :
11556 : /************************************************************************/
11557 : /* operator-() */
11558 : /************************************************************************/
11559 :
11560 : /** Subtract a constant with a band.
11561 : *
11562 : * The resulting band is lazy evaluated. A reference is taken on the input
11563 : * dataset.
11564 : *
11565 : * @since 3.12
11566 : */
11567 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11568 : {
11569 6 : return other * (-1.0) + constant;
11570 : }
11571 :
11572 : /************************************************************************/
11573 : /* operator*() */
11574 : /************************************************************************/
11575 :
11576 : /** Multiply this band with another one.
11577 : *
11578 : * The resulting band is lazy evaluated. A reference is taken on both input
11579 : * datasets.
11580 : *
11581 : * @since 3.12
11582 : * @throw std::runtime_error if both bands do not have the same dimensions.
11583 : */
11584 : GDALComputedRasterBand
11585 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
11586 : {
11587 2 : ThrowIfNotSameDimensions(*this, other);
11588 : return GDALComputedRasterBand(
11589 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11590 : }
11591 :
11592 : /************************************************************************/
11593 : /* operator*() */
11594 : /************************************************************************/
11595 :
11596 : /** Multiply this band by a constant.
11597 : *
11598 : * The resulting band is lazy evaluated. A reference is taken on the input
11599 : * dataset.
11600 : *
11601 : * @since 3.12
11602 : */
11603 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11604 : {
11605 : return GDALComputedRasterBand(
11606 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11607 : }
11608 :
11609 : /************************************************************************/
11610 : /* operator*() */
11611 : /************************************************************************/
11612 :
11613 : /** Multiply a band with a constant.
11614 : *
11615 : * The resulting band is lazy evaluated. A reference is taken on the input
11616 : * dataset.
11617 : *
11618 : * @since 3.12
11619 : */
11620 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
11621 : {
11622 2 : return other * constant;
11623 : }
11624 :
11625 : /************************************************************************/
11626 : /* operator/() */
11627 : /************************************************************************/
11628 :
11629 : /** Divide this band with another one.
11630 : *
11631 : * The resulting band is lazy evaluated. A reference is taken on both input
11632 : * datasets.
11633 : *
11634 : * @since 3.12
11635 : * @throw std::runtime_error if both bands do not have the same dimensions.
11636 : */
11637 : GDALComputedRasterBand
11638 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
11639 : {
11640 2 : ThrowIfNotSameDimensions(*this, other);
11641 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11642 2 : *this, other);
11643 : }
11644 :
11645 : /************************************************************************/
11646 : /* operator/() */
11647 : /************************************************************************/
11648 :
11649 : /** Divide this band by a constant.
11650 : *
11651 : * The resulting band is lazy evaluated. A reference is taken on the input
11652 : * dataset.
11653 : *
11654 : * @since 3.12
11655 : */
11656 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
11657 : {
11658 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11659 0 : *this, constant);
11660 : }
11661 :
11662 : /************************************************************************/
11663 : /* operator/() */
11664 : /************************************************************************/
11665 :
11666 : /** Divide a constant by a band.
11667 : *
11668 : * The resulting band is lazy evaluated. A reference is taken on the input
11669 : * dataset.
11670 : *
11671 : * @since 3.12
11672 : */
11673 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
11674 : {
11675 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11676 1 : constant, other);
11677 : }
11678 :
11679 : /************************************************************************/
11680 : /* ThrowIfNotMuparser() */
11681 : /************************************************************************/
11682 :
11683 : #ifndef HAVE_MUPARSER
11684 : static GDALComputedRasterBand ThrowIfNotMuparser()
11685 : {
11686 : throw std::runtime_error("Operator not available on a "
11687 : "GDAL build without muparser");
11688 : }
11689 : #endif
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 pixel value of the right operand.
11697 : *
11698 : * The resulting band is lazy evaluated. A reference is taken on the input
11699 : * dataset.
11700 : *
11701 : * @since 3.12
11702 : */
11703 : GDALComputedRasterBand
11704 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
11705 : {
11706 : #ifndef HAVE_MUPARSER
11707 : (void)other;
11708 : return ThrowIfNotMuparser();
11709 : #else
11710 3 : ThrowIfNotSameDimensions(*this, other);
11711 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11712 2 : *this, other);
11713 : #endif
11714 : }
11715 :
11716 : /************************************************************************/
11717 : /* operator>() */
11718 : /************************************************************************/
11719 :
11720 : /** Return a band whose value is 1 if the pixel value of the left operand
11721 : * is greater than the constant.
11722 : *
11723 : * The resulting band is lazy evaluated. A reference is taken on the input
11724 : * dataset.
11725 : *
11726 : * @since 3.12
11727 : */
11728 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
11729 : {
11730 : #ifndef HAVE_MUPARSER
11731 : (void)constant;
11732 : return ThrowIfNotMuparser();
11733 : #else
11734 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11735 3 : *this, constant);
11736 : #endif
11737 : }
11738 :
11739 : /************************************************************************/
11740 : /* operator>() */
11741 : /************************************************************************/
11742 :
11743 : /** Return a band whose value is 1 if the constant is greater than the pixel
11744 : * value of the right operand.
11745 : *
11746 : * The resulting band is lazy evaluated. A reference is taken on the input
11747 : * dataset.
11748 : *
11749 : * @since 3.12
11750 : */
11751 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
11752 : {
11753 : #ifndef HAVE_MUPARSER
11754 : (void)constant;
11755 : (void)other;
11756 : return ThrowIfNotMuparser();
11757 : #else
11758 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11759 2 : constant, 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 pixel value of the right operand.
11769 : *
11770 : * The resulting band is lazy evaluated. A reference is taken on the input
11771 : * dataset.
11772 : *
11773 : * @since 3.12
11774 : */
11775 : GDALComputedRasterBand
11776 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
11777 : {
11778 : #ifndef HAVE_MUPARSER
11779 : (void)other;
11780 : return ThrowIfNotMuparser();
11781 : #else
11782 4 : ThrowIfNotSameDimensions(*this, other);
11783 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11784 3 : *this, other);
11785 : #endif
11786 : }
11787 :
11788 : /************************************************************************/
11789 : /* operator>=() */
11790 : /************************************************************************/
11791 :
11792 : /** Return a band whose value is 1 if the pixel value of the left operand
11793 : * is greater or equal to the constant.
11794 : *
11795 : * The resulting band is lazy evaluated. A reference is taken on the input
11796 : * dataset.
11797 : *
11798 : * @since 3.12
11799 : */
11800 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
11801 : {
11802 : #ifndef HAVE_MUPARSER
11803 : (void)constant;
11804 : return ThrowIfNotMuparser();
11805 : #else
11806 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11807 3 : *this, constant);
11808 : #endif
11809 : }
11810 :
11811 : /************************************************************************/
11812 : /* operator>=() */
11813 : /************************************************************************/
11814 :
11815 : /** Return a band whose value is 1 if the constant is greater or equal to
11816 : * the pixel value of the right operand.
11817 : *
11818 : * The resulting band is lazy evaluated. A reference is taken on the input
11819 : * dataset.
11820 : *
11821 : * @since 3.12
11822 : */
11823 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
11824 : {
11825 : #ifndef HAVE_MUPARSER
11826 : (void)constant;
11827 : (void)other;
11828 : return ThrowIfNotMuparser();
11829 : #else
11830 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11831 2 : constant, 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 pixel value of the right operand.
11841 : *
11842 : * The resulting band is lazy evaluated. A reference is taken on the input
11843 : * dataset.
11844 : *
11845 : * @since 3.12
11846 : */
11847 : GDALComputedRasterBand
11848 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
11849 : {
11850 : #ifndef HAVE_MUPARSER
11851 : (void)other;
11852 : return ThrowIfNotMuparser();
11853 : #else
11854 3 : ThrowIfNotSameDimensions(*this, other);
11855 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11856 2 : *this, other);
11857 : #endif
11858 : }
11859 :
11860 : /************************************************************************/
11861 : /* operator<() */
11862 : /************************************************************************/
11863 :
11864 : /** Return a band whose value is 1 if the pixel value of the left operand
11865 : * is lesser than the constant.
11866 : *
11867 : * The resulting band is lazy evaluated. A reference is taken on the input
11868 : * dataset.
11869 : *
11870 : * @since 3.12
11871 : */
11872 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11873 : {
11874 : #ifndef HAVE_MUPARSER
11875 : (void)constant;
11876 : return ThrowIfNotMuparser();
11877 : #else
11878 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11879 3 : *this, constant);
11880 : #endif
11881 : }
11882 :
11883 : /************************************************************************/
11884 : /* operator<() */
11885 : /************************************************************************/
11886 :
11887 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11888 : * value of the right operand.
11889 : *
11890 : * The resulting band is lazy evaluated. A reference is taken on the input
11891 : * dataset.
11892 : *
11893 : * @since 3.12
11894 : */
11895 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11896 : {
11897 : #ifndef HAVE_MUPARSER
11898 : (void)constant;
11899 : (void)other;
11900 : return ThrowIfNotMuparser();
11901 : #else
11902 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11903 2 : constant, 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 pixel value of the right operand.
11913 : *
11914 : * The resulting band is lazy evaluated. A reference is taken on the input
11915 : * dataset.
11916 : *
11917 : * @since 3.12
11918 : */
11919 : GDALComputedRasterBand
11920 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11921 : {
11922 : #ifndef HAVE_MUPARSER
11923 : (void)other;
11924 : return ThrowIfNotMuparser();
11925 : #else
11926 4 : ThrowIfNotSameDimensions(*this, other);
11927 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11928 3 : *this, other);
11929 : #endif
11930 : }
11931 :
11932 : /************************************************************************/
11933 : /* operator<=() */
11934 : /************************************************************************/
11935 :
11936 : /** Return a band whose value is 1 if the pixel value of the left operand
11937 : * is lesser or equal to the constant.
11938 : *
11939 : * The resulting band is lazy evaluated. A reference is taken on the input
11940 : * dataset.
11941 : *
11942 : * @since 3.12
11943 : */
11944 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11945 : {
11946 : #ifndef HAVE_MUPARSER
11947 : (void)constant;
11948 : return ThrowIfNotMuparser();
11949 : #else
11950 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11951 3 : *this, constant);
11952 : #endif
11953 : }
11954 :
11955 : /************************************************************************/
11956 : /* operator<=() */
11957 : /************************************************************************/
11958 :
11959 : /** Return a band whose value is 1 if the constant is lesser or equal to
11960 : * the pixel value of the right operand.
11961 : *
11962 : * The resulting band is lazy evaluated. A reference is taken on the input
11963 : * dataset.
11964 : *
11965 : * @since 3.12
11966 : */
11967 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11968 : {
11969 : #ifndef HAVE_MUPARSER
11970 : (void)constant;
11971 : (void)other;
11972 : return ThrowIfNotMuparser();
11973 : #else
11974 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11975 2 : constant, 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 pixel value of the right operand.
11985 : *
11986 : * The resulting band is lazy evaluated. A reference is taken on the input
11987 : * dataset.
11988 : *
11989 : * @since 3.12
11990 : */
11991 : GDALComputedRasterBand
11992 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11993 : {
11994 : #ifndef HAVE_MUPARSER
11995 : (void)other;
11996 : return ThrowIfNotMuparser();
11997 : #else
11998 3 : ThrowIfNotSameDimensions(*this, other);
11999 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12000 2 : *this, other);
12001 : #endif
12002 : }
12003 :
12004 : /************************************************************************/
12005 : /* operator==() */
12006 : /************************************************************************/
12007 :
12008 : /** Return a band whose value is 1 if the pixel value of the left operand
12009 : * is equal to the constant.
12010 : *
12011 : * The resulting band is lazy evaluated. A reference is taken on the input
12012 : * dataset.
12013 : *
12014 : * @since 3.12
12015 : */
12016 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12017 : {
12018 : #ifndef HAVE_MUPARSER
12019 : (void)constant;
12020 : return ThrowIfNotMuparser();
12021 : #else
12022 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12023 8 : *this, constant);
12024 : #endif
12025 : }
12026 :
12027 : /************************************************************************/
12028 : /* operator==() */
12029 : /************************************************************************/
12030 :
12031 : /** Return a band whose value is 1 if the constant is equal to
12032 : * the pixel value of the right operand.
12033 : *
12034 : * The resulting band is lazy evaluated. A reference is taken on the input
12035 : * dataset.
12036 : *
12037 : * @since 3.12
12038 : */
12039 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12040 : {
12041 : #ifndef HAVE_MUPARSER
12042 : (void)constant;
12043 : (void)other;
12044 : return ThrowIfNotMuparser();
12045 : #else
12046 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12047 2 : constant, 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 pixel value of the right operand.
12057 : *
12058 : * The resulting band is lazy evaluated. A reference is taken on the input
12059 : * dataset.
12060 : *
12061 : * @since 3.12
12062 : */
12063 : GDALComputedRasterBand
12064 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12065 : {
12066 : #ifndef HAVE_MUPARSER
12067 : (void)other;
12068 : return ThrowIfNotMuparser();
12069 : #else
12070 3 : ThrowIfNotSameDimensions(*this, other);
12071 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12072 2 : *this, other);
12073 : #endif
12074 : }
12075 :
12076 : /************************************************************************/
12077 : /* operator!=() */
12078 : /************************************************************************/
12079 :
12080 : /** Return a band whose value is 1 if the pixel value of the left operand
12081 : * is different from the constant.
12082 : *
12083 : * The resulting band is lazy evaluated. A reference is taken on the input
12084 : * dataset.
12085 : *
12086 : * @since 3.12
12087 : */
12088 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12089 : {
12090 : #ifndef HAVE_MUPARSER
12091 : (void)constant;
12092 : return ThrowIfNotMuparser();
12093 : #else
12094 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12095 6 : *this, constant);
12096 : #endif
12097 : }
12098 :
12099 : /************************************************************************/
12100 : /* operator!=() */
12101 : /************************************************************************/
12102 :
12103 : /** Return a band whose value is 1 if the constant is different from
12104 : * the pixel value of the right operand.
12105 : *
12106 : * The resulting band is lazy evaluated. A reference is taken on the input
12107 : * dataset.
12108 : *
12109 : * @since 3.12
12110 : */
12111 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12112 : {
12113 : #ifndef HAVE_MUPARSER
12114 : (void)constant;
12115 : (void)other;
12116 : return ThrowIfNotMuparser();
12117 : #else
12118 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12119 2 : constant, other);
12120 : #endif
12121 : }
12122 :
12123 : #if defined(__GNUC__)
12124 : #pragma GCC diagnostic push
12125 : #pragma GCC diagnostic ignored "-Weffc++"
12126 : #endif
12127 :
12128 : /************************************************************************/
12129 : /* operator&&() */
12130 : /************************************************************************/
12131 :
12132 : /** Return a band whose value is 1 if the pixel value of the left and right
12133 : * operands is true.
12134 : *
12135 : * The resulting band is lazy evaluated. A reference is taken on the input
12136 : * dataset.
12137 : *
12138 : * @since 3.12
12139 : */
12140 : GDALComputedRasterBand
12141 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12142 : {
12143 : #ifndef HAVE_MUPARSER
12144 : (void)other;
12145 : return ThrowIfNotMuparser();
12146 : #else
12147 3 : ThrowIfNotSameDimensions(*this, other);
12148 : return GDALComputedRasterBand(
12149 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12150 : #endif
12151 : }
12152 :
12153 : /************************************************************************/
12154 : /* operator&&() */
12155 : /************************************************************************/
12156 :
12157 : /** Return a band whose value is 1 if the pixel value of the left operand
12158 : * is true, as well as the constant
12159 : *
12160 : * The resulting band is lazy evaluated. A reference is taken on the input
12161 : * dataset.
12162 : *
12163 : * @since 3.12
12164 : */
12165 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12166 : {
12167 : #ifndef HAVE_MUPARSER
12168 : (void)constant;
12169 : return ThrowIfNotMuparser();
12170 : #else
12171 : return GDALComputedRasterBand(
12172 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12173 : #endif
12174 : }
12175 :
12176 : /************************************************************************/
12177 : /* operator&&() */
12178 : /************************************************************************/
12179 :
12180 : /** Return a band whose value is 1 if the constant is true, as well as
12181 : * the pixel value of the right operand.
12182 : *
12183 : * The resulting band is lazy evaluated. A reference is taken on the input
12184 : * dataset.
12185 : *
12186 : * @since 3.12
12187 : */
12188 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12189 : {
12190 : #ifndef HAVE_MUPARSER
12191 : (void)constant;
12192 : (void)other;
12193 : return ThrowIfNotMuparser();
12194 : #else
12195 : return GDALComputedRasterBand(
12196 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, 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 or right
12205 : * operands 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 : GDALComputedRasterBand
12213 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12214 : {
12215 : #ifndef HAVE_MUPARSER
12216 : (void)other;
12217 : return ThrowIfNotMuparser();
12218 : #else
12219 4 : ThrowIfNotSameDimensions(*this, other);
12220 : return GDALComputedRasterBand(
12221 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12222 : #endif
12223 : }
12224 :
12225 : /************************************************************************/
12226 : /* operator||() */
12227 : /************************************************************************/
12228 :
12229 : /** Return a band whose value is 1 if the pixel value of the left operand
12230 : * is true, or if the constant is true
12231 : *
12232 : * The resulting band is lazy evaluated. A reference is taken on the input
12233 : * dataset.
12234 : *
12235 : * @since 3.12
12236 : */
12237 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12238 : {
12239 : #ifndef HAVE_MUPARSER
12240 : (void)constant;
12241 : return ThrowIfNotMuparser();
12242 : #else
12243 : return GDALComputedRasterBand(
12244 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12245 : #endif
12246 : }
12247 :
12248 : /************************************************************************/
12249 : /* operator||() */
12250 : /************************************************************************/
12251 :
12252 : /** Return a band whose value is 1 if the constant is true, or
12253 : * the pixel value of the right operand is true
12254 : *
12255 : * The resulting band is lazy evaluated. A reference is taken on the input
12256 : * dataset.
12257 : *
12258 : * @since 3.12
12259 : */
12260 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12261 : {
12262 : #ifndef HAVE_MUPARSER
12263 : (void)constant;
12264 : (void)other;
12265 : return ThrowIfNotMuparser();
12266 : #else
12267 : return GDALComputedRasterBand(
12268 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12269 : #endif
12270 : }
12271 :
12272 : #if defined(__GNUC__)
12273 : #pragma GCC diagnostic pop
12274 : #endif
12275 :
12276 : /************************************************************************/
12277 : /* operator!() */
12278 : /************************************************************************/
12279 :
12280 : /** Return a band whose value is the logical negation of the pixel value
12281 : *
12282 : * The resulting band is lazy evaluated. A reference is taken on the input
12283 : * dataset.
12284 : *
12285 : * @since 3.12
12286 : */
12287 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12288 : {
12289 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12290 2 : *this, true);
12291 : }
12292 :
12293 : namespace gdal
12294 : {
12295 :
12296 : /************************************************************************/
12297 : /* IfThenElse() */
12298 : /************************************************************************/
12299 :
12300 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12301 : * is not zero, or the one from elseBand otherwise.
12302 : *
12303 : * Variants of this method exits where thenBand and/or elseBand can be double
12304 : * values.
12305 : *
12306 : * The resulting band is lazy evaluated. A reference is taken on the input
12307 : * datasets.
12308 : *
12309 : * This method is the same as the C function GDALRasterBandIfThenElse()
12310 : *
12311 : * @since 3.12
12312 : */
12313 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12314 : const GDALRasterBand &thenBand,
12315 : const GDALRasterBand &elseBand)
12316 : {
12317 : #ifndef HAVE_MUPARSER
12318 : (void)condBand;
12319 : (void)thenBand;
12320 : (void)elseBand;
12321 : return ThrowIfNotMuparser();
12322 : #else
12323 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12324 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12325 : return GDALComputedRasterBand(
12326 : GDALComputedRasterBand::Operation::OP_TERNARY,
12327 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12328 : #endif
12329 : }
12330 :
12331 : //! @cond Doxygen_Suppress
12332 :
12333 : /************************************************************************/
12334 : /* IfThenElse() */
12335 : /************************************************************************/
12336 :
12337 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12338 : * is not zero, or the one from elseBand otherwise.
12339 : *
12340 : * The resulting band is lazy evaluated. A reference is taken on the input
12341 : * datasets.
12342 : *
12343 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12344 : * with thenBand = (condBand * 0) + thenValue
12345 : *
12346 : * @since 3.12
12347 : */
12348 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12349 : double thenValue,
12350 : const GDALRasterBand &elseBand)
12351 : {
12352 : #ifndef HAVE_MUPARSER
12353 : (void)condBand;
12354 : (void)thenValue;
12355 : (void)elseBand;
12356 : return ThrowIfNotMuparser();
12357 : #else
12358 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12359 : auto thenBand =
12360 1 : (condBand * 0)
12361 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12362 1 : thenValue;
12363 : return GDALComputedRasterBand(
12364 : GDALComputedRasterBand::Operation::OP_TERNARY,
12365 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12366 : #endif
12367 : }
12368 :
12369 : /************************************************************************/
12370 : /* IfThenElse() */
12371 : /************************************************************************/
12372 :
12373 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12374 : * is not zero, or the one from elseValue otherwise.
12375 : *
12376 : * The resulting band is lazy evaluated. A reference is taken on the input
12377 : * datasets.
12378 : *
12379 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12380 : * with elseBand = (condBand * 0) + elseValue
12381 :
12382 : * @since 3.12
12383 : */
12384 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12385 : const GDALRasterBand &thenBand,
12386 : double elseValue)
12387 : {
12388 : #ifndef HAVE_MUPARSER
12389 : (void)condBand;
12390 : (void)thenBand;
12391 : (void)elseValue;
12392 : return ThrowIfNotMuparser();
12393 : #else
12394 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12395 : auto elseBand =
12396 1 : (condBand * 0)
12397 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12398 1 : elseValue;
12399 : return GDALComputedRasterBand(
12400 : GDALComputedRasterBand::Operation::OP_TERNARY,
12401 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12402 : #endif
12403 : }
12404 :
12405 : /************************************************************************/
12406 : /* IfThenElse() */
12407 : /************************************************************************/
12408 :
12409 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12410 : * is not zero, or the one from elseValue otherwise.
12411 : *
12412 : * The resulting band is lazy evaluated. A reference is taken on the input
12413 : * datasets.
12414 : *
12415 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12416 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12417 : *
12418 : * @since 3.12
12419 : */
12420 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12421 : double thenValue, double elseValue)
12422 : {
12423 : #ifndef HAVE_MUPARSER
12424 : (void)condBand;
12425 : (void)thenValue;
12426 : (void)elseValue;
12427 : return ThrowIfNotMuparser();
12428 : #else
12429 : auto thenBand =
12430 3 : (condBand * 0)
12431 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12432 6 : thenValue;
12433 : auto elseBand =
12434 3 : (condBand * 0)
12435 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12436 3 : elseValue;
12437 : return GDALComputedRasterBand(
12438 : GDALComputedRasterBand::Operation::OP_TERNARY,
12439 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12440 : #endif
12441 : }
12442 :
12443 : //! @endcond
12444 :
12445 : } // namespace gdal
12446 :
12447 : /************************************************************************/
12448 : /* GDALRasterBandIfThenElse() */
12449 : /************************************************************************/
12450 :
12451 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12452 : * is not zero, or the one from hElseBand otherwise.
12453 : *
12454 : * The resulting band is lazy evaluated. A reference is taken on the input
12455 : * datasets.
12456 : *
12457 : * This function is the same as the C++ method gdal::IfThenElse()
12458 : *
12459 : * @since 3.12
12460 : */
12461 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12462 : GDALRasterBandH hThenBand,
12463 : GDALRasterBandH hElseBand)
12464 : {
12465 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12466 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12467 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12468 : #ifndef HAVE_MUPARSER
12469 : CPLError(CE_Failure, CPLE_NotSupported,
12470 : "Band comparison operators not available on a GDAL build without "
12471 : "muparser");
12472 : return nullptr;
12473 : #else
12474 :
12475 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12476 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12477 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12478 : try
12479 : {
12480 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12481 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12482 : }
12483 2 : catch (const std::exception &e)
12484 : {
12485 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12486 2 : return nullptr;
12487 : }
12488 : return new GDALComputedRasterBand(
12489 : GDALComputedRasterBand::Operation::OP_TERNARY,
12490 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12491 : #endif
12492 : }
12493 :
12494 : /************************************************************************/
12495 : /* GDALRasterBand::AsType() */
12496 : /************************************************************************/
12497 :
12498 : /** Cast this band to another type.
12499 : *
12500 : * The resulting band is lazy evaluated. A reference is taken on the input
12501 : * dataset.
12502 : *
12503 : * This method is the same as the C function GDALRasterBandAsDataType()
12504 : *
12505 : * @since 3.12
12506 : */
12507 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12508 : {
12509 10 : if (dt == GDT_Unknown)
12510 : {
12511 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12512 : }
12513 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12514 9 : *this, dt);
12515 : }
12516 :
12517 : /************************************************************************/
12518 : /* GDALRasterBandAsDataType() */
12519 : /************************************************************************/
12520 :
12521 : /** Cast this band to another type.
12522 : *
12523 : * The resulting band is lazy evaluated. A reference is taken on the input
12524 : * dataset.
12525 : *
12526 : * This function is the same as the C++ method GDALRasterBand::AsType()
12527 : *
12528 : * @since 3.12
12529 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12530 : */
12531 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12532 : GDALDataType eDT)
12533 : {
12534 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
12535 16 : if (eDT == GDT_Unknown)
12536 : {
12537 1 : CPLError(CE_Failure, CPLE_NotSupported,
12538 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12539 1 : return nullptr;
12540 : }
12541 : return new GDALComputedRasterBand(
12542 : GDALComputedRasterBand::Operation::OP_CAST,
12543 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
12544 : }
12545 :
12546 : /************************************************************************/
12547 : /* GetBandVector() */
12548 : /************************************************************************/
12549 :
12550 : static std::vector<const GDALRasterBand *>
12551 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12552 : {
12553 10 : std::vector<const GDALRasterBand *> bands;
12554 27 : for (size_t i = 0; i < nBandCount; ++i)
12555 : {
12556 20 : if (i > 0)
12557 : {
12558 10 : GDALRasterBand::ThrowIfNotSameDimensions(
12559 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
12560 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
12561 : }
12562 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12563 : }
12564 7 : return bands;
12565 : }
12566 :
12567 : /************************************************************************/
12568 : /* GDALOperationOnNBands() */
12569 : /************************************************************************/
12570 :
12571 : static GDALComputedRasterBandH
12572 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12573 : GDALRasterBandH *pahBands)
12574 : {
12575 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
12576 11 : if (nBandCount == 0)
12577 : {
12578 1 : CPLError(CE_Failure, CPLE_AppDefined,
12579 : "At least one band should be passed");
12580 1 : return nullptr;
12581 : }
12582 :
12583 20 : std::vector<const GDALRasterBand *> bands;
12584 : try
12585 : {
12586 10 : bands = GetBandVector(nBandCount, pahBands);
12587 : }
12588 3 : catch (const std::exception &e)
12589 : {
12590 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12591 3 : return nullptr;
12592 : }
12593 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12594 : }
12595 :
12596 : /************************************************************************/
12597 : /* GDALMaximumOfNBands() */
12598 : /************************************************************************/
12599 :
12600 : /** Return a band whose each pixel value is the maximum of the corresponding
12601 : * pixel values in the input bands.
12602 : *
12603 : * The resulting band is lazy evaluated. A reference is taken on input
12604 : * datasets.
12605 : *
12606 : * This function is the same as the C ++ method gdal::max()
12607 : *
12608 : * @since 3.12
12609 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12610 : */
12611 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12612 : GDALRasterBandH *pahBands)
12613 : {
12614 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12615 4 : nBandCount, pahBands);
12616 : }
12617 :
12618 : /************************************************************************/
12619 : /* gdal::max() */
12620 : /************************************************************************/
12621 :
12622 : namespace gdal
12623 : {
12624 : /** Return a band whose each pixel value is the maximum of the corresponding
12625 : * pixel values in the inputs (bands or constants)
12626 : *
12627 : * The resulting band is lazy evaluated. A reference is taken on input
12628 : * datasets.
12629 : *
12630 : * Two or more bands can be passed.
12631 : *
12632 : * This method is the same as the C function GDALMaximumOfNBands()
12633 : *
12634 : * @since 3.12
12635 : * @throw std::runtime_error if bands do not have the same dimensions.
12636 : */
12637 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
12638 : const GDALRasterBand &second)
12639 : {
12640 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12641 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
12642 1 : first, second);
12643 : }
12644 : } // namespace gdal
12645 :
12646 : /************************************************************************/
12647 : /* GDALRasterBandMaxConstant() */
12648 : /************************************************************************/
12649 :
12650 : /** Return a band whose each pixel value is the maximum of the corresponding
12651 : * pixel values in the input band and the constant.
12652 : *
12653 : * The resulting band is lazy evaluated. A reference is taken on the input
12654 : * dataset.
12655 : *
12656 : * This function is the same as the C ++ method gdal::max()
12657 : *
12658 : * @since 3.12
12659 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12660 : */
12661 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
12662 : double dfConstant)
12663 : {
12664 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12665 : GDALComputedRasterBand::Operation::OP_MAX,
12666 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12667 6 : dfConstant));
12668 : }
12669 :
12670 : /************************************************************************/
12671 : /* GDALMinimumOfNBands() */
12672 : /************************************************************************/
12673 :
12674 : /** Return a band whose each pixel value is the minimum of the corresponding
12675 : * pixel values in the input bands.
12676 : *
12677 : * The resulting band is lazy evaluated. A reference is taken on input
12678 : * datasets.
12679 : *
12680 : * This function is the same as the C ++ method gdal::min()
12681 : *
12682 : * @since 3.12
12683 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12684 : */
12685 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
12686 : GDALRasterBandH *pahBands)
12687 : {
12688 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
12689 4 : nBandCount, pahBands);
12690 : }
12691 :
12692 : /************************************************************************/
12693 : /* gdal::min() */
12694 : /************************************************************************/
12695 :
12696 : namespace gdal
12697 : {
12698 : /** Return a band whose each pixel value is the minimum of the corresponding
12699 : * pixel values in the inputs (bands or constants)
12700 : *
12701 : * The resulting band is lazy evaluated. A reference is taken on input
12702 : * datasets.
12703 : *
12704 : * Two or more bands can be passed.
12705 : *
12706 : * This method is the same as the C function GDALMinimumOfNBands()
12707 : *
12708 : * @since 3.12
12709 : * @throw std::runtime_error if bands do not have the same dimensions.
12710 : */
12711 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
12712 : const GDALRasterBand &second)
12713 : {
12714 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12715 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
12716 0 : first, second);
12717 : }
12718 : } // namespace gdal
12719 :
12720 : /************************************************************************/
12721 : /* GDALRasterBandMinConstant() */
12722 : /************************************************************************/
12723 :
12724 : /** Return a band whose each pixel value is the minimum of the corresponding
12725 : * pixel values in the input band and the constant.
12726 : *
12727 : * The resulting band is lazy evaluated. A reference is taken on the input
12728 : * dataset.
12729 : *
12730 : * This function is the same as the C ++ method gdal::min()
12731 : *
12732 : * @since 3.12
12733 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12734 : */
12735 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
12736 : double dfConstant)
12737 : {
12738 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12739 : GDALComputedRasterBand::Operation::OP_MIN,
12740 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12741 6 : dfConstant));
12742 : }
12743 :
12744 : /************************************************************************/
12745 : /* GDALMeanOfNBands() */
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 : * This function is the same as the C ++ method gdal::mean()
12755 : *
12756 : * @since 3.12
12757 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12758 : */
12759 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
12760 : GDALRasterBandH *pahBands)
12761 : {
12762 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
12763 3 : nBandCount, pahBands);
12764 : }
12765 :
12766 : /************************************************************************/
12767 : /* gdal::mean() */
12768 : /************************************************************************/
12769 :
12770 : namespace gdal
12771 : {
12772 :
12773 : /** Return a band whose each pixel value is the arithmetic mean of the
12774 : * corresponding pixel values in the input bands.
12775 : *
12776 : * The resulting band is lazy evaluated. A reference is taken on input
12777 : * datasets.
12778 : *
12779 : * Two or more bands can be passed.
12780 : *
12781 : * This method is the same as the C function GDALMeanOfNBands()
12782 : *
12783 : * @since 3.12
12784 : * @throw std::runtime_error if bands do not have the same dimensions.
12785 : */
12786 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
12787 : const GDALRasterBand &second)
12788 : {
12789 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12790 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
12791 0 : first, second);
12792 : }
12793 : } // namespace gdal
12794 :
12795 : /************************************************************************/
12796 : /* gdal::abs() */
12797 : /************************************************************************/
12798 :
12799 : namespace gdal
12800 : {
12801 :
12802 : /** Return a band whose each pixel value is the absolute value (or module
12803 : * for complex data type) of the corresponding pixel value in the input band.
12804 : *
12805 : * The resulting band is lazy evaluated. A reference is taken on input
12806 : * datasets.
12807 : *
12808 : * @since 3.12
12809 : */
12810 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
12811 : {
12812 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12813 1 : band);
12814 : }
12815 : } // namespace gdal
12816 :
12817 : /************************************************************************/
12818 : /* gdal::fabs() */
12819 : /************************************************************************/
12820 :
12821 : namespace gdal
12822 : {
12823 :
12824 : /** Return a band whose each pixel value is the absolute value (or module
12825 : * for complex data type) of the corresponding pixel value in the input band.
12826 : *
12827 : * The resulting band is lazy evaluated. A reference is taken on input
12828 : * datasets.
12829 : *
12830 : * @since 3.12
12831 : */
12832 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
12833 : {
12834 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12835 1 : band);
12836 : }
12837 : } // namespace gdal
12838 :
12839 : /************************************************************************/
12840 : /* gdal::sqrt() */
12841 : /************************************************************************/
12842 :
12843 : namespace gdal
12844 : {
12845 :
12846 : /** Return a band whose each pixel value is the square root of the
12847 : * corresponding pixel value in the input band.
12848 : *
12849 : * The resulting band is lazy evaluated. A reference is taken on input
12850 : * datasets.
12851 : *
12852 : * @since 3.12
12853 : */
12854 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12855 : {
12856 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12857 1 : band);
12858 : }
12859 : } // namespace gdal
12860 :
12861 : /************************************************************************/
12862 : /* gdal::log() */
12863 : /************************************************************************/
12864 :
12865 : namespace gdal
12866 : {
12867 :
12868 : /** Return a band whose each pixel value is the natural logarithm of the
12869 : * corresponding pixel value in the input band.
12870 : *
12871 : * The resulting band is lazy evaluated. A reference is taken on input
12872 : * datasets.
12873 : *
12874 : * @since 3.12
12875 : */
12876 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12877 : {
12878 : #ifndef HAVE_MUPARSER
12879 : (void)band;
12880 : return ThrowIfNotMuparser();
12881 : #else
12882 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12883 1 : band);
12884 : #endif
12885 : }
12886 : } // namespace gdal
12887 :
12888 : /************************************************************************/
12889 : /* gdal::log10() */
12890 : /************************************************************************/
12891 :
12892 : namespace gdal
12893 : {
12894 :
12895 : /** Return a band whose each pixel value is the logarithm base 10 of the
12896 : * corresponding pixel value in the input band.
12897 : *
12898 : * The resulting band is lazy evaluated. A reference is taken on input
12899 : * datasets.
12900 : *
12901 : * @since 3.12
12902 : */
12903 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12904 : {
12905 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12906 1 : band);
12907 : }
12908 : } // namespace gdal
12909 :
12910 : /************************************************************************/
12911 : /* gdal::pow() */
12912 : /************************************************************************/
12913 :
12914 : namespace gdal
12915 : {
12916 :
12917 : #ifndef DOXYGEN_SKIP
12918 : /** Return a band whose each pixel value is the constant raised to the power of
12919 : * the corresponding pixel value in the input band.
12920 : *
12921 : * The resulting band is lazy evaluated. A reference is taken on input
12922 : * datasets.
12923 : *
12924 : * @since 3.12
12925 : */
12926 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12927 : {
12928 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12929 1 : constant, band);
12930 : }
12931 : #endif
12932 :
12933 : } // namespace gdal
12934 :
12935 : /************************************************************************/
12936 : /* gdal::pow() */
12937 : /************************************************************************/
12938 :
12939 : namespace gdal
12940 : {
12941 :
12942 : /** Return a band whose each pixel value is the the corresponding pixel value
12943 : * in the input band raised to the power of the constant.
12944 : *
12945 : * The resulting band is lazy evaluated. A reference is taken on input
12946 : * datasets.
12947 : *
12948 : * @since 3.12
12949 : */
12950 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12951 : {
12952 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12953 1 : band, constant);
12954 : }
12955 : } // namespace gdal
12956 :
12957 : /************************************************************************/
12958 : /* gdal::pow() */
12959 : /************************************************************************/
12960 :
12961 : namespace gdal
12962 : {
12963 :
12964 : #ifndef DOXYGEN_SKIP
12965 : /** Return a band whose each pixel value is the the corresponding pixel value
12966 : * in the input band1 raised to the power of the corresponding pixel value
12967 : * in the input band2
12968 : *
12969 : * The resulting band is lazy evaluated. A reference is taken on input
12970 : * datasets.
12971 : *
12972 : * @since 3.12
12973 : * @throw std::runtime_error if bands do not have the same dimensions.
12974 : */
12975 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12976 : const GDALRasterBand &band2)
12977 : {
12978 : #ifndef HAVE_MUPARSER
12979 : (void)band1;
12980 : (void)band2;
12981 : return ThrowIfNotMuparser();
12982 : #else
12983 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12984 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12985 1 : band1, band2);
12986 : #endif
12987 : }
12988 : #endif
12989 : } // namespace gdal
|