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 1572430 : GDALRasterBand::GDALRasterBand()
60 : : GDALRasterBand(
61 1572430 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
62 : {
63 1571800 : }
64 :
65 : /** Constructor. Applications should never create GDALRasterBands directly.
66 : * @param bForceCachedIOIn Whether cached IO should be forced.
67 : */
68 1850070 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
69 1850070 : : bForceCachedIO(bForceCachedIOIn)
70 :
71 : {
72 1849380 : }
73 :
74 : /************************************************************************/
75 : /* ~GDALRasterBand() */
76 : /************************************************************************/
77 :
78 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
79 : instead destroy the GDALDataset. */
80 :
81 1850060 : GDALRasterBand::~GDALRasterBand()
82 :
83 : {
84 1850070 : if (poDS && poDS->IsMarkedSuppressOnClose())
85 : {
86 501 : if (poBandBlockCache)
87 438 : poBandBlockCache->DisableDirtyBlockWriting();
88 : }
89 1850070 : GDALRasterBand::FlushCache(true);
90 :
91 1850070 : delete poBandBlockCache;
92 :
93 1850070 : if (static_cast<GIntBig>(nBlockReads) >
94 1850070 : 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 1850070 : InvalidateMaskBand();
104 1850060 : nBand = -nBand;
105 :
106 1850060 : delete m_poPointsCache;
107 1850070 : }
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 4405040 : 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 4405040 : if (psExtraArg == nullptr)
340 : {
341 3805440 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
342 3805440 : psExtraArg = &sExtraArg;
343 : }
344 599598 : 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 4405040 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
353 : nBufYSize);
354 :
355 4389350 : 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 4389350 : 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 4389340 : if (eRWFlag == GF_Write)
379 : {
380 365887 : 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 365887 : 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 4389320 : if (nPixelSpace == 0)
400 : {
401 3964080 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
402 : }
403 :
404 4391110 : if (nLineSpace == 0)
405 : {
406 3947120 : nLineSpace = nPixelSpace * nBufXSize;
407 : }
408 :
409 : /* -------------------------------------------------------------------- */
410 : /* Do some validation of parameters. */
411 : /* -------------------------------------------------------------------- */
412 4391110 : 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 4391090 : 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 4391090 : 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 4391090 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
439 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
440 4367970 : nLineSpace, psExtraArg);
441 : }
442 :
443 : /************************************************************************/
444 : /* RasterIOInternal() */
445 : /************************************************************************/
446 :
447 4362420 : 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 4362420 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
457 :
458 : CPLErr eErr;
459 4332290 : 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 4376240 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
466 4332270 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
467 :
468 4376270 : if (bCallLeaveReadWrite)
469 600976 : LeaveReadWrite();
470 :
471 4349560 : 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 3382220 : 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 3382220 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
495 :
496 3382220 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
497 :
498 3379850 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
499 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
500 3320080 : 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 40528 : 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 40528 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
522 :
523 40528 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
524 :
525 40528 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
526 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
527 40526 : nLineSpace, psExtraArg));
528 : }
529 :
530 : /************************************************************************/
531 : /* GetGDTFromCppType() */
532 : /************************************************************************/
533 :
534 : namespace
535 : {
536 : template <class T> struct GetGDTFromCppType;
537 :
538 : #define DEFINE_GetGDTFromCppType(T, eDT) \
539 : template <> struct GetGDTFromCppType<T> \
540 : { \
541 : static constexpr GDALDataType GDT = eDT; \
542 : }
543 :
544 : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
545 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
546 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
547 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
548 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
549 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
550 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
551 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
552 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
553 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
554 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
555 : // Not allowed by C++ standard
556 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
557 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
558 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
559 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
560 : } // namespace
561 :
562 : /************************************************************************/
563 : /* ReadRaster() */
564 : /************************************************************************/
565 :
566 : // clang-format off
567 : /** Read a region of image data for this band.
568 : *
569 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
570 : * for common use cases, like reading a whole band.
571 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
572 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
573 : * float, double, std::complex<float|double>.
574 : *
575 : * When possible prefer the ReadRaster(std::vector<T>& vData, double dfXOff, double dfYOff, double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, void *pProgressData) const variant that takes a std::vector<T>&,
576 : * and can allocate memory automatically.
577 : *
578 : * To read a whole band (assuming it fits into memory), as an array of double:
579 : *
580 : \code{.cpp}
581 : double* myArray = static_cast<double*>(
582 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
583 : // TODO: check here that myArray != nullptr
584 : const size_t nArrayEltCount =
585 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
586 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
587 : {
588 : // do something
589 : }
590 : VSIFree(myArray)
591 : \endcode
592 : *
593 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
594 : *
595 : \code{.cpp}
596 : double* myArray = static_cast<double*>(
597 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
598 : // TODO: check here that myArray != nullptr
599 : const size_t nArrayEltCount = 128 * 128;
600 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
601 : {
602 : // do something
603 : }
604 : VSIFree(myArray)
605 : \endcode
606 : *
607 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
608 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
609 : * instance of this dataset) concurrently from several threads.
610 : *
611 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
612 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
613 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
614 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
615 : * Or use nLineSpace and a possibly shifted pData value.
616 : *
617 : * @param[out] pData The buffer into which the data should be written.
618 : * This buffer must contain at least nBufXSize *
619 : * nBufYSize words of type T. It is organized in left to right,
620 : * top to bottom pixel order, and fully packed.
621 : * The type of the buffer does not need to be the one of GetDataType(). The
622 : * method will perform data type translation (with potential rounding, clamping)
623 : * if needed.
624 : *
625 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
626 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
627 : * return in error if it is not. If set to zero, then pData is trusted to be
628 : * large enough.
629 : *
630 : * @param dfXOff The pixel offset to the top left corner of the region
631 : * of the band to be accessed. This would be zero to start from the left side.
632 : * Defaults to 0.
633 : *
634 : * @param dfYOff The line offset to the top left corner of the region
635 : * of the band to be accessed. This would be zero to start from the top.
636 : * Defaults to 0.
637 : *
638 : * @param dfXSize The width of the region of the band to be accessed in pixels.
639 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
640 : * dfXSize is set to the band width.
641 : *
642 : * @param dfYSize The height of the region of the band to be accessed in lines.
643 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
644 : * dfYSize is set to the band height.
645 : *
646 : * @param nBufXSize the width of the buffer image into which the desired region
647 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
648 : * then nBufXSize is initialized with dfXSize.
649 : *
650 : * @param nBufYSize the height of the buffer image into which the desired region
651 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
652 : * then nBufYSize is initialized with dfYSize.
653 : *
654 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
655 : *
656 : * @param pfnProgress Progress function. May be nullptr.
657 : *
658 : * @param pProgressData User data of pfnProgress. May be nullptr.
659 : *
660 : * @return CE_Failure if the access fails, otherwise CE_None.
661 : *
662 : * @see GDALRasterBand::RasterIO()
663 : * @since GDAL 3.10
664 : */
665 : // clang-format on
666 :
667 : template <class T>
668 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
669 : double dfXOff, double dfYOff, double dfXSize,
670 : double dfYSize, size_t nBufXSize,
671 : size_t nBufYSize,
672 : GDALRIOResampleAlg eResampleAlg,
673 : GDALProgressFunc pfnProgress,
674 : void *pProgressData) const
675 : {
676 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
677 : {
678 2 : return CE_Failure;
679 : }
680 :
681 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
682 : {
683 16 : dfXSize = nRasterXSize;
684 16 : dfYSize = nRasterYSize;
685 : }
686 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
687 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
688 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
689 2 : dfYOff + dfYSize > INT_MAX)
690 : {
691 0 : return CE_Failure;
692 : }
693 :
694 : GDALRasterIOExtraArg sExtraArg;
695 18 : sExtraArg.nVersion = 1;
696 18 : sExtraArg.eResampleAlg = eResampleAlg;
697 18 : sExtraArg.pfnProgress = pfnProgress;
698 18 : sExtraArg.pProgressData = pProgressData;
699 18 : sExtraArg.bFloatingPointWindowValidity = true;
700 18 : sExtraArg.dfXOff = dfXOff;
701 18 : sExtraArg.dfYOff = dfYOff;
702 18 : sExtraArg.dfXSize = dfXSize;
703 18 : sExtraArg.dfYSize = dfYSize;
704 18 : const int nXOff = static_cast<int>(dfXOff);
705 18 : const int nYOff = static_cast<int>(dfYOff);
706 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
707 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
708 18 : if (nBufXSize == 0 && nBufYSize == 0)
709 : {
710 17 : if (static_cast<int>(dfXSize) == dfXSize &&
711 17 : static_cast<int>(dfYSize) == dfYSize)
712 : {
713 17 : nBufXSize = static_cast<int>(dfXSize);
714 17 : nBufYSize = static_cast<int>(dfYSize);
715 : }
716 : else
717 : {
718 0 : CPLError(CE_Failure, CPLE_AppDefined,
719 : "nBufXSize and nBufYSize must be provided if dfXSize or "
720 : "dfYSize is not an integer value");
721 0 : return CE_Failure;
722 : }
723 : }
724 18 : if (nBufXSize == 0 || nBufYSize == 0)
725 : {
726 0 : CPLDebug("GDAL",
727 : "RasterIO() skipped for odd window or buffer size.\n"
728 : " Window = (%d,%d)x%dx%d\n"
729 : " Buffer = %dx%d\n",
730 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
731 : static_cast<int>(nBufYSize));
732 :
733 0 : return CE_None;
734 : }
735 :
736 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
737 : {
738 1 : CPLError(CE_Failure, CPLE_AppDefined,
739 : "Provided array is not large enough");
740 1 : return CE_Failure;
741 : }
742 :
743 17 : constexpr GSpacing nPixelSpace = sizeof(T);
744 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
745 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
746 :
747 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
748 :
749 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
750 : static_cast<int>(nBufXSize),
751 : static_cast<int>(nBufYSize), eBufType,
752 17 : nPixelSpace, nLineSpace, &sExtraArg);
753 : }
754 :
755 : //! @cond Doxygen_Suppress
756 :
757 : #define INSTANTIATE_READ_RASTER(T) \
758 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
759 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
760 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
761 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
762 : void *pProgressData) const;
763 :
764 : INSTANTIATE_READ_RASTER(uint8_t)
765 : INSTANTIATE_READ_RASTER(int8_t)
766 : INSTANTIATE_READ_RASTER(uint16_t)
767 : INSTANTIATE_READ_RASTER(int16_t)
768 : INSTANTIATE_READ_RASTER(uint32_t)
769 : INSTANTIATE_READ_RASTER(int32_t)
770 : INSTANTIATE_READ_RASTER(uint64_t)
771 : INSTANTIATE_READ_RASTER(int64_t)
772 : INSTANTIATE_READ_RASTER(GFloat16)
773 : INSTANTIATE_READ_RASTER(float)
774 : INSTANTIATE_READ_RASTER(double)
775 : // Not allowed by C++ standard
776 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
777 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
778 : INSTANTIATE_READ_RASTER(std::complex<float>)
779 : INSTANTIATE_READ_RASTER(std::complex<double>)
780 :
781 : //! @endcond
782 :
783 : /************************************************************************/
784 : /* ReadRaster() */
785 : /************************************************************************/
786 :
787 : /** Read a region of image data for this band.
788 : *
789 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
790 : * for common use cases, like reading a whole band.
791 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
792 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
793 : * float, double, std::complex<float|double>.
794 : *
795 : * To read a whole band (assuming it fits into memory), as a vector of double:
796 : *
797 : \code
798 : std::vector<double> myArray;
799 : if (poBand->ReadRaster(myArray) == CE_None)
800 : {
801 : // do something
802 : }
803 : \endcode
804 : *
805 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
806 : *
807 : \code{.cpp}
808 : std::vector<double> myArray;
809 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
810 : {
811 : // do something
812 : }
813 : \endcode
814 : *
815 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
816 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
817 : * instance of this dataset) concurrently from several threads.
818 : *
819 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
820 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
821 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
822 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
823 : * Or use nLineSpace and a possibly shifted pData value.
824 : *
825 : * @param[out] vData The vector into which the data should be written.
826 : * The vector will be resized, if needed, to contain at least nBufXSize *
827 : * nBufYSize values. The values in the vector are organized in left to right,
828 : * top to bottom pixel order, and fully packed.
829 : * The type of the vector does not need to be the one of GetDataType(). The
830 : * method will perform data type translation (with potential rounding, clamping)
831 : * if needed.
832 : *
833 : * @param dfXOff The pixel offset to the top left corner of the region
834 : * of the band to be accessed. This would be zero to start from the left side.
835 : * Defaults to 0.
836 : *
837 : * @param dfYOff The line offset to the top left corner of the region
838 : * of the band to be accessed. This would be zero to start from the top.
839 : * Defaults to 0.
840 : *
841 : * @param dfXSize The width of the region of the band to be accessed in pixels.
842 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
843 : * dfXSize is set to the band width.
844 : *
845 : * @param dfYSize The height of the region of the band to be accessed in lines.
846 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
847 : * dfYSize is set to the band height.
848 : *
849 : * @param nBufXSize the width of the buffer image into which the desired region
850 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
851 : * then nBufXSize is initialized with dfXSize.
852 : *
853 : * @param nBufYSize the height of the buffer image into which the desired region
854 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
855 : * then nBufYSize is initialized with dfYSize.
856 : *
857 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
858 : *
859 : * @param pfnProgress Progress function. May be nullptr.
860 : *
861 : * @param pProgressData User data of pfnProgress. May be nullptr.
862 : *
863 : * @return CE_Failure if the access fails, otherwise CE_None.
864 : *
865 : * @see GDALRasterBand::RasterIO()
866 : * @since GDAL 3.10
867 : */
868 : template <class T>
869 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
870 : double dfYOff, double dfXSize, double dfYSize,
871 : size_t nBufXSize, size_t nBufYSize,
872 : GDALRIOResampleAlg eResampleAlg,
873 : GDALProgressFunc pfnProgress,
874 : void *pProgressData) const
875 : {
876 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
877 : {
878 2 : return CE_Failure;
879 : }
880 :
881 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
882 : {
883 13 : dfXSize = nRasterXSize;
884 13 : dfYSize = nRasterYSize;
885 : }
886 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
887 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
888 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
889 7 : dfYOff + dfYSize > INT_MAX)
890 : {
891 0 : return CE_Failure;
892 : }
893 :
894 : GDALRasterIOExtraArg sExtraArg;
895 20 : sExtraArg.nVersion = 1;
896 20 : sExtraArg.eResampleAlg = eResampleAlg;
897 20 : sExtraArg.pfnProgress = pfnProgress;
898 20 : sExtraArg.pProgressData = pProgressData;
899 20 : sExtraArg.bFloatingPointWindowValidity = true;
900 20 : sExtraArg.dfXOff = dfXOff;
901 20 : sExtraArg.dfYOff = dfYOff;
902 20 : sExtraArg.dfXSize = dfXSize;
903 20 : sExtraArg.dfYSize = dfYSize;
904 20 : const int nXOff = static_cast<int>(dfXOff);
905 20 : const int nYOff = static_cast<int>(dfYOff);
906 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
907 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
908 20 : if (nBufXSize == 0 && nBufYSize == 0)
909 : {
910 16 : if (static_cast<int>(dfXSize) == dfXSize &&
911 15 : static_cast<int>(dfYSize) == dfYSize)
912 : {
913 15 : nBufXSize = static_cast<int>(dfXSize);
914 15 : nBufYSize = static_cast<int>(dfYSize);
915 : }
916 : else
917 : {
918 1 : CPLError(CE_Failure, CPLE_AppDefined,
919 : "nBufXSize and nBufYSize must be provided if "
920 : "dfXSize or dfYSize is not an integer value");
921 1 : return CE_Failure;
922 : }
923 : }
924 19 : if (nBufXSize == 0 || nBufYSize == 0)
925 : {
926 0 : CPLDebug("GDAL",
927 : "RasterIO() skipped for odd window or buffer size.\n"
928 : " Window = (%d,%d)x%dx%d\n"
929 : " Buffer = %dx%d\n",
930 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
931 : static_cast<int>(nBufYSize));
932 :
933 0 : return CE_None;
934 : }
935 :
936 : if constexpr (SIZEOF_VOIDP < 8)
937 : {
938 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
939 : {
940 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
941 : return CE_Failure;
942 : }
943 : }
944 :
945 19 : if (vData.size() < nBufXSize * nBufYSize)
946 : {
947 : try
948 : {
949 17 : vData.resize(nBufXSize * nBufYSize);
950 : }
951 1 : catch (const std::exception &)
952 : {
953 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
954 1 : return CE_Failure;
955 : }
956 : }
957 :
958 18 : constexpr GSpacing nPixelSpace = sizeof(T);
959 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
960 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
961 :
962 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
963 :
964 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
965 : vData.data(), static_cast<int>(nBufXSize),
966 : static_cast<int>(nBufYSize), eBufType,
967 18 : nPixelSpace, nLineSpace, &sExtraArg);
968 : }
969 :
970 : //! @cond Doxygen_Suppress
971 :
972 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
973 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
974 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
975 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
976 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
977 : void *pProgressData) const;
978 :
979 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
981 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
982 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
983 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
984 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
985 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
986 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
987 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
988 : INSTANTIATE_READ_RASTER_VECTOR(float)
989 : INSTANTIATE_READ_RASTER_VECTOR(double)
990 : // Not allowed by C++ standard
991 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
992 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
993 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
994 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
995 :
996 : //! @endcond
997 :
998 : /************************************************************************/
999 : /* ReadBlock() */
1000 : /************************************************************************/
1001 :
1002 : /**
1003 : * \brief Read a block of image data efficiently.
1004 : *
1005 : * This method accesses a "natural" block from the raster band without
1006 : * resampling, or data type conversion. For a more generalized, but
1007 : * potentially less efficient access use RasterIO().
1008 : *
1009 : * This method is the same as the C GDALReadBlock() function.
1010 : *
1011 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1012 : * block oriented data without an extra copy into an application buffer.
1013 : *
1014 : * The following code would efficiently compute a histogram of eight bit
1015 : * raster data. Note that the final block may be partial ... data beyond
1016 : * the edge of the underlying raster band in these edge blocks is of an
1017 : * undetermined value.
1018 : *
1019 : \code{.cpp}
1020 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1021 :
1022 : {
1023 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1024 :
1025 : CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
1026 :
1027 : int nXBlockSize, nYBlockSize;
1028 :
1029 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1030 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1031 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1032 :
1033 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1034 :
1035 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1036 : {
1037 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1038 : {
1039 : int nXValid, nYValid;
1040 :
1041 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1042 :
1043 : // Compute the portion of the block that is valid
1044 : // for partial edge blocks.
1045 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1046 :
1047 : // Collect the histogram counts.
1048 : for( int iY = 0; iY < nYValid; iY++ )
1049 : {
1050 : for( int iX = 0; iX < nXValid; iX++ )
1051 : {
1052 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1053 : }
1054 : }
1055 : }
1056 : }
1057 : }
1058 : \endcode
1059 : *
1060 : * @param nXBlockOff the horizontal block offset, with zero indicating
1061 : * the left most block, 1 the next block and so forth.
1062 : *
1063 : * @param nYBlockOff the vertical block offset, with zero indicating
1064 : * the top most block, 1 the next block and so forth.
1065 : *
1066 : * @param pImage the buffer into which the data will be read. The buffer
1067 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1068 : * of type GetRasterDataType().
1069 : *
1070 : * @return CE_None on success or CE_Failure on an error.
1071 : */
1072 :
1073 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1074 :
1075 : {
1076 : /* -------------------------------------------------------------------- */
1077 : /* Validate arguments. */
1078 : /* -------------------------------------------------------------------- */
1079 894 : CPLAssert(pImage != nullptr);
1080 :
1081 894 : if (!InitBlockInfo())
1082 0 : return CE_Failure;
1083 :
1084 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1085 : {
1086 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1087 : "Illegal nXBlockOff value (%d) in "
1088 : "GDALRasterBand::ReadBlock()\n",
1089 : nXBlockOff);
1090 :
1091 0 : return (CE_Failure);
1092 : }
1093 :
1094 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1095 : {
1096 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1097 : "Illegal nYBlockOff value (%d) in "
1098 : "GDALRasterBand::ReadBlock()\n",
1099 : nYBlockOff);
1100 :
1101 0 : return (CE_Failure);
1102 : }
1103 :
1104 : /* -------------------------------------------------------------------- */
1105 : /* Invoke underlying implementation method. */
1106 : /* -------------------------------------------------------------------- */
1107 :
1108 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1109 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1110 894 : if (bCallLeaveReadWrite)
1111 4 : LeaveReadWrite();
1112 894 : return eErr;
1113 : }
1114 :
1115 : /************************************************************************/
1116 : /* GDALReadBlock() */
1117 : /************************************************************************/
1118 :
1119 : /**
1120 : * \brief Read a block of image data efficiently.
1121 : *
1122 : * @see GDALRasterBand::ReadBlock()
1123 : */
1124 :
1125 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1126 : void *pData)
1127 :
1128 : {
1129 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1130 :
1131 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1132 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1133 : }
1134 :
1135 : /************************************************************************/
1136 : /* IReadBlock() */
1137 : /************************************************************************/
1138 :
1139 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1140 : * ) \brief Read a block of data.
1141 : *
1142 : * Default internal implementation ... to be overridden by
1143 : * subclasses that support reading.
1144 : * @param nBlockXOff Block X Offset
1145 : * @param nBlockYOff Block Y Offset
1146 : * @param pData Pixel buffer into which to place read data.
1147 : * @return CE_None on success or CE_Failure on an error.
1148 : */
1149 :
1150 : /************************************************************************/
1151 : /* IWriteBlock() */
1152 : /************************************************************************/
1153 :
1154 : /**
1155 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1156 : * Write a block of data.
1157 : *
1158 : * Default internal implementation ... to be overridden by
1159 : * subclasses that support writing.
1160 : * @param nBlockXOff Block X Offset
1161 : * @param nBlockYOff Block Y Offset
1162 : * @param pData Pixel buffer to write
1163 : * @return CE_None on success or CE_Failure on an error.
1164 : */
1165 :
1166 : /**/
1167 : /**/
1168 :
1169 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1170 : void * /*pData*/)
1171 :
1172 : {
1173 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1174 0 : ReportError(CE_Failure, CPLE_NotSupported,
1175 : "WriteBlock() not supported for this dataset.");
1176 :
1177 0 : return (CE_Failure);
1178 : }
1179 :
1180 : /************************************************************************/
1181 : /* WriteBlock() */
1182 : /************************************************************************/
1183 :
1184 : /**
1185 : * \brief Write a block of image data efficiently.
1186 : *
1187 : * This method accesses a "natural" block from the raster band without
1188 : * resampling, or data type conversion. For a more generalized, but
1189 : * potentially less efficient access use RasterIO().
1190 : *
1191 : * This method is the same as the C GDALWriteBlock() function.
1192 : *
1193 : * See ReadBlock() for an example of block oriented data access.
1194 : *
1195 : * @param nXBlockOff the horizontal block offset, with zero indicating
1196 : * the left most block, 1 the next block and so forth.
1197 : *
1198 : * @param nYBlockOff the vertical block offset, with zero indicating
1199 : * the left most block, 1 the next block and so forth.
1200 : *
1201 : * @param pImage the buffer from which the data will be written. The buffer
1202 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1203 : * of type GetRasterDataType(). Note that the content of the buffer might be
1204 : * temporarily modified during the execution of this method (and eventually
1205 : * restored back to its original content), so it is not safe to use a buffer
1206 : * stored in a read-only section of the calling program.
1207 : *
1208 : * @return CE_None on success or CE_Failure on an error.
1209 : */
1210 :
1211 4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1212 :
1213 : {
1214 : /* -------------------------------------------------------------------- */
1215 : /* Validate arguments. */
1216 : /* -------------------------------------------------------------------- */
1217 4883 : CPLAssert(pImage != nullptr);
1218 :
1219 4883 : if (!InitBlockInfo())
1220 0 : return CE_Failure;
1221 :
1222 4883 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1223 : {
1224 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1225 : "Illegal nXBlockOff value (%d) in "
1226 : "GDALRasterBand::WriteBlock()\n",
1227 : nXBlockOff);
1228 :
1229 0 : return (CE_Failure);
1230 : }
1231 :
1232 4883 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1233 : {
1234 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1235 : "Illegal nYBlockOff value (%d) in "
1236 : "GDALRasterBand::WriteBlock()\n",
1237 : nYBlockOff);
1238 :
1239 0 : return (CE_Failure);
1240 : }
1241 :
1242 4883 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1243 : {
1244 0 : return CE_Failure;
1245 : }
1246 :
1247 4883 : if (eFlushBlockErr != CE_None)
1248 : {
1249 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1250 : "An error occurred while writing a dirty block "
1251 : "from GDALRasterBand::WriteBlock");
1252 0 : CPLErr eErr = eFlushBlockErr;
1253 0 : eFlushBlockErr = CE_None;
1254 0 : return eErr;
1255 : }
1256 :
1257 : /* -------------------------------------------------------------------- */
1258 : /* Invoke underlying implementation method. */
1259 : /* -------------------------------------------------------------------- */
1260 :
1261 4883 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1262 4883 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1263 4883 : if (bCallLeaveReadWrite)
1264 4883 : LeaveReadWrite();
1265 :
1266 4883 : return eErr;
1267 : }
1268 :
1269 : /************************************************************************/
1270 : /* GDALWriteBlock() */
1271 : /************************************************************************/
1272 :
1273 : /**
1274 : * \brief Write a block of image data efficiently.
1275 : *
1276 : * @see GDALRasterBand::WriteBlock()
1277 : */
1278 :
1279 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1280 : void *pData)
1281 :
1282 : {
1283 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1284 :
1285 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1286 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1287 : }
1288 :
1289 : /************************************************************************/
1290 : /* EmitErrorMessageIfWriteNotSupported() */
1291 : /************************************************************************/
1292 :
1293 : /**
1294 : * Emit an error message if a write operation to this band is not supported.
1295 : *
1296 : * The base implementation will emit an error message if the access mode is
1297 : * read-only. Derived classes may implement it to provide a custom message.
1298 : *
1299 : * @param pszCaller Calling function.
1300 : * @return true if an error message has been emitted.
1301 : */
1302 639596 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1303 : const char *pszCaller) const
1304 : {
1305 639596 : 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 639592 : 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 52120 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1342 : int *pnXValid, int *pnYValid) const
1343 : {
1344 104239 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1345 104237 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1346 104234 : nYBlockOff < 0 || nBlockYSize == 0 ||
1347 52117 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1348 : {
1349 4 : return CE_Failure;
1350 : }
1351 :
1352 52116 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1353 52116 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1354 :
1355 52116 : *pnXValid = nBlockXSize;
1356 52116 : *pnYValid = nBlockYSize;
1357 :
1358 52116 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1359 : {
1360 50483 : *pnXValid = nRasterXSize - nXPixelOff;
1361 : }
1362 :
1363 52116 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1364 : {
1365 3820 : *pnYValid = nRasterYSize - nYPixelOff;
1366 : }
1367 :
1368 52116 : 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 2415 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1428 : {
1429 2415 : 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 8798830 : GDALDataType GDALRasterBand::GetRasterDataType() const
1445 :
1446 : {
1447 8798830 : 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 905993 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1461 :
1462 : {
1463 905993 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1464 :
1465 905993 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1466 905993 : 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 5400650 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1496 :
1497 : {
1498 5400650 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1499 : {
1500 59454 : ReportError(CE_Failure, CPLE_AppDefined,
1501 59454 : "Invalid block dimension : %d * %d", nBlockXSize,
1502 59454 : nBlockYSize);
1503 4 : if (pnXSize != nullptr)
1504 4 : *pnXSize = 0;
1505 4 : if (pnYSize != nullptr)
1506 4 : *pnYSize = 0;
1507 : }
1508 : else
1509 : {
1510 5341200 : if (pnXSize != nullptr)
1511 5299890 : *pnXSize = nBlockXSize;
1512 5341200 : if (pnYSize != nullptr)
1513 5339120 : *pnYSize = nBlockYSize;
1514 : }
1515 5341200 : }
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 3651060 : int GDALRasterBand::InitBlockInfo()
1543 :
1544 : {
1545 3651060 : if (poBandBlockCache != nullptr)
1546 3412110 : 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 238943 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1551 : {
1552 301 : ReportError(CE_Failure, CPLE_AppDefined,
1553 : "Invalid block dimension : %d * %d", nBlockXSize,
1554 : nBlockYSize);
1555 0 : return FALSE;
1556 : }
1557 :
1558 238642 : 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 238655 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1567 238917 : if (nDataTypeSize == 0)
1568 : {
1569 259 : 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 238658 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1590 238658 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1591 :
1592 : const char *pszBlockStrategy =
1593 238658 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1594 239017 : bool bUseArray = true;
1595 239017 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1596 : {
1597 238977 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1598 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1599 : {
1600 238958 : GUIntBig nBlockCount =
1601 238958 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1602 238958 : if (poDS != nullptr)
1603 238754 : nBlockCount *= poDS->GetRasterCount();
1604 238958 : 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 238977 : }
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 239017 : if (bUseArray)
1619 238946 : 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 238978 : if (poBandBlockCache == nullptr)
1627 0 : return FALSE;
1628 238978 : 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 5632180 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1650 :
1651 : {
1652 5749260 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1653 117081 : poBandBlockCache)
1654 3197 : poBandBlockCache->DisableDirtyBlockWriting();
1655 :
1656 5620380 : CPLErr eGlobalErr = eFlushBlockErr;
1657 :
1658 5620380 : 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 5620380 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1667 4813730 : return eGlobalErr;
1668 :
1669 806655 : 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 29654 : 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 29654 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1787 29654 : 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 29651 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1800 : {
1801 29651 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1802 29646 : 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 10646000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1888 : int nYBlockOff)
1889 :
1890 : {
1891 10646000 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1892 172604 : return nullptr;
1893 :
1894 : /* -------------------------------------------------------------------- */
1895 : /* Validate the request */
1896 : /* -------------------------------------------------------------------- */
1897 10473200 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1898 : {
1899 1254 : 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 10472000 : 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 10472000 : 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 10335600 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1955 : int nYBlockOff,
1956 : int bJustInitialize)
1957 :
1958 : {
1959 : /* -------------------------------------------------------------------- */
1960 : /* Try and fetch from cache. */
1961 : /* -------------------------------------------------------------------- */
1962 10335600 : 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 10336100 : if (poBlock == nullptr)
1970 : {
1971 3373720 : if (!InitBlockInfo())
1972 0 : return (nullptr);
1973 :
1974 : /* --------------------------------------------------------------------
1975 : */
1976 : /* Validate the request */
1977 : /* --------------------------------------------------------------------
1978 : */
1979 3373950 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1980 : {
1981 160 : 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 3373790 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1990 : {
1991 14 : 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 3373780 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
2000 3373740 : if (poBlock == nullptr)
2001 0 : return nullptr;
2002 :
2003 3373740 : 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 3373800 : if (poDS)
2018 3373070 : poDS->TemporarilyDropReadWriteLock();
2019 : /* allocate data space */
2020 3373760 : CPLErr eErr = poBlock->Internalize();
2021 3373950 : if (poDS)
2022 3373070 : poDS->ReacquireReadWriteLock();
2023 3373760 : if (eErr != CE_None)
2024 : {
2025 0 : poBlock->DropLock();
2026 0 : delete poBlock;
2027 0 : return nullptr;
2028 : }
2029 :
2030 3373760 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2031 : {
2032 0 : poBlock->DropLock();
2033 0 : delete poBlock;
2034 0 : return nullptr;
2035 : }
2036 :
2037 3373930 : if (!bJustInitialize)
2038 : {
2039 2887670 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2040 2887680 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2041 2887510 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2042 2887760 : if (bCallLeaveReadWrite)
2043 130218 : LeaveReadWrite();
2044 2887550 : 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 2886390 : nBlockReads++;
2058 2886390 : if (static_cast<GIntBig>(nBlockReads) ==
2059 2886390 : 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 10335000 : 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 268881 : 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 268881 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2108 : {
2109 6 : return CE_Failure;
2110 : }
2111 :
2112 : // Make sure block parameters are set.
2113 268875 : if (!InitBlockInfo())
2114 0 : return CE_Failure;
2115 :
2116 : // Allocate the source block.
2117 268875 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2118 268875 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2119 268875 : auto blockByteSize = blockSize * elementSize;
2120 : unsigned char *srcBlock =
2121 268875 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2122 268875 : 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 268875 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2133 268875 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2134 : elementSize, blockSize);
2135 :
2136 268875 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2137 :
2138 : // Write block to block cache
2139 872406 : for (int j = 0; j < nBlocksPerColumn; ++j)
2140 : {
2141 1501410 : for (int i = 0; i < nBlocksPerRow; ++i)
2142 : {
2143 897878 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2144 897878 : 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 897878 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2153 897878 : destBlock->MarkDirty();
2154 897878 : destBlock->DropLock();
2155 : }
2156 : }
2157 :
2158 268875 : if (bCallLeaveReadWrite)
2159 267686 : LeaveReadWrite();
2160 :
2161 : // Free up the source block
2162 268875 : VSIFree(srcBlock);
2163 :
2164 268875 : 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 268683 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2177 : double dfImaginaryValue)
2178 : {
2179 268683 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2180 :
2181 268683 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2182 268683 : 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 3040 : GDALAccess GDALRasterBand::GetAccess()
2198 :
2199 : {
2200 3040 : 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 2382 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2214 :
2215 : {
2216 2382 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2217 :
2218 2382 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2219 2382 : 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 414461 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2367 : int *pbSuccess)
2368 :
2369 : {
2370 414461 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2371 :
2372 414461 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2373 414461 : 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 994 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2674 : double dfValue)
2675 :
2676 : {
2677 994 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2678 :
2679 994 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2680 994 : 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_UInt8:
2909 : {
2910 340 : EnablePixelTypeSignedByteWarning(false);
2911 : const char *pszPixelType =
2912 340 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2913 340 : EnablePixelTypeSignedByteWarning(true);
2914 340 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2915 0 : return 127;
2916 :
2917 340 : return 255;
2918 : }
2919 :
2920 1 : case GDT_Int8:
2921 1 : return 127;
2922 :
2923 21 : case GDT_UInt16:
2924 21 : return 65535;
2925 :
2926 24 : case GDT_Int16:
2927 : case GDT_CInt16:
2928 24 : return 32767;
2929 :
2930 39 : case GDT_Int32:
2931 : case GDT_CInt32:
2932 39 : return 2147483647.0;
2933 :
2934 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_UInt8:
3018 : {
3019 343 : EnablePixelTypeSignedByteWarning(false);
3020 : const char *pszPixelType =
3021 343 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3022 343 : EnablePixelTypeSignedByteWarning(true);
3023 343 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3024 0 : return -128;
3025 :
3026 343 : return 0;
3027 : }
3028 :
3029 1 : case GDT_Int8:
3030 1 : return -128;
3031 :
3032 21 : case GDT_UInt16:
3033 21 : return 0;
3034 :
3035 24 : case GDT_Int16:
3036 : case GDT_CInt16:
3037 24 : return -32768;
3038 :
3039 39 : case GDT_Int32:
3040 : case GDT_CInt32:
3041 39 : return -2147483648.0;
3042 :
3043 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 1989 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3212 :
3213 : {
3214 1989 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3215 :
3216 1989 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3217 1989 : 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 1066480 : int GDALRasterBand::GetOverviewCount()
3330 :
3331 : {
3332 1723240 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3333 656749 : poDS->AreOverviewsEnabled())
3334 656750 : return poDS->oOvManager.GetOverviewCount(nBand);
3335 :
3336 409735 : 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 3302 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3350 :
3351 : {
3352 3302 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3353 :
3354 3302 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3355 3302 : return poBand->GetOverviewCount();
3356 : }
3357 :
3358 : /************************************************************************/
3359 : /* GetOverview() */
3360 : /************************************************************************/
3361 :
3362 : /**
3363 : * \brief Fetch overview raster band object.
3364 : *
3365 : * This method is the same as the C function GDALGetOverview().
3366 : *
3367 : * @param i overview index between 0 and GetOverviewCount()-1.
3368 : *
3369 : * @return overview GDALRasterBand.
3370 : */
3371 :
3372 942 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3373 :
3374 : {
3375 1732 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3376 790 : poDS->AreOverviewsEnabled())
3377 790 : return poDS->oOvManager.GetOverview(nBand, i);
3378 :
3379 152 : return nullptr;
3380 : }
3381 :
3382 : /************************************************************************/
3383 : /* GDALGetOverview() */
3384 : /************************************************************************/
3385 :
3386 : /**
3387 : * \brief Fetch overview raster band object.
3388 : *
3389 : * @see GDALRasterBand::GetOverview()
3390 : */
3391 :
3392 5641 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3393 :
3394 : {
3395 5641 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3396 :
3397 5641 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3398 5641 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3399 : }
3400 :
3401 : /************************************************************************/
3402 : /* GetRasterSampleOverview() */
3403 : /************************************************************************/
3404 :
3405 : /**
3406 : * \brief Fetch best sampling overview.
3407 : *
3408 : * Returns the most reduced overview of the given band that still satisfies
3409 : * the desired number of samples. This function can be used with zero
3410 : * as the number of desired samples to fetch the most reduced overview.
3411 : * The same band as was passed in will be returned if it has not overviews,
3412 : * or if none of the overviews have enough samples.
3413 : *
3414 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3415 : * and GDALGetRasterSampleOverviewEx().
3416 : *
3417 : * @param nDesiredSamples the returned band will have at least this many
3418 : * pixels.
3419 : *
3420 : * @return optimal overview or the band itself.
3421 : */
3422 :
3423 : GDALRasterBand *
3424 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3425 :
3426 : {
3427 2006 : GDALRasterBand *poBestBand = this;
3428 :
3429 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3430 :
3431 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3432 : {
3433 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3434 :
3435 2017 : if (poOBand == nullptr)
3436 0 : continue;
3437 :
3438 : const double dfOSamples =
3439 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3440 :
3441 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3442 : {
3443 2014 : dfBestSamples = dfOSamples;
3444 2014 : poBestBand = poOBand;
3445 : }
3446 : }
3447 :
3448 2006 : return poBestBand;
3449 : }
3450 :
3451 : /************************************************************************/
3452 : /* GDALGetRasterSampleOverview() */
3453 : /************************************************************************/
3454 :
3455 : /**
3456 : * \brief Fetch best sampling overview.
3457 : *
3458 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3459 : * billion samples.
3460 : *
3461 : * @see GDALRasterBand::GetRasterSampleOverview()
3462 : * @see GDALGetRasterSampleOverviewEx()
3463 : */
3464 :
3465 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3466 : int nDesiredSamples)
3467 :
3468 : {
3469 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3470 :
3471 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3472 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3473 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3474 : }
3475 :
3476 : /************************************************************************/
3477 : /* GDALGetRasterSampleOverviewEx() */
3478 : /************************************************************************/
3479 :
3480 : /**
3481 : * \brief Fetch best sampling overview.
3482 : *
3483 : * @see GDALRasterBand::GetRasterSampleOverview()
3484 : */
3485 :
3486 : GDALRasterBandH CPL_STDCALL
3487 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3488 :
3489 : {
3490 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3491 :
3492 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3493 2000 : return GDALRasterBand::ToHandle(
3494 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3495 : }
3496 :
3497 : /************************************************************************/
3498 : /* BuildOverviews() */
3499 : /************************************************************************/
3500 :
3501 : /**
3502 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3503 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3504 : *
3505 : * If the operation is unsupported for the indicated dataset, then
3506 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3507 : * CPLE_NotSupported.
3508 : *
3509 : * WARNING: Most formats don't support per-band overview computation, but
3510 : * require that overviews are computed for all bands of a dataset, using
3511 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3512 : * is the HFA driver which supports this method.
3513 : *
3514 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3515 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3516 : * applied.
3517 : * @param nOverviews number of overviews to build.
3518 : * @param panOverviewList the list of overview decimation factors to build.
3519 : * @param pfnProgress a function to call to report progress, or NULL.
3520 : * @param pProgressData application data to pass to the progress function.
3521 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3522 : * key=value pairs, or NULL
3523 : *
3524 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3525 : */
3526 :
3527 : /**/
3528 : /**/
3529 :
3530 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3531 : int /*nOverviews*/,
3532 : const int * /*panOverviewList*/,
3533 : GDALProgressFunc /*pfnProgress*/,
3534 : void * /*pProgressData*/,
3535 : CSLConstList /* papszOptions */)
3536 :
3537 : {
3538 0 : ReportError(CE_Failure, CPLE_NotSupported,
3539 : "BuildOverviews() not supported for this dataset.");
3540 :
3541 0 : return (CE_Failure);
3542 : }
3543 :
3544 : /************************************************************************/
3545 : /* GetOffset() */
3546 : /************************************************************************/
3547 :
3548 : /**
3549 : * \brief Fetch the raster value offset.
3550 : *
3551 : * This value (in combination with the GetScale() value) can be used to
3552 : * transform raw pixel values into the units returned by GetUnitType().
3553 : * For example this might be used to store elevations in GUInt16 bands
3554 : * with a precision of 0.1, and starting from -100.
3555 : *
3556 : * Units value = (raw value * scale) + offset
3557 : *
3558 : * Note that applying scale and offset is of the responsibility of the user,
3559 : * and is not done by methods such as RasterIO() or ReadBlock().
3560 : *
3561 : * For file formats that don't know this intrinsically a value of zero
3562 : * is returned.
3563 : *
3564 : * This method is the same as the C function GDALGetRasterOffset().
3565 : *
3566 : * @param pbSuccess pointer to a boolean to use to indicate if the
3567 : * returned value is meaningful or not. May be NULL (default).
3568 : *
3569 : * @return the raster offset.
3570 : */
3571 :
3572 445 : double GDALRasterBand::GetOffset(int *pbSuccess)
3573 :
3574 : {
3575 445 : if (pbSuccess != nullptr)
3576 336 : *pbSuccess = FALSE;
3577 :
3578 445 : return 0.0;
3579 : }
3580 :
3581 : /************************************************************************/
3582 : /* GDALGetRasterOffset() */
3583 : /************************************************************************/
3584 :
3585 : /**
3586 : * \brief Fetch the raster value offset.
3587 : *
3588 : * @see GDALRasterBand::GetOffset()
3589 : */
3590 :
3591 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 1487 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3790 :
3791 : {
3792 1487 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3793 :
3794 1487 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3795 1487 : 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 96 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3842 : const char *pszNewValue)
3843 :
3844 : {
3845 96 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3846 :
3847 96 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3848 96 : 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 8285610 : int GDALRasterBand::GetXSize() const
3864 :
3865 : {
3866 8285610 : 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 4502800 : int GDALRasterBand::GetYSize() const
3901 :
3902 : {
3903 4502800 : 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 150830 : int GDALRasterBand::GetBand() const
3943 :
3944 : {
3945 150830 : 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 5253630 : GDALDataset *GDALRasterBand::GetDataset() const
3984 :
3985 : {
3986 5253630 : 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 3014 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4013 : double dfNoDataValue,
4014 : int &bGotNoDataValue,
4015 : GFloat16 &fNoDataValue,
4016 : bool &bGotFloat16NoDataValue)
4017 : {
4018 3014 : 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 3014 : }
4029 :
4030 : /************************************************************************/
4031 : /* ComputeFloatNoDataValue() */
4032 : /************************************************************************/
4033 :
4034 3014 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4035 : double dfNoDataValue,
4036 : int &bGotNoDataValue,
4037 : float &fNoDataValue,
4038 : bool &bGotFloatNoDataValue)
4039 : {
4040 3014 : 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 3014 : }
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 3106 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4082 3106 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4083 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4084 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4085 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4086 3106 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4087 : {
4088 3106 : 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 3048 : 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 3014 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4123 3014 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4124 :
4125 3014 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4126 3014 : fNoDataValue, bGotFloatNoDataValue);
4127 :
4128 3014 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4129 3014 : hfNoDataValue, bGotFloat16NoDataValue);
4130 : }
4131 3106 : }
4132 : };
4133 :
4134 : /************************************************************************/
4135 : /* ARE_REAL_EQUAL() */
4136 : /************************************************************************/
4137 :
4138 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4139 : {
4140 : using std::abs;
4141 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4142 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4143 0 : abs(dfVal1 + dfVal2) * ulp;
4144 : }
4145 :
4146 : /************************************************************************/
4147 : /* GetHistogram() */
4148 : /************************************************************************/
4149 :
4150 : /**
4151 : * \brief Compute raster histogram.
4152 : *
4153 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4154 : *
4155 : * For example to compute a simple 256 entry histogram of eight bit data,
4156 : * the following would be suitable. The unusual bounds are to ensure that
4157 : * bucket boundaries don't fall right on integer values causing possible errors
4158 : * due to rounding after scaling.
4159 : \code{.cpp}
4160 : GUIntBig anHistogram[256];
4161 :
4162 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4163 : GDALDummyProgress, nullptr );
4164 : \endcode
4165 : *
4166 : * Note that setting bApproxOK will generally result in a subsampling of the
4167 : * file, and will utilize overviews if available. It should generally
4168 : * produce a representative histogram for the data that is suitable for use
4169 : * in generating histogram based luts for instance. Generally bApproxOK is
4170 : * much faster than an exactly computed histogram.
4171 : *
4172 : * This method is the same as the C functions GDALGetRasterHistogram() and
4173 : * GDALGetRasterHistogramEx().
4174 : *
4175 : * @param dfMin the lower bound of the histogram.
4176 : * @param dfMax the upper bound of the histogram.
4177 : * @param nBuckets the number of buckets in panHistogram.
4178 : * @param panHistogram array into which the histogram totals are placed.
4179 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4180 : * mapped into panHistogram[0], and values above will be mapped into
4181 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4182 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4183 : * @param pfnProgress function to report progress to completion.
4184 : * @param pProgressData application data to pass to pfnProgress.
4185 : *
4186 : * @return CE_None on success, or CE_Failure if something goes wrong.
4187 : */
4188 :
4189 45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4190 : GUIntBig *panHistogram,
4191 : int bIncludeOutOfRange, int bApproxOK,
4192 : GDALProgressFunc pfnProgress,
4193 : void *pProgressData)
4194 :
4195 : {
4196 45 : CPLAssert(nullptr != panHistogram);
4197 :
4198 45 : if (pfnProgress == nullptr)
4199 29 : pfnProgress = GDALDummyProgress;
4200 :
4201 : /* -------------------------------------------------------------------- */
4202 : /* If we have overviews, use them for the histogram. */
4203 : /* -------------------------------------------------------------------- */
4204 45 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4205 : {
4206 : // FIXME: should we use the most reduced overview here or use some
4207 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4208 : // does?
4209 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4210 :
4211 0 : if (poBestOverview != this)
4212 : {
4213 0 : return poBestOverview->GetHistogram(
4214 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4215 0 : bApproxOK, pfnProgress, pProgressData);
4216 : }
4217 : }
4218 :
4219 : /* -------------------------------------------------------------------- */
4220 : /* Read actual data and build histogram. */
4221 : /* -------------------------------------------------------------------- */
4222 45 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4223 : {
4224 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4225 0 : return CE_Failure;
4226 : }
4227 :
4228 : // Written this way to deal with NaN
4229 45 : if (!(dfMax > dfMin))
4230 : {
4231 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4232 : "dfMax should be strictly greater than dfMin");
4233 5 : return CE_Failure;
4234 : }
4235 :
4236 : GDALRasterIOExtraArg sExtraArg;
4237 40 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4238 :
4239 40 : const double dfScale = nBuckets / (dfMax - dfMin);
4240 40 : if (dfScale == 0 || !std::isfinite(dfScale))
4241 : {
4242 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4243 : "dfMin and dfMax should be finite values such that "
4244 : "nBuckets / (dfMax - dfMin) is non-zero");
4245 5 : return CE_Failure;
4246 : }
4247 35 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4248 :
4249 35 : GDALNoDataValues sNoDataValues(this, eDataType);
4250 35 : GDALRasterBand *poMaskBand = nullptr;
4251 35 : if (!sNoDataValues.bGotNoDataValue)
4252 : {
4253 34 : const int l_nMaskFlags = GetMaskFlags();
4254 36 : if (l_nMaskFlags != GMF_ALL_VALID &&
4255 2 : GetColorInterpretation() != GCI_AlphaBand)
4256 : {
4257 2 : poMaskBand = GetMaskBand();
4258 : }
4259 : }
4260 :
4261 35 : bool bSignedByte = false;
4262 35 : if (eDataType == GDT_UInt8)
4263 : {
4264 26 : EnablePixelTypeSignedByteWarning(false);
4265 : const char *pszPixelType =
4266 26 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4267 26 : EnablePixelTypeSignedByteWarning(true);
4268 26 : bSignedByte =
4269 26 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4270 : }
4271 :
4272 35 : if (bApproxOK && HasArbitraryOverviews())
4273 : {
4274 : /* --------------------------------------------------------------------
4275 : */
4276 : /* Figure out how much the image should be reduced to get an */
4277 : /* approximate value. */
4278 : /* --------------------------------------------------------------------
4279 : */
4280 : const double dfReduction =
4281 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4282 : GDALSTAT_APPROX_NUMSAMPLES);
4283 :
4284 0 : int nXReduced = nRasterXSize;
4285 0 : int nYReduced = nRasterYSize;
4286 0 : if (dfReduction > 1.0)
4287 : {
4288 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4289 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4290 :
4291 : // Catch the case of huge resizing ratios here
4292 0 : if (nXReduced == 0)
4293 0 : nXReduced = 1;
4294 0 : if (nYReduced == 0)
4295 0 : nYReduced = 1;
4296 : }
4297 :
4298 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4299 : nXReduced, nYReduced);
4300 0 : if (!pData)
4301 0 : return CE_Failure;
4302 :
4303 : const CPLErr eErr =
4304 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4305 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4306 0 : if (eErr != CE_None)
4307 : {
4308 0 : CPLFree(pData);
4309 0 : return eErr;
4310 : }
4311 :
4312 0 : GByte *pabyMaskData = nullptr;
4313 0 : if (poMaskBand)
4314 : {
4315 : pabyMaskData =
4316 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4317 0 : if (!pabyMaskData)
4318 : {
4319 0 : CPLFree(pData);
4320 0 : return CE_Failure;
4321 : }
4322 :
4323 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4324 : pabyMaskData, nXReduced, nYReduced,
4325 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
4326 : {
4327 0 : CPLFree(pData);
4328 0 : CPLFree(pabyMaskData);
4329 0 : return CE_Failure;
4330 : }
4331 : }
4332 :
4333 : // This isn't the fastest way to do this, but is easier for now.
4334 0 : for (int iY = 0; iY < nYReduced; iY++)
4335 : {
4336 0 : for (int iX = 0; iX < nXReduced; iX++)
4337 : {
4338 0 : const int iOffset = iX + iY * nXReduced;
4339 0 : double dfValue = 0.0;
4340 :
4341 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4342 0 : continue;
4343 :
4344 0 : switch (eDataType)
4345 : {
4346 0 : case GDT_UInt8:
4347 : {
4348 0 : if (bSignedByte)
4349 0 : dfValue =
4350 0 : static_cast<signed char *>(pData)[iOffset];
4351 : else
4352 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4353 0 : break;
4354 : }
4355 0 : case GDT_Int8:
4356 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4357 0 : break;
4358 0 : case GDT_UInt16:
4359 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4360 0 : break;
4361 0 : case GDT_Int16:
4362 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4363 0 : break;
4364 0 : case GDT_UInt32:
4365 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4366 0 : break;
4367 0 : case GDT_Int32:
4368 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4369 0 : break;
4370 0 : case GDT_UInt64:
4371 0 : dfValue = static_cast<double>(
4372 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4373 0 : break;
4374 0 : case GDT_Int64:
4375 0 : dfValue = static_cast<double>(
4376 0 : static_cast<GInt64 *>(pData)[iOffset]);
4377 0 : break;
4378 0 : case GDT_Float16:
4379 : {
4380 : using namespace std;
4381 0 : const GFloat16 hfValue =
4382 0 : static_cast<GFloat16 *>(pData)[iOffset];
4383 0 : if (isnan(hfValue) ||
4384 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4385 0 : ARE_REAL_EQUAL(hfValue,
4386 : sNoDataValues.hfNoDataValue)))
4387 0 : continue;
4388 0 : dfValue = hfValue;
4389 0 : break;
4390 : }
4391 0 : case GDT_Float32:
4392 : {
4393 0 : const float fValue =
4394 0 : static_cast<float *>(pData)[iOffset];
4395 0 : if (std::isnan(fValue) ||
4396 0 : (sNoDataValues.bGotFloatNoDataValue &&
4397 0 : ARE_REAL_EQUAL(fValue,
4398 : sNoDataValues.fNoDataValue)))
4399 0 : continue;
4400 0 : dfValue = double(fValue);
4401 0 : break;
4402 : }
4403 0 : case GDT_Float64:
4404 0 : dfValue = static_cast<double *>(pData)[iOffset];
4405 0 : if (std::isnan(dfValue))
4406 0 : continue;
4407 0 : break;
4408 0 : case GDT_CInt16:
4409 : {
4410 0 : const double dfReal =
4411 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4412 0 : const double dfImag =
4413 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4414 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4415 0 : continue;
4416 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4417 : }
4418 0 : break;
4419 0 : case GDT_CInt32:
4420 : {
4421 0 : const double dfReal =
4422 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4423 0 : const double dfImag =
4424 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4425 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4426 0 : continue;
4427 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4428 : }
4429 0 : break;
4430 0 : case GDT_CFloat16:
4431 : {
4432 : const double dfReal =
4433 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4434 : const double dfImag =
4435 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4436 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4437 0 : continue;
4438 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4439 0 : break;
4440 : }
4441 0 : case GDT_CFloat32:
4442 : {
4443 0 : const double dfReal =
4444 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4445 0 : const double dfImag = double(
4446 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4447 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4448 0 : continue;
4449 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4450 0 : break;
4451 : }
4452 0 : case GDT_CFloat64:
4453 : {
4454 0 : const double dfReal =
4455 0 : static_cast<double *>(pData)[iOffset * 2];
4456 0 : const double dfImag =
4457 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4458 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4459 0 : continue;
4460 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4461 0 : break;
4462 : }
4463 0 : case GDT_Unknown:
4464 : case GDT_TypeCount:
4465 0 : CPLAssert(false);
4466 : }
4467 :
4468 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4469 0 : sNoDataValues.bGotNoDataValue &&
4470 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4471 0 : continue;
4472 :
4473 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4474 : // finite, the result of the multiplication cannot be NaN
4475 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4476 :
4477 0 : if (dfIndex < 0)
4478 : {
4479 0 : if (bIncludeOutOfRange)
4480 0 : panHistogram[0]++;
4481 : }
4482 0 : else if (dfIndex >= nBuckets)
4483 : {
4484 0 : if (bIncludeOutOfRange)
4485 0 : ++panHistogram[nBuckets - 1];
4486 : }
4487 : else
4488 : {
4489 0 : ++panHistogram[static_cast<int>(dfIndex)];
4490 : }
4491 : }
4492 : }
4493 :
4494 0 : CPLFree(pData);
4495 0 : CPLFree(pabyMaskData);
4496 : }
4497 : else // No arbitrary overviews.
4498 : {
4499 35 : if (!InitBlockInfo())
4500 0 : return CE_Failure;
4501 :
4502 : /* --------------------------------------------------------------------
4503 : */
4504 : /* Figure out the ratio of blocks we will read to get an */
4505 : /* approximate value. */
4506 : /* --------------------------------------------------------------------
4507 : */
4508 :
4509 35 : int nSampleRate = 1;
4510 35 : if (bApproxOK)
4511 : {
4512 8 : nSampleRate = static_cast<int>(std::max(
4513 16 : 1.0,
4514 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4515 : // We want to avoid probing only the first column of blocks for
4516 : // a square shaped raster, because it is not unlikely that it may
4517 : // be padding only (#6378).
4518 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4519 1 : nSampleRate += 1;
4520 : }
4521 :
4522 35 : GByte *pabyMaskData = nullptr;
4523 35 : if (poMaskBand)
4524 : {
4525 : pabyMaskData = static_cast<GByte *>(
4526 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4527 2 : if (!pabyMaskData)
4528 : {
4529 0 : return CE_Failure;
4530 : }
4531 : }
4532 :
4533 : /* --------------------------------------------------------------------
4534 : */
4535 : /* Read the blocks, and add to histogram. */
4536 : /* --------------------------------------------------------------------
4537 : */
4538 35 : for (GIntBig iSampleBlock = 0;
4539 160 : iSampleBlock <
4540 160 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4541 125 : iSampleBlock += nSampleRate)
4542 : {
4543 125 : if (!pfnProgress(
4544 125 : static_cast<double>(iSampleBlock) /
4545 125 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4546 : "Compute Histogram", pProgressData))
4547 : {
4548 0 : CPLFree(pabyMaskData);
4549 0 : return CE_Failure;
4550 : }
4551 :
4552 125 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4553 125 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4554 :
4555 125 : int nXCheck = 0, nYCheck = 0;
4556 125 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4557 :
4558 127 : if (poMaskBand &&
4559 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4560 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4561 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
4562 2 : 0, nBlockXSize, nullptr) != CE_None)
4563 : {
4564 0 : CPLFree(pabyMaskData);
4565 0 : return CE_Failure;
4566 : }
4567 :
4568 125 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4569 125 : if (poBlock == nullptr)
4570 : {
4571 0 : CPLFree(pabyMaskData);
4572 0 : return CE_Failure;
4573 : }
4574 :
4575 125 : void *pData = poBlock->GetDataRef();
4576 :
4577 : // this is a special case for a common situation.
4578 125 : if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
4579 89 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4580 86 : nXCheck == nBlockXSize && nBuckets == 256)
4581 : {
4582 86 : const GPtrDiff_t nPixels =
4583 86 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4584 86 : GByte *pabyData = static_cast<GByte *>(pData);
4585 :
4586 79640 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4587 : {
4588 79554 : if (pabyMaskData && pabyMaskData[i] == 0)
4589 0 : continue;
4590 79554 : if (!(sNoDataValues.bGotNoDataValue &&
4591 512 : (pabyData[i] ==
4592 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4593 : {
4594 79298 : panHistogram[pabyData[i]]++;
4595 : }
4596 : }
4597 :
4598 86 : poBlock->DropLock();
4599 86 : continue; // To next sample block.
4600 : }
4601 :
4602 : // This isn't the fastest way to do this, but is easier for now.
4603 257 : for (int iY = 0; iY < nYCheck; iY++)
4604 : {
4605 36389 : for (int iX = 0; iX < nXCheck; iX++)
4606 : {
4607 36171 : const GPtrDiff_t iOffset =
4608 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4609 :
4610 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4611 2 : continue;
4612 :
4613 36169 : double dfValue = 0.0;
4614 :
4615 36169 : switch (eDataType)
4616 : {
4617 19716 : case GDT_UInt8:
4618 : {
4619 19716 : if (bSignedByte)
4620 0 : dfValue =
4621 0 : static_cast<signed char *>(pData)[iOffset];
4622 : else
4623 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4624 19716 : break;
4625 : }
4626 1 : case GDT_Int8:
4627 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4628 1 : break;
4629 16384 : case GDT_UInt16:
4630 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4631 16384 : break;
4632 3 : case GDT_Int16:
4633 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4634 3 : break;
4635 0 : case GDT_UInt32:
4636 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4637 0 : break;
4638 60 : case GDT_Int32:
4639 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4640 60 : break;
4641 0 : case GDT_UInt64:
4642 0 : dfValue = static_cast<double>(
4643 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4644 0 : break;
4645 0 : case GDT_Int64:
4646 0 : dfValue = static_cast<double>(
4647 0 : static_cast<GInt64 *>(pData)[iOffset]);
4648 0 : break;
4649 0 : case GDT_Float16:
4650 : {
4651 : using namespace std;
4652 0 : const GFloat16 hfValue =
4653 0 : static_cast<GFloat16 *>(pData)[iOffset];
4654 0 : if (isnan(hfValue) ||
4655 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4656 0 : ARE_REAL_EQUAL(hfValue,
4657 : sNoDataValues.hfNoDataValue)))
4658 0 : continue;
4659 0 : dfValue = hfValue;
4660 0 : break;
4661 : }
4662 3 : case GDT_Float32:
4663 : {
4664 3 : const float fValue =
4665 3 : static_cast<float *>(pData)[iOffset];
4666 6 : if (std::isnan(fValue) ||
4667 6 : (sNoDataValues.bGotFloatNoDataValue &&
4668 3 : ARE_REAL_EQUAL(fValue,
4669 : sNoDataValues.fNoDataValue)))
4670 0 : continue;
4671 3 : dfValue = double(fValue);
4672 3 : break;
4673 : }
4674 2 : case GDT_Float64:
4675 2 : dfValue = static_cast<double *>(pData)[iOffset];
4676 2 : if (std::isnan(dfValue))
4677 0 : continue;
4678 2 : break;
4679 0 : case GDT_CInt16:
4680 : {
4681 0 : double dfReal =
4682 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4683 0 : double dfImag =
4684 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4685 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4686 0 : break;
4687 : }
4688 0 : case GDT_CInt32:
4689 : {
4690 0 : double dfReal =
4691 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4692 0 : double dfImag =
4693 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4694 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4695 0 : break;
4696 : }
4697 0 : case GDT_CFloat16:
4698 : {
4699 : double dfReal =
4700 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4701 : double dfImag =
4702 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4703 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4704 0 : continue;
4705 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4706 0 : break;
4707 : }
4708 0 : case GDT_CFloat32:
4709 : {
4710 0 : double dfReal = double(
4711 0 : static_cast<float *>(pData)[iOffset * 2]);
4712 0 : double dfImag = double(
4713 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4714 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4715 0 : continue;
4716 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4717 0 : break;
4718 : }
4719 0 : case GDT_CFloat64:
4720 : {
4721 0 : double dfReal =
4722 0 : static_cast<double *>(pData)[iOffset * 2];
4723 0 : double dfImag =
4724 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4725 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4726 0 : continue;
4727 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4728 0 : break;
4729 : }
4730 0 : case GDT_Unknown:
4731 : case GDT_TypeCount:
4732 0 : CPLAssert(false);
4733 : CPLFree(pabyMaskData);
4734 : return CE_Failure;
4735 : }
4736 :
4737 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4738 72338 : sNoDataValues.bGotNoDataValue &&
4739 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4740 0 : continue;
4741 :
4742 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4743 : // and finite, the result of the multiplication cannot be
4744 : // NaN
4745 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4746 :
4747 36169 : if (dfIndex < 0)
4748 : {
4749 1 : if (bIncludeOutOfRange)
4750 1 : panHistogram[0]++;
4751 : }
4752 36168 : else if (dfIndex >= nBuckets)
4753 : {
4754 7 : if (bIncludeOutOfRange)
4755 4 : ++panHistogram[nBuckets - 1];
4756 : }
4757 : else
4758 : {
4759 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4760 : }
4761 : }
4762 : }
4763 :
4764 39 : poBlock->DropLock();
4765 : }
4766 :
4767 35 : CPLFree(pabyMaskData);
4768 : }
4769 :
4770 35 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4771 :
4772 35 : return CE_None;
4773 : }
4774 :
4775 : /************************************************************************/
4776 : /* GDALGetRasterHistogram() */
4777 : /************************************************************************/
4778 :
4779 : /**
4780 : * \brief Compute raster histogram.
4781 : *
4782 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4783 : * exceeding 2 billion.
4784 : *
4785 : * @see GDALRasterBand::GetHistogram()
4786 : * @see GDALGetRasterHistogramEx()
4787 : */
4788 :
4789 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4790 : double dfMax, int nBuckets,
4791 : int *panHistogram,
4792 : int bIncludeOutOfRange, int bApproxOK,
4793 : GDALProgressFunc pfnProgress,
4794 : void *pProgressData)
4795 :
4796 : {
4797 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4798 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4799 :
4800 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4801 :
4802 : GUIntBig *panHistogramTemp =
4803 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4804 0 : if (panHistogramTemp == nullptr)
4805 : {
4806 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4807 : "Out of memory in GDALGetRasterHistogram().");
4808 0 : return CE_Failure;
4809 : }
4810 :
4811 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4812 : bIncludeOutOfRange, bApproxOK,
4813 0 : pfnProgress, pProgressData);
4814 :
4815 0 : if (eErr == CE_None)
4816 : {
4817 0 : for (int i = 0; i < nBuckets; i++)
4818 : {
4819 0 : if (panHistogramTemp[i] > INT_MAX)
4820 : {
4821 0 : CPLError(CE_Warning, CPLE_AppDefined,
4822 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4823 : " exceeds maximum 32 bit value",
4824 0 : i, panHistogramTemp[i]);
4825 0 : panHistogram[i] = INT_MAX;
4826 : }
4827 : else
4828 : {
4829 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4830 : }
4831 : }
4832 : }
4833 :
4834 0 : CPLFree(panHistogramTemp);
4835 :
4836 0 : return eErr;
4837 : }
4838 :
4839 : /************************************************************************/
4840 : /* GDALGetRasterHistogramEx() */
4841 : /************************************************************************/
4842 :
4843 : /**
4844 : * \brief Compute raster histogram.
4845 : *
4846 : * @see GDALRasterBand::GetHistogram()
4847 : *
4848 : */
4849 :
4850 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4851 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4852 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4853 : GDALProgressFunc pfnProgress, void *pProgressData)
4854 :
4855 : {
4856 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4857 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4858 :
4859 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4860 :
4861 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4862 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4863 26 : pProgressData);
4864 : }
4865 :
4866 : /************************************************************************/
4867 : /* GetDefaultHistogram() */
4868 : /************************************************************************/
4869 :
4870 : /**
4871 : * \brief Fetch default raster histogram.
4872 : *
4873 : * The default method in GDALRasterBand will compute a default histogram. This
4874 : * method is overridden by derived classes (such as GDALPamRasterBand,
4875 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4876 : * stored histogram.
4877 : *
4878 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4879 : * GDALGetDefaultHistogramEx().
4880 : *
4881 : * @param pdfMin pointer to double value that will contain the lower bound of
4882 : * the histogram.
4883 : * @param pdfMax pointer to double value that will contain the upper bound of
4884 : * the histogram.
4885 : * @param pnBuckets pointer to int value that will contain the number of buckets
4886 : * in *ppanHistogram.
4887 : * @param ppanHistogram pointer to array into which the histogram totals are
4888 : * placed. To be freed with VSIFree
4889 : * @param bForce TRUE to force the computation. If FALSE and no default
4890 : * histogram is available, the method will return CE_Warning
4891 : * @param pfnProgress function to report progress to completion.
4892 : * @param pProgressData application data to pass to pfnProgress.
4893 : *
4894 : * @return CE_None on success, CE_Failure if something goes wrong, or
4895 : * CE_Warning if no default histogram is available.
4896 : */
4897 :
4898 27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4899 : int *pnBuckets,
4900 : GUIntBig **ppanHistogram, int bForce,
4901 : GDALProgressFunc pfnProgress,
4902 : void *pProgressData)
4903 :
4904 : {
4905 27 : CPLAssert(nullptr != pnBuckets);
4906 27 : CPLAssert(nullptr != ppanHistogram);
4907 27 : CPLAssert(nullptr != pdfMin);
4908 27 : CPLAssert(nullptr != pdfMax);
4909 :
4910 27 : *pnBuckets = 0;
4911 27 : *ppanHistogram = nullptr;
4912 :
4913 27 : if (!bForce)
4914 5 : return CE_Warning;
4915 :
4916 22 : int nBuckets = 256;
4917 :
4918 22 : bool bSignedByte = false;
4919 22 : if (eDataType == GDT_UInt8)
4920 : {
4921 20 : EnablePixelTypeSignedByteWarning(false);
4922 : const char *pszPixelType =
4923 20 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4924 20 : EnablePixelTypeSignedByteWarning(true);
4925 20 : bSignedByte =
4926 20 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4927 : }
4928 :
4929 22 : if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
4930 : {
4931 20 : *pdfMin = -0.5;
4932 20 : *pdfMax = 255.5;
4933 : }
4934 2 : else if (GetRasterDataType() == GDT_Int8)
4935 : {
4936 1 : *pdfMin = -128 - 0.5;
4937 1 : *pdfMax = 127 + 0.5;
4938 : }
4939 : else
4940 : {
4941 :
4942 : const CPLErr eErr =
4943 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4944 1 : if (eErr != CE_None)
4945 0 : return eErr;
4946 1 : if (*pdfMin == *pdfMax)
4947 : {
4948 1 : nBuckets = 1;
4949 1 : *pdfMin -= 0.5;
4950 1 : *pdfMax += 0.5;
4951 : }
4952 : else
4953 : {
4954 0 : const double dfHalfBucket =
4955 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4956 0 : *pdfMin -= dfHalfBucket;
4957 0 : *pdfMax += dfHalfBucket;
4958 : }
4959 : }
4960 :
4961 22 : *ppanHistogram =
4962 22 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4963 22 : if (*ppanHistogram == nullptr)
4964 : {
4965 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4966 : "Out of memory in 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 113835 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5129 : int /*nYSize*/, int /*nBufXSize*/,
5130 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5131 : char ** /*papszOptions*/)
5132 : {
5133 113835 : 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 1164 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5309 : {
5310 1164 : }
5311 :
5312 : public:
5313 776 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5314 : {
5315 : // Evaluates to just a single mul on x86_64
5316 776 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5317 : }
5318 :
5319 388 : GDALUInt128 operator-(const GDALUInt128 &other) const
5320 : {
5321 388 : return GDALUInt128(val - other.val);
5322 : }
5323 :
5324 379 : operator double() const
5325 : {
5326 379 : return static_cast<double>(val);
5327 : }
5328 : };
5329 : #else
5330 :
5331 : #if defined(_MSC_VER) && defined(_M_X64)
5332 : #include <intrin.h>
5333 : #endif
5334 :
5335 : class GDALUInt128
5336 : {
5337 : GUIntBig low, high;
5338 :
5339 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5340 : {
5341 : }
5342 :
5343 : public:
5344 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5345 : {
5346 : #if defined(_MSC_VER) && defined(_M_X64)
5347 : GUIntBig highRes;
5348 : GUIntBig lowRes = _umul128(first, second, &highRes);
5349 : return GDALUInt128(lowRes, highRes);
5350 : #else
5351 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5352 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5353 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5354 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5355 : GUIntBig highRes = 0;
5356 : const GUIntBig firstLowSecondHigh =
5357 : static_cast<GUIntBig>(firstLow) * secondHigh;
5358 : const GUIntBig firstHighSecondLow =
5359 : static_cast<GUIntBig>(firstHigh) * secondLow;
5360 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5361 : if (middleTerm < firstLowSecondHigh) // check for overflow
5362 : highRes += static_cast<GUIntBig>(1) << 32;
5363 : const GUIntBig firstLowSecondLow =
5364 : static_cast<GUIntBig>(firstLow) * secondLow;
5365 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5366 : if (lowRes < firstLowSecondLow) // check for overflow
5367 : highRes++;
5368 : highRes +=
5369 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5370 : return GDALUInt128(lowRes, highRes);
5371 : #endif
5372 : }
5373 :
5374 : GDALUInt128 operator-(const GDALUInt128 &other) const
5375 : {
5376 : GUIntBig highRes = high - other.high;
5377 : GUIntBig lowRes = low - other.low;
5378 : if (lowRes > low) // check for underflow
5379 : --highRes;
5380 : return GDALUInt128(lowRes, highRes);
5381 : }
5382 :
5383 : operator double() const
5384 : {
5385 : const double twoPow64 = 18446744073709551616.0;
5386 : return high * twoPow64 + low;
5387 : }
5388 : };
5389 : #endif
5390 :
5391 : /************************************************************************/
5392 : /* ComputeStatisticsInternal() */
5393 : /************************************************************************/
5394 :
5395 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5396 : // not needed.
5397 : #define static_cast_for_coverity_scan static_cast
5398 :
5399 : // The rationale for below optimizations is detailed in statistics.txt
5400 :
5401 : // Use with T = GByte or GUInt16 only !
5402 : template <class T, bool COMPUTE_OTHER_STATS>
5403 : struct ComputeStatisticsInternalGeneric
5404 : {
5405 251 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5406 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5407 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5408 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5409 : {
5410 : static_assert(std::is_same<T, GByte>::value ||
5411 : std::is_same<T, GUInt16>::value,
5412 : "bad type for T");
5413 251 : if (bHasNoData)
5414 : {
5415 : // General case
5416 608 : for (int iY = 0; iY < nYCheck; iY++)
5417 : {
5418 161753 : for (int iX = 0; iX < nXCheck; iX++)
5419 : {
5420 161269 : const GPtrDiff_t iOffset =
5421 161269 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5422 161269 : const GUInt32 nValue = pData[iOffset];
5423 161269 : if (nValue == nNoDataValue)
5424 319 : continue;
5425 160950 : if (nValue < nMin)
5426 34 : nMin = nValue;
5427 160950 : if (nValue > nMax)
5428 71 : nMax = nValue;
5429 : if constexpr (COMPUTE_OTHER_STATS)
5430 : {
5431 159314 : nValidCount++;
5432 159314 : nSum += nValue;
5433 159314 : nSumSquare +=
5434 159314 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5435 159314 : nValue;
5436 : }
5437 : }
5438 : }
5439 : if constexpr (COMPUTE_OTHER_STATS)
5440 : {
5441 40 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5442 : }
5443 : }
5444 145 : else if (nMin == std::numeric_limits<T>::lowest() &&
5445 18 : nMax == std::numeric_limits<T>::max())
5446 : {
5447 : if constexpr (COMPUTE_OTHER_STATS)
5448 : {
5449 : // Optimization when there is no nodata and we know we have already
5450 : // reached the min and max
5451 416 : for (int iY = 0; iY < nYCheck; iY++)
5452 : {
5453 : int iX;
5454 2004 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5455 : {
5456 1600 : const GPtrDiff_t iOffset =
5457 1600 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5458 1600 : const GUIntBig nValue = pData[iOffset];
5459 1600 : const GUIntBig nValue2 = pData[iOffset + 1];
5460 1600 : const GUIntBig nValue3 = pData[iOffset + 2];
5461 1600 : const GUIntBig nValue4 = pData[iOffset + 3];
5462 1600 : nSum += nValue;
5463 1600 : nSumSquare += nValue * nValue;
5464 1600 : nSum += nValue2;
5465 1600 : nSumSquare += nValue2 * nValue2;
5466 1600 : nSum += nValue3;
5467 1600 : nSumSquare += nValue3 * nValue3;
5468 1600 : nSum += nValue4;
5469 1600 : nSumSquare += nValue4 * nValue4;
5470 : }
5471 414 : for (; iX < nXCheck; ++iX)
5472 : {
5473 10 : const GPtrDiff_t iOffset =
5474 10 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5475 10 : const GUIntBig nValue = pData[iOffset];
5476 10 : nSum += nValue;
5477 10 : nSumSquare += nValue * nValue;
5478 : }
5479 : }
5480 12 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5481 12 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5482 : }
5483 : }
5484 : else
5485 : {
5486 6021 : for (int iY = 0; iY < nYCheck; iY++)
5487 : {
5488 : int iX;
5489 1270512 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5490 : {
5491 1264612 : const GPtrDiff_t iOffset =
5492 1264612 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5493 1264612 : const GUInt32 nValue = pData[iOffset];
5494 1264612 : const GUInt32 nValue2 = pData[iOffset + 1];
5495 1264612 : if (nValue < nValue2)
5496 : {
5497 2325 : if (nValue < nMin)
5498 51 : nMin = nValue;
5499 2325 : if (nValue2 > nMax)
5500 119 : nMax = nValue2;
5501 : }
5502 : else
5503 : {
5504 1262285 : if (nValue2 < nMin)
5505 67 : nMin = nValue2;
5506 1262285 : if (nValue > nMax)
5507 216 : nMax = nValue;
5508 : }
5509 : if constexpr (COMPUTE_OTHER_STATS)
5510 : {
5511 1257560 : nSum += nValue;
5512 1257560 : nSumSquare +=
5513 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5514 1257560 : nValue;
5515 1257560 : nSum += nValue2;
5516 1257560 : nSumSquare +=
5517 1257560 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5518 1257560 : nValue2;
5519 : }
5520 : }
5521 5906 : if (iX < nXCheck)
5522 : {
5523 27 : const GPtrDiff_t iOffset =
5524 27 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5525 27 : const GUInt32 nValue = pData[iOffset];
5526 27 : if (nValue < nMin)
5527 19 : nMin = nValue;
5528 27 : if (nValue > nMax)
5529 20 : nMax = nValue;
5530 : if (COMPUTE_OTHER_STATS)
5531 : {
5532 19 : nSum += nValue;
5533 19 : nSumSquare +=
5534 19 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5535 19 : nValue;
5536 : }
5537 : }
5538 : }
5539 : if constexpr (COMPUTE_OTHER_STATS)
5540 : {
5541 60 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5542 60 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5543 : }
5544 : }
5545 251 : }
5546 : };
5547 :
5548 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5549 : // using 64bit accumulators in internal loops. This also slightly helps in
5550 : // 64bit mode.
5551 : template <bool COMPUTE_OTHER_STATS>
5552 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5553 : {
5554 13738 : 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 13738 : int nOuterLoops = nXCheck / 65536;
5560 13738 : if (nXCheck % 65536)
5561 13747 : nOuterLoops++;
5562 :
5563 13738 : 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 20722797 : for (; iX < iMax; iX++)
5579 : {
5580 20709660 : const GPtrDiff_t iOffset =
5581 20709660 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5582 20709660 : const GUInt32 nValue = pData[iOffset];
5583 :
5584 20709660 : nSampleCount32bit++;
5585 20709660 : if (nValue == nNoDataValue)
5586 20353516 : continue;
5587 356089 : if (nValue < nMin)
5588 371 : nMin = nValue;
5589 356089 : if (nValue > nMax)
5590 834 : nMax = nValue;
5591 : if constexpr (COMPUTE_OTHER_STATS)
5592 : {
5593 32344 : nValidCount32bit++;
5594 32344 : nSum32bit += nValue;
5595 32344 : 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 3156 : 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 8461 : for (int iY = 0; iY < nYCheck; iY++)
5660 : {
5661 5337 : int iX = 0;
5662 10674 : for (int k = 0; k < nOuterLoops; k++)
5663 : {
5664 5337 : int iMax = iX + 65536;
5665 5337 : if (iMax > nXCheck)
5666 5337 : iMax = nXCheck;
5667 5337 : GUInt32 nSum32bit = 0;
5668 5337 : GUInt32 nSumSquare32bit = 0;
5669 285021 : for (; iX + 1 < iMax; iX += 2)
5670 : {
5671 279684 : const GPtrDiff_t iOffset =
5672 279684 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5673 279684 : const GUInt32 nValue = pData[iOffset];
5674 279684 : const GUInt32 nValue2 = pData[iOffset + 1];
5675 279684 : if (nValue < nValue2)
5676 : {
5677 8111 : if (nValue < nMin)
5678 234 : nMin = nValue;
5679 8111 : if (nValue2 > nMax)
5680 222 : nMax = nValue2;
5681 : }
5682 : else
5683 : {
5684 271573 : if (nValue2 < nMin)
5685 364 : nMin = nValue2;
5686 271573 : if (nValue > nMax)
5687 833 : nMax = nValue;
5688 : }
5689 : if constexpr (COMPUTE_OTHER_STATS)
5690 : {
5691 257546 : nSum32bit += nValue;
5692 257546 : nSumSquare32bit += nValue * nValue;
5693 257546 : nSum32bit += nValue2;
5694 257546 : nSumSquare32bit += nValue2 * nValue2;
5695 : }
5696 : }
5697 : if constexpr (COMPUTE_OTHER_STATS)
5698 : {
5699 2150 : nSum += nSum32bit;
5700 2150 : nSumSquare += nSumSquare32bit;
5701 : }
5702 : }
5703 5337 : 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 927 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5724 927 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5725 : }
5726 : }
5727 13738 : }
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 30262 : 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 30262 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5922 30262 : 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 28770 : 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 13747 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6158 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6159 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6160 : }
6161 30262 : }
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_UInt8:
6345 : {
6346 1400770 : if (bSignedByte)
6347 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6348 : else
6349 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6350 1400770 : break;
6351 : }
6352 617 : case GDT_Int8:
6353 617 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6354 617 : break;
6355 200608 : case GDT_UInt16:
6356 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6357 200608 : break;
6358 114437 : case GDT_Int16:
6359 114437 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6360 114437 : break;
6361 10454 : case GDT_UInt32:
6362 10454 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6363 10454 : break;
6364 140108 : case GDT_Int32:
6365 140108 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6366 140108 : break;
6367 36 : case GDT_UInt64:
6368 36 : dfValue = static_cast<double>(
6369 36 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6370 36 : break;
6371 3244 : case GDT_Int64:
6372 3244 : dfValue = static_cast<double>(
6373 3244 : static_cast<const std::int64_t *>(pData)[iOffset]);
6374 3244 : break;
6375 8 : case GDT_Float16:
6376 : {
6377 : using namespace std;
6378 8 : const GFloat16 hfValue =
6379 8 : static_cast<const GFloat16 *>(pData)[iOffset];
6380 14 : if (isnan(hfValue) ||
6381 6 : (sNoDataValues.bGotFloat16NoDataValue &&
6382 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6383 : {
6384 2 : bValid = false;
6385 2 : return 0.0;
6386 : }
6387 6 : dfValue = hfValue;
6388 6 : return dfValue;
6389 : }
6390 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 535 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6473 : GUIntBig nValidCount)
6474 : {
6475 535 : if (nValidCount == 0)
6476 : {
6477 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6478 : }
6479 523 : else if (nValidCount == nSampleCount)
6480 : {
6481 465 : 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 535 : }
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 513 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6911 : double *pdfMax, double *pdfMean,
6912 : double *pdfStdDev,
6913 : GDALProgressFunc pfnProgress,
6914 : void *pProgressData)
6915 :
6916 : {
6917 513 : if (pfnProgress == nullptr)
6918 183 : pfnProgress = GDALDummyProgress;
6919 :
6920 : /* -------------------------------------------------------------------- */
6921 : /* If we have overview bands, use them for statistics. */
6922 : /* -------------------------------------------------------------------- */
6923 513 : 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 510 : 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 510 : double dfMin = std::numeric_limits<double>::infinity();
6971 510 : double dfMax = -std::numeric_limits<double>::infinity();
6972 510 : double dfMean = 0.0;
6973 510 : double dfM2 = 0.0;
6974 :
6975 : GDALRasterIOExtraArg sExtraArg;
6976 510 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6977 :
6978 510 : GDALNoDataValues sNoDataValues(this, eDataType);
6979 510 : GDALRasterBand *poMaskBand = nullptr;
6980 510 : if (!sNoDataValues.bGotNoDataValue)
6981 : {
6982 477 : const int l_nMaskFlags = GetMaskFlags();
6983 523 : if (l_nMaskFlags != GMF_ALL_VALID &&
6984 46 : GetColorInterpretation() != GCI_AlphaBand)
6985 : {
6986 46 : poMaskBand = GetMaskBand();
6987 : }
6988 : }
6989 :
6990 510 : bool bSignedByte = false;
6991 510 : if (eDataType == GDT_UInt8)
6992 : {
6993 213 : EnablePixelTypeSignedByteWarning(false);
6994 : const char *pszPixelType =
6995 213 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6996 213 : EnablePixelTypeSignedByteWarning(true);
6997 213 : bSignedByte =
6998 213 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6999 : }
7000 :
7001 510 : GUIntBig nSampleCount = 0;
7002 510 : GUIntBig nValidCount = 0;
7003 :
7004 510 : 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_UInt8, 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 510 : if (!InitBlockInfo())
7104 243 : 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 510 : int nSampleRate = 1;
7113 510 : 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 510 : if (nSampleRate == 1)
7125 476 : bApproxOK = false;
7126 :
7127 : // Particular case for GDT_UInt8 and GUInt16 that only use integral types
7128 : // for each block, and possibly for the whole raster.
7129 510 : if (!poMaskBand && ((eDataType == GDT_UInt8 && !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 439 : ((eDataType == GDT_UInt8 &&
7140 196 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
7141 196 : nSampleRate <
7142 196 : GUINTBIG_MAX / (255U * 255U) /
7143 196 : (static_cast<GUInt64>(nBlockXSize) *
7144 196 : 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 533 : 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 243 : CPLTestBool(
7154 243 : CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
7155 :
7156 243 : const GUInt32 nMaxValueType =
7157 243 : (eDataType == GDT_UInt8) ? 255 : 65535;
7158 243 : GUInt32 nMin = nMaxValueType;
7159 243 : GUInt32 nMax = 0;
7160 243 : GUIntBig nSum = 0;
7161 243 : GUIntBig nSumSquare = 0;
7162 : // If no valid nodata, map to invalid value (256 for Byte)
7163 243 : const GUInt32 nNoDataValue =
7164 270 : (sNoDataValues.bGotNoDataValue &&
7165 27 : sNoDataValues.dfNoDataValue >= 0 &&
7166 27 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
7167 27 : fabs(sNoDataValues.dfNoDataValue -
7168 27 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
7169 : 1e-10)) < 1e-10)
7170 270 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
7171 : : nMaxValueType + 1;
7172 :
7173 243 : for (GIntBig iSampleBlock = 0;
7174 13082 : iSampleBlock <
7175 13082 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7176 12839 : iSampleBlock += nSampleRate)
7177 : {
7178 12839 : const int iYBlock =
7179 12839 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7180 12839 : const int iXBlock =
7181 12839 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7182 :
7183 : GDALRasterBlock *const poBlock =
7184 12839 : GetLockedBlockRef(iXBlock, iYBlock);
7185 12839 : if (poBlock == nullptr)
7186 0 : return CE_Failure;
7187 :
7188 12839 : void *const pData = poBlock->GetDataRef();
7189 :
7190 12838 : int nXCheck = 0, nYCheck = 0;
7191 12838 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7192 :
7193 12839 : GUIntBig nBlockSum = 0;
7194 12839 : GUIntBig nBlockSumSquare = 0;
7195 12839 : GUIntBig nBlockSampleCount = 0;
7196 12839 : GUIntBig nBlockValidCount = 0;
7197 12839 : GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
7198 12839 : GUIntBig &nBlockSumSquareRef =
7199 : bIntegerStats ? nSumSquare : nBlockSumSquare;
7200 12839 : GUIntBig &nBlockSampleCountRef =
7201 : bIntegerStats ? nSampleCount : nBlockSampleCount;
7202 12839 : GUIntBig &nBlockValidCountRef =
7203 : bIntegerStats ? nValidCount : nBlockValidCount;
7204 :
7205 12839 : if (eDataType == GDT_UInt8)
7206 : {
7207 : ComputeStatisticsInternal<
7208 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
7209 12157 : f(nXCheck, nBlockXSize, nYCheck,
7210 : static_cast<const GByte *>(pData),
7211 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7212 : nMax, nBlockSumRef, nBlockSumSquareRef,
7213 : nBlockSampleCountRef, nBlockValidCountRef);
7214 : }
7215 : else
7216 : {
7217 : ComputeStatisticsInternal<
7218 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
7219 682 : f(nXCheck, nBlockXSize, nYCheck,
7220 : static_cast<const GUInt16 *>(pData),
7221 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
7222 : nMax, nBlockSumRef, nBlockSumSquareRef,
7223 : nBlockSampleCountRef, nBlockValidCountRef);
7224 : }
7225 :
7226 12839 : poBlock->DropLock();
7227 :
7228 12839 : if (!bIntegerStats)
7229 : {
7230 169 : nSampleCount += nBlockSampleCount;
7231 169 : if (nBlockValidCount)
7232 : {
7233 : // Update the global mean and M2 (the difference of the
7234 : // square to the mean) from the values of the block
7235 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7236 169 : const double dfBlockValidCount =
7237 169 : static_cast<double>(nBlockValidCount);
7238 169 : const double dfBlockMean =
7239 169 : static_cast<double>(nBlockSum) / dfBlockValidCount;
7240 : const double dfBlockM2 =
7241 169 : static_cast<double>(
7242 169 : GDALUInt128::Mul(nBlockSumSquare,
7243 169 : nBlockValidCount) -
7244 338 : GDALUInt128::Mul(nBlockSum, nBlockSum)) /
7245 169 : dfBlockValidCount;
7246 169 : const double dfDelta = dfBlockMean - dfMean;
7247 169 : const auto nNewValidCount =
7248 169 : nValidCount + nBlockValidCount;
7249 169 : const double dfNewValidCount =
7250 : static_cast<double>(nNewValidCount);
7251 169 : dfMean +=
7252 169 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7253 169 : dfM2 +=
7254 169 : dfBlockM2 + dfDelta * dfDelta *
7255 169 : static_cast<double>(nValidCount) *
7256 169 : dfBlockValidCount / dfNewValidCount;
7257 169 : nValidCount = nNewValidCount;
7258 : }
7259 : }
7260 :
7261 12839 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
7262 12839 : (static_cast<double>(nBlocksPerRow) *
7263 12839 : nBlocksPerColumn),
7264 : "Compute Statistics", pProgressData))
7265 : {
7266 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
7267 : "User terminated");
7268 0 : return CE_Failure;
7269 : }
7270 : }
7271 :
7272 243 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7273 : {
7274 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7275 0 : return CE_Failure;
7276 : }
7277 :
7278 243 : double dfStdDev = 0;
7279 243 : if (bIntegerStats)
7280 : {
7281 219 : if (nValidCount)
7282 210 : dfMean = static_cast<double>(nSum) / nValidCount;
7283 :
7284 : // To avoid potential precision issues when doing the difference,
7285 : // we need to do that computation on 128 bit rather than casting
7286 : // to double
7287 : const GDALUInt128 nTmpForStdDev(
7288 219 : GDALUInt128::Mul(nSumSquare, nValidCount) -
7289 438 : GDALUInt128::Mul(nSum, nSum));
7290 219 : dfStdDev =
7291 219 : nValidCount > 0
7292 219 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
7293 : : 0.0;
7294 : }
7295 24 : else if (nValidCount > 0)
7296 : {
7297 24 : dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
7298 : }
7299 :
7300 : /// Save computed information
7301 243 : if (nValidCount > 0)
7302 : {
7303 234 : if (bApproxOK)
7304 : {
7305 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7306 : }
7307 210 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7308 : {
7309 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7310 : }
7311 234 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
7312 : }
7313 :
7314 243 : SetValidPercent(nSampleCount, nValidCount);
7315 :
7316 : /* --------------------------------------------------------------------
7317 : */
7318 : /* Record results. */
7319 : /* --------------------------------------------------------------------
7320 : */
7321 243 : if (pdfMin != nullptr)
7322 240 : *pdfMin = nValidCount ? nMin : 0;
7323 243 : if (pdfMax != nullptr)
7324 240 : *pdfMax = nValidCount ? nMax : 0;
7325 :
7326 243 : if (pdfMean != nullptr)
7327 236 : *pdfMean = dfMean;
7328 :
7329 243 : if (pdfStdDev != nullptr)
7330 236 : *pdfStdDev = dfStdDev;
7331 :
7332 243 : if (nValidCount > 0)
7333 234 : return CE_None;
7334 :
7335 9 : ReportError(CE_Failure, CPLE_AppDefined,
7336 : "Failed to compute statistics, no valid pixels found "
7337 : "in sampling.");
7338 9 : return CE_Failure;
7339 : }
7340 :
7341 267 : GByte *pabyMaskData = nullptr;
7342 267 : if (poMaskBand)
7343 : {
7344 : pabyMaskData = static_cast<GByte *>(
7345 46 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7346 46 : if (!pabyMaskData)
7347 : {
7348 0 : return CE_Failure;
7349 : }
7350 : }
7351 :
7352 267 : float fMin = std::numeric_limits<float>::infinity();
7353 267 : float fMax = -std::numeric_limits<float>::infinity();
7354 : const bool bFloat32Optim =
7355 44 : eDataType == GDT_Float32 && !pabyMaskData &&
7356 329 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7357 18 : CPLTestBool(
7358 267 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
7359 :
7360 : #if (defined(__x86_64__) || defined(_M_X64))
7361 : const bool bFloat64Optim =
7362 13 : eDataType == GDT_Float64 && !pabyMaskData &&
7363 293 : nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
7364 13 : CPLTestBool(
7365 267 : CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
7366 : #endif
7367 :
7368 267 : for (GIntBig iSampleBlock = 0;
7369 5918 : iSampleBlock <
7370 5918 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7371 5651 : iSampleBlock += nSampleRate)
7372 : {
7373 5651 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7374 5651 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7375 :
7376 5651 : int nXCheck = 0, nYCheck = 0;
7377 5651 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7378 :
7379 6224 : if (poMaskBand &&
7380 573 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7381 573 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7382 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
7383 573 : 0, nBlockXSize, nullptr) != CE_None)
7384 : {
7385 0 : CPLFree(pabyMaskData);
7386 0 : return CE_Failure;
7387 : }
7388 :
7389 : GDALRasterBlock *const poBlock =
7390 5651 : GetLockedBlockRef(iXBlock, iYBlock);
7391 5651 : if (poBlock == nullptr)
7392 : {
7393 0 : CPLFree(pabyMaskData);
7394 0 : return CE_Failure;
7395 : }
7396 :
7397 5651 : const void *const pData = poBlock->GetDataRef();
7398 :
7399 5651 : if (bFloat32Optim)
7400 : {
7401 2330 : const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
7402 0 : !std::isnan(sNoDataValues.fNoDataValue);
7403 2330 : float fBlockMean = 0.0f;
7404 2330 : float fBlockM2 = 0.0f;
7405 2330 : int nBlockValidCount = 0;
7406 7219 : for (int iY = 0; iY < nYCheck; iY++)
7407 : {
7408 4889 : const int iOffset = iY * nBlockXSize;
7409 4889 : if (nBlockValidCount && fMin != fMax)
7410 : {
7411 2432 : int iX = 0;
7412 : #if (defined(__x86_64__) || defined(_M_X64))
7413 2432 : if (bHasNoData)
7414 : {
7415 : iX = ComputeStatisticsFloat32_SSE2<
7416 : /* bCheckMinEqMax = */ false,
7417 0 : /* bHasNoData = */ true>(
7418 0 : static_cast<const float *>(pData) + iOffset,
7419 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7420 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7421 : }
7422 : else
7423 : {
7424 : iX = ComputeStatisticsFloat32_SSE2<
7425 : /* bCheckMinEqMax = */ false,
7426 2432 : /* bHasNoData = */ false>(
7427 2432 : static_cast<const float *>(pData) + iOffset,
7428 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7429 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7430 : }
7431 : #endif
7432 2961 : for (; iX < nXCheck; iX++)
7433 : {
7434 529 : const float fValue =
7435 529 : static_cast<const float *>(pData)[iOffset + iX];
7436 529 : if (std::isnan(fValue) ||
7437 0 : (bHasNoData &&
7438 0 : fValue == sNoDataValues.fNoDataValue))
7439 11 : continue;
7440 518 : fMin = std::min(fMin, fValue);
7441 518 : fMax = std::max(fMax, fValue);
7442 518 : ++nBlockValidCount;
7443 518 : const float fDelta = fValue - fBlockMean;
7444 518 : fBlockMean +=
7445 518 : fDelta / static_cast<float>(nBlockValidCount);
7446 518 : fBlockM2 += fDelta * (fValue - fBlockMean);
7447 2432 : }
7448 : }
7449 : else
7450 : {
7451 2457 : int iX = 0;
7452 2457 : if (nBlockValidCount == 0)
7453 : {
7454 2330 : for (; iX < nXCheck; iX++)
7455 : {
7456 2330 : const float fValue = static_cast<const float *>(
7457 2330 : pData)[iOffset + iX];
7458 2330 : if (std::isnan(fValue) ||
7459 0 : (bHasNoData &&
7460 0 : fValue == sNoDataValues.fNoDataValue))
7461 0 : continue;
7462 2330 : fMin = std::min(fMin, fValue);
7463 2330 : fMax = std::max(fMax, fValue);
7464 2330 : nBlockValidCount = 1;
7465 2330 : fBlockMean = fValue;
7466 2330 : iX++;
7467 2330 : break;
7468 : }
7469 : }
7470 : #if (defined(__x86_64__) || defined(_M_X64))
7471 2457 : if (bHasNoData)
7472 : {
7473 : iX = ComputeStatisticsFloat32_SSE2<
7474 : /* bCheckMinEqMax = */ true,
7475 0 : /* bHasNoData = */ true>(
7476 0 : static_cast<const float *>(pData) + iOffset,
7477 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7478 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7479 : }
7480 : else
7481 : {
7482 : iX = ComputeStatisticsFloat32_SSE2<
7483 : /* bCheckMinEqMax = */ true,
7484 2457 : /* bHasNoData = */ false>(
7485 2457 : static_cast<const float *>(pData) + iOffset,
7486 : sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
7487 : fMax, fBlockMean, fBlockM2, nBlockValidCount);
7488 : }
7489 : #endif
7490 17534 : for (; iX < nXCheck; iX++)
7491 : {
7492 15077 : const float fValue =
7493 15077 : static_cast<const float *>(pData)[iOffset + iX];
7494 15077 : if (std::isnan(fValue) ||
7495 0 : (bHasNoData &&
7496 0 : fValue == sNoDataValues.fNoDataValue))
7497 1 : continue;
7498 15076 : fMin = std::min(fMin, fValue);
7499 15076 : fMax = std::max(fMax, fValue);
7500 15076 : ++nBlockValidCount;
7501 15076 : if (fMin != fMax)
7502 : {
7503 7123 : const float fDelta = fValue - fBlockMean;
7504 7123 : fBlockMean += fDelta / static_cast<float>(
7505 : nBlockValidCount);
7506 7123 : fBlockM2 += fDelta * (fValue - fBlockMean);
7507 : }
7508 : }
7509 : }
7510 : }
7511 :
7512 2330 : if (nBlockValidCount)
7513 : {
7514 : // Update the global mean and M2 (the difference of the
7515 : // square to the mean) from the values of the block
7516 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7517 2330 : const auto nNewValidCount = nValidCount + nBlockValidCount;
7518 2330 : const double dfBlockMean = static_cast<double>(fBlockMean);
7519 2330 : if (dfBlockMean != dfMean)
7520 : {
7521 1066 : const double dfBlockM2 = static_cast<double>(fBlockM2);
7522 1066 : if (nValidCount == 0)
7523 : {
7524 13 : dfMean = dfBlockMean;
7525 13 : dfM2 = dfBlockM2;
7526 : }
7527 : else
7528 : {
7529 1053 : const double dfBlockValidCount =
7530 1053 : static_cast<double>(nBlockValidCount);
7531 1053 : const double dfDelta = dfBlockMean - dfMean;
7532 1053 : const double dfNewValidCount =
7533 : static_cast<double>(nNewValidCount);
7534 1053 : dfMean +=
7535 1053 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7536 1053 : dfM2 += dfBlockM2 +
7537 1053 : dfDelta * dfDelta *
7538 1053 : static_cast<double>(nValidCount) *
7539 1053 : dfBlockValidCount / dfNewValidCount;
7540 : }
7541 : }
7542 2330 : nValidCount = nNewValidCount;
7543 : }
7544 : }
7545 :
7546 : #if (defined(__x86_64__) || defined(_M_X64))
7547 3321 : else if (bFloat64Optim)
7548 : {
7549 : const bool bHasNoData =
7550 545 : sNoDataValues.bGotNoDataValue &&
7551 263 : !std::isnan(sNoDataValues.dfNoDataValue);
7552 282 : double dfBlockMean = 0;
7553 282 : double dfBlockM2 = 0;
7554 282 : double dfBlockValidCount = 0;
7555 1633 : for (int iY = 0; iY < nYCheck; iY++)
7556 : {
7557 1351 : const int iOffset = iY * nBlockXSize;
7558 1351 : if (dfBlockValidCount != 0 && dfMin != dfMax)
7559 : {
7560 813 : int iX = 0;
7561 813 : if (bHasNoData)
7562 : {
7563 : iX = ComputeStatisticsFloat64_SSE2<
7564 : /* bCheckMinEqMax = */ false,
7565 381 : /* bHasNoData = */ true>(
7566 381 : static_cast<const double *>(pData) + iOffset,
7567 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7568 : dfMax, dfBlockMean, dfBlockM2,
7569 : dfBlockValidCount);
7570 : }
7571 : else
7572 : {
7573 : iX = ComputeStatisticsFloat64_SSE2<
7574 : /* bCheckMinEqMax = */ false,
7575 432 : /* bHasNoData = */ false>(
7576 432 : static_cast<const double *>(pData) + iOffset,
7577 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7578 : dfMax, dfBlockMean, dfBlockM2,
7579 : dfBlockValidCount);
7580 : }
7581 1931 : for (; iX < nXCheck; iX++)
7582 : {
7583 1118 : const double dfValue = static_cast<const double *>(
7584 1118 : pData)[iOffset + iX];
7585 1625 : if (std::isnan(dfValue) ||
7586 507 : (bHasNoData &&
7587 507 : dfValue == sNoDataValues.dfNoDataValue))
7588 53 : continue;
7589 1065 : dfMin = std::min(dfMin, dfValue);
7590 1065 : dfMax = std::max(dfMax, dfValue);
7591 1065 : dfBlockValidCount += 1.0;
7592 1065 : const double dfDelta = dfValue - dfBlockMean;
7593 1065 : dfBlockMean += dfDelta / dfBlockValidCount;
7594 1065 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7595 813 : }
7596 : }
7597 : else
7598 : {
7599 538 : int iX = 0;
7600 538 : if (dfBlockValidCount == 0)
7601 : {
7602 7661 : for (; iX < nXCheck; iX++)
7603 : {
7604 7627 : const double dfValue =
7605 : static_cast<const double *>(
7606 7627 : pData)[iOffset + iX];
7607 15235 : if (std::isnan(dfValue) ||
7608 7608 : (bHasNoData &&
7609 7608 : dfValue == sNoDataValues.dfNoDataValue))
7610 7377 : continue;
7611 250 : dfMin = std::min(dfMin, dfValue);
7612 250 : dfMax = std::max(dfMax, dfValue);
7613 250 : dfBlockValidCount = 1;
7614 250 : dfBlockMean = dfValue;
7615 250 : iX++;
7616 250 : break;
7617 : }
7618 : }
7619 538 : if (bHasNoData)
7620 : {
7621 : iX = ComputeStatisticsFloat64_SSE2<
7622 : /* bCheckMinEqMax = */ true,
7623 392 : /* bHasNoData = */ true>(
7624 392 : static_cast<const double *>(pData) + iOffset,
7625 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7626 : dfMax, dfBlockMean, dfBlockM2,
7627 : dfBlockValidCount);
7628 : }
7629 : else
7630 : {
7631 : iX = ComputeStatisticsFloat64_SSE2<
7632 : /* bCheckMinEqMax = */ true,
7633 146 : /* bHasNoData = */ false>(
7634 146 : static_cast<const double *>(pData) + iOffset,
7635 : sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
7636 : dfMax, dfBlockMean, dfBlockM2,
7637 : dfBlockValidCount);
7638 : }
7639 1081 : for (; iX < nXCheck; iX++)
7640 : {
7641 543 : const double dfValue = static_cast<const double *>(
7642 543 : pData)[iOffset + iX];
7643 1065 : if (std::isnan(dfValue) ||
7644 522 : (bHasNoData &&
7645 522 : dfValue == sNoDataValues.dfNoDataValue))
7646 140 : continue;
7647 403 : dfMin = std::min(dfMin, dfValue);
7648 403 : dfMax = std::max(dfMax, dfValue);
7649 403 : dfBlockValidCount += 1.0;
7650 403 : if (dfMin != dfMax)
7651 : {
7652 128 : const double dfDelta = dfValue - dfBlockMean;
7653 128 : dfBlockMean += dfDelta / dfBlockValidCount;
7654 128 : dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
7655 : }
7656 : }
7657 : }
7658 : }
7659 :
7660 282 : if (dfBlockValidCount > 0)
7661 : {
7662 : // Update the global mean and M2 (the difference of the
7663 : // square to the mean) from the values of the block
7664 : // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
7665 250 : const auto nNewValidCount =
7666 250 : nValidCount + static_cast<int>(dfBlockValidCount);
7667 250 : if (dfBlockMean != dfMean)
7668 : {
7669 237 : if (nValidCount == 0)
7670 : {
7671 11 : dfMean = dfBlockMean;
7672 11 : dfM2 = dfBlockM2;
7673 : }
7674 : else
7675 : {
7676 226 : const double dfDelta = dfBlockMean - dfMean;
7677 226 : const double dfNewValidCount =
7678 : static_cast<double>(nNewValidCount);
7679 226 : dfMean +=
7680 226 : dfDelta * (dfBlockValidCount / dfNewValidCount);
7681 226 : dfM2 += dfBlockM2 +
7682 226 : dfDelta * dfDelta *
7683 226 : static_cast<double>(nValidCount) *
7684 226 : dfBlockValidCount / dfNewValidCount;
7685 : }
7686 : }
7687 250 : nValidCount = nNewValidCount;
7688 : }
7689 : }
7690 : #endif // (defined(__x86_64__) || defined(_M_X64))
7691 :
7692 : else
7693 : {
7694 : // This isn't the fastest way to do this, but is easier for now.
7695 8754 : for (int iY = 0; iY < nYCheck; iY++)
7696 : {
7697 5715 : if (nValidCount && dfMin != dfMax)
7698 : {
7699 212546 : for (int iX = 0; iX < nXCheck; iX++)
7700 : {
7701 209962 : const GPtrDiff_t iOffset =
7702 209962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7703 209962 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7704 9635 : continue;
7705 :
7706 200339 : bool bValid = true;
7707 : double dfValue =
7708 200339 : GetPixelValue(eDataType, bSignedByte, pData,
7709 200339 : iOffset, sNoDataValues, bValid);
7710 :
7711 200339 : if (!bValid)
7712 12 : continue;
7713 :
7714 200327 : dfMin = std::min(dfMin, dfValue);
7715 200327 : dfMax = std::max(dfMax, dfValue);
7716 :
7717 200327 : nValidCount++;
7718 200327 : const double dfDelta = dfValue - dfMean;
7719 200327 : dfMean += dfDelta / nValidCount;
7720 200327 : dfM2 += dfDelta * (dfValue - dfMean);
7721 2584 : }
7722 : }
7723 : else
7724 : {
7725 3131 : int iX = 0;
7726 3131 : if (nValidCount == 0)
7727 : {
7728 94577 : for (; iX < nXCheck; iX++)
7729 : {
7730 94520 : const GPtrDiff_t iOffset =
7731 94520 : iX +
7732 94520 : static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7733 94520 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7734 94282 : continue;
7735 :
7736 239 : bool bValid = true;
7737 239 : double dfValue = GetPixelValue(
7738 : eDataType, bSignedByte, pData, iOffset,
7739 : sNoDataValues, bValid);
7740 :
7741 239 : if (!bValid)
7742 1 : continue;
7743 :
7744 238 : dfMin = dfValue;
7745 238 : dfMax = dfValue;
7746 238 : dfMean = dfValue;
7747 238 : nValidCount = 1;
7748 238 : iX++;
7749 238 : break;
7750 : }
7751 : }
7752 227675 : for (; iX < nXCheck; iX++)
7753 : {
7754 224544 : const GPtrDiff_t iOffset =
7755 224544 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7756 224544 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7757 358 : continue;
7758 :
7759 224187 : bool bValid = true;
7760 : double dfValue =
7761 224187 : GetPixelValue(eDataType, bSignedByte, pData,
7762 224187 : iOffset, sNoDataValues, bValid);
7763 :
7764 224187 : if (!bValid)
7765 1 : continue;
7766 :
7767 224186 : dfMin = std::min(dfMin, dfValue);
7768 224186 : dfMax = std::max(dfMax, dfValue);
7769 :
7770 224186 : nValidCount++;
7771 224186 : if (dfMin != dfMax)
7772 : {
7773 2170 : const double dfDelta = dfValue - dfMean;
7774 2170 : dfMean += dfDelta / nValidCount;
7775 2170 : dfM2 += dfDelta * (dfValue - dfMean);
7776 : }
7777 : }
7778 : }
7779 : }
7780 : }
7781 :
7782 5651 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
7783 :
7784 5651 : poBlock->DropLock();
7785 :
7786 5651 : if (!pfnProgress(
7787 5651 : static_cast<double>(iSampleBlock) /
7788 5651 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
7789 : "Compute Statistics", pProgressData))
7790 : {
7791 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7792 0 : CPLFree(pabyMaskData);
7793 0 : return CE_Failure;
7794 : }
7795 : }
7796 :
7797 267 : if (bFloat32Optim)
7798 : {
7799 17 : dfMin = static_cast<double>(fMin);
7800 17 : dfMax = static_cast<double>(fMax);
7801 : }
7802 267 : CPLFree(pabyMaskData);
7803 : }
7804 :
7805 267 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7806 : {
7807 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7808 0 : return CE_Failure;
7809 : }
7810 :
7811 : /* -------------------------------------------------------------------- */
7812 : /* Save computed information. */
7813 : /* -------------------------------------------------------------------- */
7814 267 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7815 :
7816 267 : if (nValidCount > 0)
7817 : {
7818 266 : if (bApproxOK)
7819 : {
7820 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7821 : }
7822 258 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7823 : {
7824 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7825 : }
7826 266 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7827 : }
7828 : else
7829 : {
7830 1 : dfMin = 0.0;
7831 1 : dfMax = 0.0;
7832 : }
7833 :
7834 267 : SetValidPercent(nSampleCount, nValidCount);
7835 :
7836 : /* -------------------------------------------------------------------- */
7837 : /* Record results. */
7838 : /* -------------------------------------------------------------------- */
7839 267 : if (pdfMin != nullptr)
7840 264 : *pdfMin = dfMin;
7841 267 : if (pdfMax != nullptr)
7842 264 : *pdfMax = dfMax;
7843 :
7844 267 : if (pdfMean != nullptr)
7845 261 : *pdfMean = dfMean;
7846 :
7847 267 : if (pdfStdDev != nullptr)
7848 261 : *pdfStdDev = dfStdDev;
7849 :
7850 267 : if (nValidCount > 0)
7851 266 : return CE_None;
7852 :
7853 1 : ReportError(
7854 : CE_Failure, CPLE_AppDefined,
7855 : "Failed to compute statistics, no valid pixels found in sampling.");
7856 1 : return CE_Failure;
7857 : }
7858 :
7859 : /************************************************************************/
7860 : /* GDALComputeRasterStatistics() */
7861 : /************************************************************************/
7862 :
7863 : /**
7864 : * \brief Compute image statistics.
7865 : *
7866 : * @see GDALRasterBand::ComputeStatistics()
7867 : */
7868 :
7869 169 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7870 : int bApproxOK, double *pdfMin,
7871 : double *pdfMax, double *pdfMean,
7872 : double *pdfStdDev,
7873 : GDALProgressFunc pfnProgress,
7874 : void *pProgressData)
7875 :
7876 : {
7877 169 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7878 :
7879 169 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7880 :
7881 169 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7882 169 : pdfStdDev, pfnProgress, pProgressData);
7883 : }
7884 :
7885 : /************************************************************************/
7886 : /* SetStatistics() */
7887 : /************************************************************************/
7888 :
7889 : /**
7890 : * \brief Set statistics on band.
7891 : *
7892 : * This method can be used to store min/max/mean/standard deviation
7893 : * statistics on a raster band.
7894 : *
7895 : * The default implementation stores them as metadata, and will only work
7896 : * on formats that can save arbitrary metadata. This method cannot detect
7897 : * whether metadata will be properly saved and so may return CE_None even
7898 : * if the statistics will never be saved.
7899 : *
7900 : * This method is the same as the C function GDALSetRasterStatistics().
7901 : *
7902 : * @param dfMin minimum pixel value.
7903 : *
7904 : * @param dfMax maximum pixel value.
7905 : *
7906 : * @param dfMean mean (average) of all pixel values.
7907 : *
7908 : * @param dfStdDev Standard deviation of all pixel values.
7909 : *
7910 : * @return CE_None on success or CE_Failure on failure.
7911 : */
7912 :
7913 533 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7914 : double dfStdDev)
7915 :
7916 : {
7917 533 : char szValue[128] = {0};
7918 :
7919 533 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7920 533 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7921 :
7922 533 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7923 533 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7924 :
7925 533 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7926 533 : SetMetadataItem("STATISTICS_MEAN", szValue);
7927 :
7928 533 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7929 533 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7930 :
7931 533 : return CE_None;
7932 : }
7933 :
7934 : /************************************************************************/
7935 : /* GDALSetRasterStatistics() */
7936 : /************************************************************************/
7937 :
7938 : /**
7939 : * \brief Set statistics on band.
7940 : *
7941 : * @see GDALRasterBand::SetStatistics()
7942 : */
7943 :
7944 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7945 : double dfMax, double dfMean,
7946 : double dfStdDev)
7947 :
7948 : {
7949 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7950 :
7951 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7952 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7953 : }
7954 :
7955 : /************************************************************************/
7956 : /* ComputeRasterMinMax() */
7957 : /************************************************************************/
7958 :
7959 : template <class T, bool HAS_NODATA>
7960 2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7961 : T *pMax)
7962 : {
7963 2 : T min0 = *pMin;
7964 2 : T max0 = *pMax;
7965 2 : T min1 = *pMin;
7966 2 : T max1 = *pMax;
7967 : size_t i;
7968 2 : for (i = 0; i + 1 < nElts; i += 2)
7969 : {
7970 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
7971 : {
7972 0 : min0 = std::min(min0, buffer[i]);
7973 0 : max0 = std::max(max0, buffer[i]);
7974 : }
7975 0 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7976 : {
7977 0 : min1 = std::min(min1, buffer[i + 1]);
7978 0 : max1 = std::max(max1, buffer[i + 1]);
7979 : }
7980 : }
7981 2 : T min = std::min(min0, min1);
7982 2 : T max = std::max(max0, max1);
7983 2 : if (i < nElts)
7984 : {
7985 0 : if (!HAS_NODATA || buffer[i] != nodataValue)
7986 : {
7987 2 : min = std::min(min, buffer[i]);
7988 2 : max = std::max(max, buffer[i]);
7989 : }
7990 : }
7991 2 : *pMin = min;
7992 2 : *pMax = max;
7993 2 : }
7994 :
7995 : template <GDALDataType eDataType, bool bSignedByte>
7996 : static void
7997 6703 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7998 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7999 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
8000 : {
8001 6703 : double dfLocalMin = dfMin;
8002 6703 : double dfLocalMax = dfMax;
8003 :
8004 22051 : for (int iY = 0; iY < nYCheck; iY++)
8005 : {
8006 14858421 : for (int iX = 0; iX < nXCheck; iX++)
8007 : {
8008 14843085 : const GPtrDiff_t iOffset =
8009 14843085 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8010 14843085 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8011 109836 : continue;
8012 14760102 : bool bValid = true;
8013 14760102 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
8014 : iOffset, sNoDataValues, bValid);
8015 14760102 : if (!bValid)
8016 26871 : continue;
8017 :
8018 14733202 : dfLocalMin = std::min(dfLocalMin, dfValue);
8019 14733202 : dfLocalMax = std::max(dfLocalMax, dfValue);
8020 : }
8021 : }
8022 :
8023 6703 : dfMin = dfLocalMin;
8024 6703 : dfMax = dfLocalMax;
8025 6703 : }
8026 :
8027 6703 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
8028 : bool bSignedByte, int nXCheck, int nYCheck,
8029 : int nBlockXSize,
8030 : const GDALNoDataValues &sNoDataValues,
8031 : const GByte *pabyMaskData, double &dfMin,
8032 : double &dfMax)
8033 : {
8034 6703 : switch (eDataType)
8035 : {
8036 0 : case GDT_Unknown:
8037 0 : CPLAssert(false);
8038 : break;
8039 660 : case GDT_UInt8:
8040 660 : if (bSignedByte)
8041 : {
8042 3 : ComputeMinMaxGeneric<GDT_UInt8, true>(
8043 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8044 : pabyMaskData, dfMin, dfMax);
8045 : }
8046 : else
8047 : {
8048 657 : ComputeMinMaxGeneric<GDT_UInt8, false>(
8049 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8050 : pabyMaskData, dfMin, dfMax);
8051 : }
8052 660 : break;
8053 4 : case GDT_Int8:
8054 4 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
8055 : nBlockXSize, sNoDataValues,
8056 : pabyMaskData, dfMin, dfMax);
8057 4 : break;
8058 969 : case GDT_UInt16:
8059 969 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
8060 : nBlockXSize, sNoDataValues,
8061 : pabyMaskData, dfMin, dfMax);
8062 969 : break;
8063 2 : case GDT_Int16:
8064 2 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
8065 : nBlockXSize, sNoDataValues,
8066 : pabyMaskData, dfMin, dfMax);
8067 2 : break;
8068 3 : case GDT_UInt32:
8069 3 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
8070 : nBlockXSize, sNoDataValues,
8071 : pabyMaskData, dfMin, dfMax);
8072 3 : break;
8073 3 : case GDT_Int32:
8074 3 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
8075 : nBlockXSize, sNoDataValues,
8076 : pabyMaskData, dfMin, dfMax);
8077 3 : break;
8078 4 : case GDT_UInt64:
8079 4 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
8080 : nBlockXSize, sNoDataValues,
8081 : pabyMaskData, dfMin, dfMax);
8082 4 : break;
8083 4 : case GDT_Int64:
8084 4 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
8085 : nBlockXSize, sNoDataValues,
8086 : pabyMaskData, dfMin, dfMax);
8087 4 : break;
8088 2 : case GDT_Float16:
8089 2 : ComputeMinMaxGeneric<GDT_Float16, false>(
8090 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8091 : pabyMaskData, dfMin, dfMax);
8092 2 : break;
8093 4941 : case GDT_Float32:
8094 4941 : ComputeMinMaxGeneric<GDT_Float32, false>(
8095 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8096 : pabyMaskData, dfMin, dfMax);
8097 4941 : break;
8098 1 : case GDT_Float64:
8099 1 : ComputeMinMaxGeneric<GDT_Float64, false>(
8100 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8101 : pabyMaskData, dfMin, dfMax);
8102 1 : break;
8103 9 : case GDT_CInt16:
8104 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
8105 : nBlockXSize, sNoDataValues,
8106 : pabyMaskData, dfMin, dfMax);
8107 9 : break;
8108 9 : case GDT_CInt32:
8109 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
8110 : nBlockXSize, sNoDataValues,
8111 : pabyMaskData, dfMin, dfMax);
8112 9 : break;
8113 0 : case GDT_CFloat16:
8114 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
8115 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8116 : pabyMaskData, dfMin, dfMax);
8117 0 : break;
8118 75 : case GDT_CFloat32:
8119 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
8120 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8121 : pabyMaskData, dfMin, dfMax);
8122 75 : break;
8123 17 : case GDT_CFloat64:
8124 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
8125 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
8126 : pabyMaskData, dfMin, dfMax);
8127 17 : break;
8128 0 : case GDT_TypeCount:
8129 0 : CPLAssert(false);
8130 : break;
8131 : }
8132 6703 : }
8133 :
8134 189 : static bool ComputeMinMaxGenericIterBlocks(
8135 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
8136 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
8137 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
8138 : double &dfMin, double &dfMax)
8139 :
8140 : {
8141 189 : GByte *pabyMaskData = nullptr;
8142 : int nBlockXSize, nBlockYSize;
8143 189 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
8144 :
8145 189 : if (poMaskBand)
8146 : {
8147 : pabyMaskData =
8148 125 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8149 125 : if (!pabyMaskData)
8150 : {
8151 0 : return false;
8152 : }
8153 : }
8154 :
8155 6892 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
8156 6703 : iSampleBlock += nSampleRate)
8157 : {
8158 6703 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
8159 6703 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
8160 :
8161 6703 : int nXCheck = 0, nYCheck = 0;
8162 6703 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8163 :
8164 13283 : if (poMaskBand &&
8165 6580 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8166 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8167 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8168 : nBlockXSize, nullptr) != CE_None)
8169 : {
8170 0 : CPLFree(pabyMaskData);
8171 0 : return false;
8172 : }
8173 :
8174 6703 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
8175 6703 : if (poBlock == nullptr)
8176 : {
8177 0 : CPLFree(pabyMaskData);
8178 0 : return false;
8179 : }
8180 :
8181 6703 : void *const pData = poBlock->GetDataRef();
8182 :
8183 6703 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
8184 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
8185 : dfMax);
8186 :
8187 6703 : poBlock->DropLock();
8188 : }
8189 :
8190 189 : CPLFree(pabyMaskData);
8191 189 : return true;
8192 : }
8193 :
8194 : /**
8195 : * \brief Compute the min/max values for a band.
8196 : *
8197 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
8198 : * be trusted. If it doesn't work, a subsample of blocks will be read to
8199 : * get an approximate min/max. If the band has a nodata value it will
8200 : * be excluded from the minimum and maximum.
8201 : *
8202 : * If bApprox is FALSE, then all pixels will be read and used to compute
8203 : * an exact range.
8204 : *
8205 : * This method is the same as the C function GDALComputeRasterMinMax().
8206 : *
8207 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
8208 : * FALSE.
8209 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
8210 : * maximum (adfMinMax[1]) are returned.
8211 : *
8212 : * @return CE_None on success or CE_Failure on failure.
8213 : */
8214 :
8215 1814 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
8216 : {
8217 : /* -------------------------------------------------------------------- */
8218 : /* Does the driver already know the min/max? */
8219 : /* -------------------------------------------------------------------- */
8220 1814 : if (bApproxOK)
8221 : {
8222 23 : int bSuccessMin = FALSE;
8223 23 : int bSuccessMax = FALSE;
8224 :
8225 23 : double dfMin = GetMinimum(&bSuccessMin);
8226 23 : double dfMax = GetMaximum(&bSuccessMax);
8227 :
8228 23 : if (bSuccessMin && bSuccessMax)
8229 : {
8230 1 : adfMinMax[0] = dfMin;
8231 1 : adfMinMax[1] = dfMax;
8232 1 : return CE_None;
8233 : }
8234 : }
8235 :
8236 : /* -------------------------------------------------------------------- */
8237 : /* If we have overview bands, use them for min/max. */
8238 : /* -------------------------------------------------------------------- */
8239 : // cppcheck-suppress knownConditionTrueFalse
8240 1813 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
8241 : {
8242 : GDALRasterBand *poBand =
8243 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
8244 :
8245 0 : if (poBand != this)
8246 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
8247 : }
8248 :
8249 : /* -------------------------------------------------------------------- */
8250 : /* Read actual data and compute minimum and maximum. */
8251 : /* -------------------------------------------------------------------- */
8252 1813 : GDALNoDataValues sNoDataValues(this, eDataType);
8253 1813 : GDALRasterBand *poMaskBand = nullptr;
8254 1813 : if (!sNoDataValues.bGotNoDataValue)
8255 : {
8256 1551 : const int l_nMaskFlags = GetMaskFlags();
8257 1676 : if (l_nMaskFlags != GMF_ALL_VALID &&
8258 125 : GetColorInterpretation() != GCI_AlphaBand)
8259 : {
8260 125 : poMaskBand = GetMaskBand();
8261 : }
8262 : }
8263 :
8264 1813 : if (!bApproxOK &&
8265 1791 : (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
8266 1653 : eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
8267 1450 : eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
8268 1404 : eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
8269 1791 : eDataType == GDT_Float64) &&
8270 : !poMaskBand)
8271 : {
8272 1464 : CPLErr eErr = ComputeRasterMinMaxLocation(
8273 732 : &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
8274 732 : if (eErr == CE_Warning)
8275 : {
8276 9 : ReportError(CE_Failure, CPLE_AppDefined,
8277 : "Failed to compute min/max, no valid pixels found in "
8278 : "sampling.");
8279 9 : eErr = CE_Failure;
8280 : }
8281 732 : return eErr;
8282 : }
8283 :
8284 1081 : bool bSignedByte = false;
8285 1081 : if (eDataType == GDT_UInt8)
8286 : {
8287 781 : EnablePixelTypeSignedByteWarning(false);
8288 : const char *pszPixelType =
8289 781 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8290 781 : EnablePixelTypeSignedByteWarning(true);
8291 781 : bSignedByte =
8292 781 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8293 : }
8294 :
8295 : GDALRasterIOExtraArg sExtraArg;
8296 1081 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
8297 :
8298 2162 : GUInt32 nMin = (eDataType == GDT_UInt8)
8299 1081 : ? 255
8300 : : 65535; // used for GByte & GUInt16 cases
8301 1081 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
8302 1081 : GInt16 nMinInt16 =
8303 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
8304 1081 : GInt16 nMaxInt16 =
8305 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
8306 1081 : double dfMin =
8307 : std::numeric_limits<double>::infinity(); // used for generic code path
8308 1081 : double dfMax =
8309 : -std::numeric_limits<double>::infinity(); // used for generic code path
8310 1081 : const bool bUseOptimizedPath =
8311 1287 : !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
8312 206 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
8313 :
8314 : const auto ComputeMinMaxForBlock =
8315 19520 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
8316 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
8317 113020 : int nYCheck)
8318 : {
8319 19520 : if (eDataType == GDT_UInt8 && !bSignedByte)
8320 : {
8321 : const bool bHasNoData =
8322 11562 : sNoDataValues.bGotNoDataValue &&
8323 29667 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
8324 11562 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
8325 11562 : sNoDataValues.dfNoDataValue;
8326 18105 : const GUInt32 nNoDataValue =
8327 18105 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
8328 : : 0;
8329 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8330 : ComputeStatisticsInternal<GByte,
8331 : /* COMPUTE_OTHER_STATS = */ false>::
8332 18105 : f(nXCheck, nBufferWidth, nYCheck,
8333 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
8334 18105 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8335 : }
8336 1415 : else if (eDataType == GDT_UInt16)
8337 : {
8338 : const bool bHasNoData =
8339 84 : sNoDataValues.bGotNoDataValue &&
8340 1497 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
8341 84 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
8342 84 : sNoDataValues.dfNoDataValue;
8343 1413 : const GUInt32 nNoDataValue =
8344 1413 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
8345 : : 0;
8346 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
8347 : ComputeStatisticsInternal<GUInt16,
8348 : /* COMPUTE_OTHER_STATS = */ false>::
8349 1413 : f(nXCheck, nBufferWidth, nYCheck,
8350 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
8351 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
8352 : }
8353 2 : else if (eDataType == GDT_Int16)
8354 : {
8355 : const bool bHasNoData =
8356 0 : sNoDataValues.bGotNoDataValue &&
8357 2 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
8358 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
8359 0 : sNoDataValues.dfNoDataValue;
8360 2 : if (bHasNoData)
8361 : {
8362 0 : const int16_t nNoDataValue =
8363 0 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
8364 0 : for (int iY = 0; iY < nYCheck; iY++)
8365 : {
8366 0 : ComputeMinMax<int16_t, true>(
8367 0 : static_cast<const int16_t *>(pData) +
8368 0 : static_cast<size_t>(iY) * nBufferWidth,
8369 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
8370 : }
8371 : }
8372 : else
8373 : {
8374 4 : for (int iY = 0; iY < nYCheck; iY++)
8375 : {
8376 2 : ComputeMinMax<int16_t, false>(
8377 2 : static_cast<const int16_t *>(pData) +
8378 2 : static_cast<size_t>(iY) * nBufferWidth,
8379 : nXCheck, 0, &nMinInt16, &nMaxInt16);
8380 : }
8381 : }
8382 : }
8383 19520 : };
8384 :
8385 1081 : if (bApproxOK && HasArbitraryOverviews())
8386 : {
8387 : /* --------------------------------------------------------------------
8388 : */
8389 : /* Figure out how much the image should be reduced to get an */
8390 : /* approximate value. */
8391 : /* --------------------------------------------------------------------
8392 : */
8393 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
8394 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
8395 :
8396 0 : int nXReduced = nRasterXSize;
8397 0 : int nYReduced = nRasterYSize;
8398 0 : if (dfReduction > 1.0)
8399 : {
8400 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
8401 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
8402 :
8403 : // Catch the case of huge resizing ratios here
8404 0 : if (nXReduced == 0)
8405 0 : nXReduced = 1;
8406 0 : if (nYReduced == 0)
8407 0 : nYReduced = 1;
8408 : }
8409 :
8410 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
8411 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
8412 :
8413 : const CPLErr eErr =
8414 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
8415 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
8416 0 : if (eErr != CE_None)
8417 : {
8418 0 : CPLFree(pData);
8419 0 : return eErr;
8420 : }
8421 :
8422 0 : GByte *pabyMaskData = nullptr;
8423 0 : if (poMaskBand)
8424 : {
8425 : pabyMaskData =
8426 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
8427 0 : if (!pabyMaskData)
8428 : {
8429 0 : CPLFree(pData);
8430 0 : return CE_Failure;
8431 : }
8432 :
8433 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
8434 : pabyMaskData, nXReduced, nYReduced,
8435 0 : GDT_UInt8, 0, 0, nullptr) != CE_None)
8436 : {
8437 0 : CPLFree(pData);
8438 0 : CPLFree(pabyMaskData);
8439 0 : return CE_Failure;
8440 : }
8441 : }
8442 :
8443 0 : if (bUseOptimizedPath)
8444 : {
8445 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
8446 : }
8447 : else
8448 : {
8449 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
8450 : nYReduced, nXReduced, sNoDataValues,
8451 : pabyMaskData, dfMin, dfMax);
8452 : }
8453 :
8454 0 : CPLFree(pData);
8455 0 : CPLFree(pabyMaskData);
8456 : }
8457 :
8458 : else // No arbitrary overviews
8459 : {
8460 1081 : if (!InitBlockInfo())
8461 0 : return CE_Failure;
8462 :
8463 : /* --------------------------------------------------------------------
8464 : */
8465 : /* Figure out the ratio of blocks we will read to get an */
8466 : /* approximate value. */
8467 : /* --------------------------------------------------------------------
8468 : */
8469 1081 : int nSampleRate = 1;
8470 :
8471 1081 : if (bApproxOK)
8472 : {
8473 22 : nSampleRate = static_cast<int>(std::max(
8474 44 : 1.0,
8475 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
8476 : // We want to avoid probing only the first column of blocks for
8477 : // a square shaped raster, because it is not unlikely that it may
8478 : // be padding only (#6378).
8479 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
8480 0 : nSampleRate += 1;
8481 : }
8482 :
8483 1081 : if (bUseOptimizedPath)
8484 : {
8485 892 : for (GIntBig iSampleBlock = 0;
8486 20338 : iSampleBlock <
8487 20338 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8488 19446 : iSampleBlock += nSampleRate)
8489 : {
8490 19522 : const int iYBlock =
8491 19522 : static_cast<int>(iSampleBlock / nBlocksPerRow);
8492 19522 : const int iXBlock =
8493 19522 : static_cast<int>(iSampleBlock % nBlocksPerRow);
8494 :
8495 19522 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8496 19522 : if (poBlock == nullptr)
8497 2 : return CE_Failure;
8498 :
8499 19520 : void *const pData = poBlock->GetDataRef();
8500 :
8501 19520 : int nXCheck = 0, nYCheck = 0;
8502 19520 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8503 :
8504 19520 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
8505 :
8506 19520 : poBlock->DropLock();
8507 :
8508 19520 : if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
8509 4110 : nMax == 255)
8510 74 : break;
8511 : }
8512 : }
8513 : else
8514 : {
8515 189 : const GIntBig nTotalBlocks =
8516 189 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8517 189 : if (!ComputeMinMaxGenericIterBlocks(
8518 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
8519 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
8520 : {
8521 0 : return CE_Failure;
8522 : }
8523 : }
8524 : }
8525 :
8526 1079 : if (bUseOptimizedPath)
8527 : {
8528 890 : if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
8529 : {
8530 889 : dfMin = nMin;
8531 889 : dfMax = nMax;
8532 : }
8533 1 : else if (eDataType == GDT_Int16)
8534 : {
8535 1 : dfMin = nMinInt16;
8536 1 : dfMax = nMaxInt16;
8537 : }
8538 : }
8539 :
8540 1079 : if (dfMin > dfMax)
8541 : {
8542 23 : adfMinMax[0] = 0;
8543 23 : adfMinMax[1] = 0;
8544 23 : ReportError(
8545 : CE_Failure, CPLE_AppDefined,
8546 : "Failed to compute min/max, no valid pixels found in sampling.");
8547 23 : return CE_Failure;
8548 : }
8549 :
8550 1056 : adfMinMax[0] = dfMin;
8551 1056 : adfMinMax[1] = dfMax;
8552 :
8553 1056 : return CE_None;
8554 : }
8555 :
8556 : /************************************************************************/
8557 : /* GDALComputeRasterMinMax() */
8558 : /************************************************************************/
8559 :
8560 : /**
8561 : * \brief Compute the min/max values for a band.
8562 : *
8563 : * @see GDALRasterBand::ComputeRasterMinMax()
8564 : *
8565 : * @note Prior to GDAL 3.6, this function returned void
8566 : */
8567 :
8568 1663 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
8569 : double adfMinMax[2])
8570 :
8571 : {
8572 1663 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
8573 :
8574 1663 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8575 1663 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
8576 : }
8577 :
8578 : /************************************************************************/
8579 : /* ComputeRasterMinMaxLocation() */
8580 : /************************************************************************/
8581 :
8582 : /**
8583 : * \brief Compute the min/max values for a band, and their location.
8584 : *
8585 : * Pixels whose value matches the nodata value or are masked by the mask
8586 : * band are ignored.
8587 : *
8588 : * If the minimum or maximum value is hit in several locations, it is not
8589 : * specified which one will be returned.
8590 : *
8591 : * @param[out] pdfMin Pointer to the minimum value.
8592 : * @param[out] pdfMax Pointer to the maximum value.
8593 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
8594 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
8595 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
8596 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
8597 : *
8598 : * @return CE_None in case of success, CE_Warning if there are no valid values,
8599 : * CE_Failure in case of error.
8600 : *
8601 : * @since GDAL 3.11
8602 : */
8603 :
8604 748 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
8605 : double *pdfMax, int *pnMinX,
8606 : int *pnMinY, int *pnMaxX,
8607 : int *pnMaxY)
8608 : {
8609 748 : int nMinX = -1;
8610 748 : int nMinY = -1;
8611 748 : int nMaxX = -1;
8612 748 : int nMaxY = -1;
8613 748 : double dfMin = std::numeric_limits<double>::infinity();
8614 748 : double dfMax = -std::numeric_limits<double>::infinity();
8615 748 : if (pdfMin)
8616 745 : *pdfMin = dfMin;
8617 748 : if (pdfMax)
8618 745 : *pdfMax = dfMax;
8619 748 : if (pnMinX)
8620 14 : *pnMinX = nMinX;
8621 748 : if (pnMinY)
8622 14 : *pnMinY = nMinY;
8623 748 : if (pnMaxX)
8624 14 : *pnMaxX = nMaxX;
8625 748 : if (pnMaxY)
8626 14 : *pnMaxY = nMaxY;
8627 :
8628 748 : if (GDALDataTypeIsComplex(eDataType))
8629 : {
8630 0 : CPLError(CE_Failure, CPLE_NotSupported,
8631 : "Complex data type not supported");
8632 0 : return CE_Failure;
8633 : }
8634 :
8635 748 : if (!InitBlockInfo())
8636 0 : return CE_Failure;
8637 :
8638 748 : GDALNoDataValues sNoDataValues(this, eDataType);
8639 748 : GDALRasterBand *poMaskBand = nullptr;
8640 748 : if (!sNoDataValues.bGotNoDataValue)
8641 : {
8642 575 : const int l_nMaskFlags = GetMaskFlags();
8643 576 : if (l_nMaskFlags != GMF_ALL_VALID &&
8644 1 : GetColorInterpretation() != GCI_AlphaBand)
8645 : {
8646 1 : poMaskBand = GetMaskBand();
8647 : }
8648 : }
8649 :
8650 748 : bool bSignedByte = false;
8651 748 : if (eDataType == GDT_UInt8)
8652 : {
8653 7 : EnablePixelTypeSignedByteWarning(false);
8654 : const char *pszPixelType =
8655 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
8656 7 : EnablePixelTypeSignedByteWarning(true);
8657 7 : bSignedByte =
8658 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
8659 : }
8660 :
8661 748 : GByte *pabyMaskData = nullptr;
8662 748 : if (poMaskBand)
8663 : {
8664 : pabyMaskData =
8665 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
8666 1 : if (!pabyMaskData)
8667 : {
8668 0 : return CE_Failure;
8669 : }
8670 : }
8671 :
8672 748 : const GIntBig nTotalBlocks =
8673 748 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
8674 748 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
8675 748 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
8676 7842 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
8677 : {
8678 7097 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
8679 7097 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
8680 :
8681 7097 : int nXCheck = 0, nYCheck = 0;
8682 7097 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
8683 :
8684 7099 : if (poMaskBand &&
8685 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
8686 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
8687 : pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
8688 2 : nBlockXSize, nullptr) != CE_None)
8689 : {
8690 0 : CPLFree(pabyMaskData);
8691 0 : return CE_Failure;
8692 : }
8693 :
8694 7097 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
8695 7097 : if (poBlock == nullptr)
8696 : {
8697 0 : CPLFree(pabyMaskData);
8698 0 : return CE_Failure;
8699 : }
8700 :
8701 7097 : void *const pData = poBlock->GetDataRef();
8702 :
8703 7097 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
8704 : {
8705 5059 : for (int iY = 0; iY < nYCheck; ++iY)
8706 : {
8707 238290 : for (int iX = 0; iX < nXCheck; ++iX)
8708 : {
8709 233478 : const GPtrDiff_t iOffset =
8710 233478 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
8711 233478 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
8712 2 : continue;
8713 233476 : bool bValid = true;
8714 : double dfValue =
8715 233476 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
8716 : sNoDataValues, bValid);
8717 233476 : if (!bValid)
8718 0 : continue;
8719 233476 : if (dfValue < dfMin)
8720 : {
8721 606 : dfMin = dfValue;
8722 606 : nMinX = iXBlock * nBlockXSize + iX;
8723 606 : nMinY = iYBlock * nBlockYSize + iY;
8724 : }
8725 233476 : if (dfValue > dfMax)
8726 : {
8727 1515 : dfMax = dfValue;
8728 1515 : nMaxX = iXBlock * nBlockXSize + iX;
8729 1515 : nMaxY = iYBlock * nBlockYSize + iY;
8730 : }
8731 : }
8732 247 : }
8733 : }
8734 : else
8735 : {
8736 6850 : size_t pos_min = 0;
8737 6850 : size_t pos_max = 0;
8738 6850 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
8739 6850 : if (bNeedsMin && bNeedsMax)
8740 : {
8741 13692 : std::tie(pos_min, pos_max) = gdal::minmax_element(
8742 6846 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8743 6846 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8744 13692 : sNoDataValues.dfNoDataValue);
8745 : }
8746 4 : else if (bNeedsMin)
8747 : {
8748 1 : pos_min = gdal::min_element(
8749 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8750 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8751 : sNoDataValues.dfNoDataValue);
8752 : }
8753 3 : else if (bNeedsMax)
8754 : {
8755 2 : pos_max = gdal::max_element(
8756 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
8757 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
8758 : sNoDataValues.dfNoDataValue);
8759 : }
8760 :
8761 6850 : if (bNeedsMin)
8762 : {
8763 6847 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
8764 6847 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
8765 6847 : bool bValid = true;
8766 : const double dfMinValueBlock =
8767 6847 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
8768 : sNoDataValues, bValid);
8769 6847 : if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
8770 : {
8771 1039 : dfMin = dfMinValueBlock;
8772 1039 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
8773 1039 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
8774 : }
8775 : }
8776 :
8777 6850 : if (bNeedsMax)
8778 : {
8779 6848 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
8780 6848 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
8781 6848 : bool bValid = true;
8782 : const double dfMaxValueBlock =
8783 6848 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
8784 : sNoDataValues, bValid);
8785 6848 : if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
8786 : {
8787 954 : dfMax = dfMaxValueBlock;
8788 954 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
8789 954 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
8790 : }
8791 : }
8792 : }
8793 :
8794 7097 : poBlock->DropLock();
8795 :
8796 7097 : if (eDataType == GDT_UInt8)
8797 : {
8798 10 : if (bNeedsMin && dfMin == 0)
8799 : {
8800 1 : bNeedsMin = false;
8801 : }
8802 10 : if (bNeedsMax && dfMax == 255)
8803 : {
8804 4 : bNeedsMax = false;
8805 : }
8806 10 : if (!bNeedsMin && !bNeedsMax)
8807 : {
8808 3 : break;
8809 : }
8810 : }
8811 : }
8812 :
8813 748 : CPLFree(pabyMaskData);
8814 :
8815 748 : if (pdfMin)
8816 745 : *pdfMin = dfMin;
8817 748 : if (pdfMax)
8818 745 : *pdfMax = dfMax;
8819 748 : if (pnMinX)
8820 14 : *pnMinX = nMinX;
8821 748 : if (pnMinY)
8822 14 : *pnMinY = nMinY;
8823 748 : if (pnMaxX)
8824 14 : *pnMaxX = nMaxX;
8825 748 : if (pnMaxY)
8826 14 : *pnMaxY = nMaxY;
8827 748 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8828 748 : : CE_None;
8829 : }
8830 :
8831 : /************************************************************************/
8832 : /* GDALComputeRasterMinMaxLocation() */
8833 : /************************************************************************/
8834 :
8835 : /**
8836 : * \brief Compute the min/max values for a band, and their location.
8837 : *
8838 : * @see GDALRasterBand::ComputeRasterMinMax()
8839 : * @since GDAL 3.11
8840 : */
8841 :
8842 14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8843 : double *pdfMax, int *pnMinX, int *pnMinY,
8844 : int *pnMaxX, int *pnMaxY)
8845 :
8846 : {
8847 14 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8848 :
8849 14 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8850 14 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8851 14 : pnMaxX, pnMaxY);
8852 : }
8853 :
8854 : /************************************************************************/
8855 : /* SetDefaultHistogram() */
8856 : /************************************************************************/
8857 :
8858 : /* FIXME : add proper documentation */
8859 : /**
8860 : * \brief Set default histogram.
8861 : *
8862 : * This method is the same as the C function GDALSetDefaultHistogram() and
8863 : * GDALSetDefaultHistogramEx()
8864 : */
8865 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8866 : double /* dfMax */,
8867 : int /* nBuckets */,
8868 : GUIntBig * /* panHistogram */)
8869 :
8870 : {
8871 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8872 0 : ReportError(CE_Failure, CPLE_NotSupported,
8873 : "SetDefaultHistogram() not implemented for this format.");
8874 :
8875 0 : return CE_Failure;
8876 : }
8877 :
8878 : /************************************************************************/
8879 : /* GDALSetDefaultHistogram() */
8880 : /************************************************************************/
8881 :
8882 : /**
8883 : * \brief Set default histogram.
8884 : *
8885 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8886 : * 2 billion.
8887 : *
8888 : * @see GDALRasterBand::SetDefaultHistogram()
8889 : * @see GDALSetRasterHistogramEx()
8890 : */
8891 :
8892 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8893 : double dfMax, int nBuckets,
8894 : int *panHistogram)
8895 :
8896 : {
8897 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8898 :
8899 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8900 :
8901 : GUIntBig *panHistogramTemp =
8902 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8903 0 : if (panHistogramTemp == nullptr)
8904 : {
8905 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8906 : "Out of memory in GDALSetDefaultHistogram().");
8907 0 : return CE_Failure;
8908 : }
8909 :
8910 0 : for (int i = 0; i < nBuckets; ++i)
8911 : {
8912 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8913 : }
8914 :
8915 : const CPLErr eErr =
8916 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8917 :
8918 0 : CPLFree(panHistogramTemp);
8919 :
8920 0 : return eErr;
8921 : }
8922 :
8923 : /************************************************************************/
8924 : /* GDALSetDefaultHistogramEx() */
8925 : /************************************************************************/
8926 :
8927 : /**
8928 : * \brief Set default histogram.
8929 : *
8930 : * @see GDALRasterBand::SetDefaultHistogram()
8931 : *
8932 : */
8933 :
8934 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8935 : double dfMin, double dfMax,
8936 : int nBuckets,
8937 : GUIntBig *panHistogram)
8938 :
8939 : {
8940 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8941 :
8942 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8943 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8944 : }
8945 :
8946 : /************************************************************************/
8947 : /* GetDefaultRAT() */
8948 : /************************************************************************/
8949 :
8950 : /**
8951 : * \brief Fetch default Raster Attribute Table.
8952 : *
8953 : * A RAT will be returned if there is a default one associated with the
8954 : * band, otherwise NULL is returned. The returned RAT is owned by the
8955 : * band and should not be deleted by the application.
8956 : *
8957 : * This method is the same as the C function GDALGetDefaultRAT().
8958 : *
8959 : * @return NULL, or a pointer to an internal RAT owned by the band.
8960 : */
8961 :
8962 180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8963 :
8964 : {
8965 180 : return nullptr;
8966 : }
8967 :
8968 : /************************************************************************/
8969 : /* GDALGetDefaultRAT() */
8970 : /************************************************************************/
8971 :
8972 : /**
8973 : * \brief Fetch default Raster Attribute Table.
8974 : *
8975 : * @see GDALRasterBand::GetDefaultRAT()
8976 : */
8977 :
8978 1158 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8979 :
8980 : {
8981 1158 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8982 :
8983 1158 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8984 1158 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8985 : }
8986 :
8987 : /************************************************************************/
8988 : /* SetDefaultRAT() */
8989 : /************************************************************************/
8990 :
8991 : /**
8992 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8993 : * \brief Set default Raster Attribute Table.
8994 : *
8995 : * Associates a default RAT with the band. If not implemented for the
8996 : * format a CPLE_NotSupported error will be issued. If successful a copy
8997 : * of the RAT is made, the original remains owned by the caller.
8998 : *
8999 : * This method is the same as the C function GDALSetDefaultRAT().
9000 : *
9001 : * @param poRAT the RAT to assign to the band.
9002 : *
9003 : * @return CE_None on success or CE_Failure if unsupported or otherwise
9004 : * failing.
9005 : */
9006 :
9007 : /**/
9008 : /**/
9009 :
9010 : CPLErr
9011 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
9012 : {
9013 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
9014 : {
9015 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
9016 0 : ReportError(CE_Failure, CPLE_NotSupported,
9017 : "SetDefaultRAT() not implemented for this format.");
9018 0 : CPLPopErrorHandler();
9019 : }
9020 0 : return CE_Failure;
9021 : }
9022 :
9023 : /************************************************************************/
9024 : /* GDALSetDefaultRAT() */
9025 : /************************************************************************/
9026 :
9027 : /**
9028 : * \brief Set default Raster Attribute Table.
9029 : *
9030 : * @see GDALRasterBand::GDALSetDefaultRAT()
9031 : */
9032 :
9033 25 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
9034 : GDALRasterAttributeTableH hRAT)
9035 :
9036 : {
9037 25 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
9038 :
9039 25 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9040 :
9041 25 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
9042 : }
9043 :
9044 : /************************************************************************/
9045 : /* GetMaskBand() */
9046 : /************************************************************************/
9047 :
9048 : /**
9049 : * \brief Return the mask band associated with the band.
9050 : *
9051 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9052 : * that returns one of four default implementations :
9053 : * <ul>
9054 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9055 : * </li>
9056 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9057 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9058 : * GMF_NODATA | GMF_PER_DATASET.
9059 : * </li>
9060 : * <li>If the band has a nodata value set, an instance of the new
9061 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9062 : * GMF_NODATA.
9063 : * </li>
9064 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
9065 : * to apply to this band (specific rules yet to be determined) and that is of
9066 : * type GDT_UInt8 then that alpha band will be returned, and the flags
9067 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9068 : * </li>
9069 : * <li>If neither of the above apply, an instance of the new
9070 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9071 : * pixels. The null flags will return GMF_ALL_VALID.
9072 : * </li>
9073 : * </ul>
9074 : *
9075 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
9076 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
9077 : *
9078 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9079 : * dataset, with the same name as the main dataset and suffixed with .msk,
9080 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9081 : * main dataset.
9082 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9083 : * level, where xx matches the band number of a band of the main dataset. The
9084 : * value of those items is a combination of the flags GMF_ALL_VALID,
9085 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9086 : * a band, then the other rules explained above will be used to generate a
9087 : * on-the-fly mask band.
9088 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9089 : *
9090 : * This method is the same as the C function GDALGetMaskBand().
9091 : *
9092 : * @return a valid mask band.
9093 : *
9094 : *
9095 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9096 : *
9097 : */
9098 698790 : GDALRasterBand *GDALRasterBand::GetMaskBand()
9099 :
9100 : {
9101 397087 : const auto HasNoData = [this]()
9102 : {
9103 132040 : int bHaveNoDataRaw = FALSE;
9104 132040 : bool bHaveNoData = false;
9105 132040 : if (eDataType == GDT_Int64)
9106 : {
9107 204 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
9108 204 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9109 : }
9110 131836 : else if (eDataType == GDT_UInt64)
9111 : {
9112 152 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
9113 152 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
9114 : }
9115 : else
9116 : {
9117 131684 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
9118 131694 : if (bHaveNoDataRaw &&
9119 131694 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
9120 : {
9121 1126 : bHaveNoData = true;
9122 : }
9123 : }
9124 132051 : return bHaveNoData;
9125 698790 : };
9126 :
9127 698790 : if (poMask != nullptr)
9128 : {
9129 577690 : if (poMask.IsOwned())
9130 : {
9131 294146 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
9132 : {
9133 33613 : if (HasNoData())
9134 : {
9135 9 : InvalidateMaskBand();
9136 : }
9137 : }
9138 267780 : else if (auto poNoDataMaskBand =
9139 270884 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
9140 : {
9141 396 : int bHaveNoDataRaw = FALSE;
9142 396 : bool bIsSame = false;
9143 396 : if (eDataType == GDT_Int64)
9144 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
9145 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
9146 10 : bHaveNoDataRaw;
9147 379 : else if (eDataType == GDT_UInt64)
9148 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
9149 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
9150 10 : bHaveNoDataRaw;
9151 : else
9152 : {
9153 : const double dfNoDataValue =
9154 362 : GetNoDataValue(&bHaveNoDataRaw);
9155 362 : if (bHaveNoDataRaw)
9156 : {
9157 359 : bIsSame =
9158 359 : std::isnan(dfNoDataValue)
9159 359 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
9160 324 : : poNoDataMaskBand->m_dfNoDataValue ==
9161 : dfNoDataValue;
9162 : }
9163 : }
9164 396 : if (!bIsSame)
9165 23 : InvalidateMaskBand();
9166 : }
9167 : }
9168 :
9169 636910 : if (poMask)
9170 657409 : return poMask.get();
9171 : }
9172 :
9173 : /* -------------------------------------------------------------------- */
9174 : /* Check for a mask in a .msk file. */
9175 : /* -------------------------------------------------------------------- */
9176 98537 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
9177 : {
9178 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
9179 47 : if (poMask != nullptr)
9180 : {
9181 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
9182 45 : return poMask.get();
9183 : }
9184 : }
9185 :
9186 : /* -------------------------------------------------------------------- */
9187 : /* Check for NODATA_VALUES metadata. */
9188 : /* -------------------------------------------------------------------- */
9189 98489 : if (poDS != nullptr)
9190 : {
9191 : const char *pszGDALNoDataValues =
9192 98473 : poDS->GetMetadataItem("NODATA_VALUES");
9193 98475 : if (pszGDALNoDataValues != nullptr)
9194 : {
9195 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
9196 : pszGDALNoDataValues, " ", FALSE, FALSE);
9197 :
9198 : // Make sure we have as many values as bands.
9199 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
9200 68 : poDS->GetRasterCount() != 0)
9201 : {
9202 : // Make sure that all bands have the same data type
9203 : // This is clearly not a fundamental condition, just a
9204 : // condition to make implementation easier.
9205 68 : GDALDataType eDT = GDT_Unknown;
9206 68 : int i = 0; // Used after for.
9207 270 : for (; i < poDS->GetRasterCount(); ++i)
9208 : {
9209 202 : if (i == 0)
9210 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
9211 134 : else if (eDT !=
9212 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
9213 : {
9214 0 : break;
9215 : }
9216 : }
9217 68 : if (i == poDS->GetRasterCount())
9218 : {
9219 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
9220 : try
9221 : {
9222 68 : poMask.reset(
9223 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
9224 : }
9225 0 : catch (const std::bad_alloc &)
9226 : {
9227 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9228 0 : poMask.reset();
9229 : }
9230 68 : CSLDestroy(papszGDALNoDataValues);
9231 68 : return poMask.get();
9232 : }
9233 : else
9234 : {
9235 0 : ReportError(CE_Warning, CPLE_AppDefined,
9236 : "All bands should have the same type in "
9237 : "order the NODATA_VALUES metadata item "
9238 : "to be used as a mask.");
9239 : }
9240 : }
9241 : else
9242 : {
9243 0 : ReportError(
9244 : CE_Warning, CPLE_AppDefined,
9245 : "NODATA_VALUES metadata item doesn't have the same number "
9246 : "of values as the number of bands. "
9247 : "Ignoring it for mask.");
9248 : }
9249 :
9250 0 : CSLDestroy(papszGDALNoDataValues);
9251 : }
9252 : }
9253 :
9254 : /* -------------------------------------------------------------------- */
9255 : /* Check for nodata case. */
9256 : /* -------------------------------------------------------------------- */
9257 98423 : if (HasNoData())
9258 : {
9259 1152 : nMaskFlags = GMF_NODATA;
9260 : try
9261 : {
9262 1152 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
9263 : }
9264 0 : catch (const std::bad_alloc &)
9265 : {
9266 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9267 0 : poMask.reset();
9268 : }
9269 1152 : return poMask.get();
9270 : }
9271 :
9272 : /* -------------------------------------------------------------------- */
9273 : /* Check for alpha case. */
9274 : /* -------------------------------------------------------------------- */
9275 97255 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
9276 195124 : this == poDS->GetRasterBand(1) &&
9277 599 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
9278 : {
9279 231 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
9280 : {
9281 187 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9282 187 : poMask.resetNotOwned(poDS->GetRasterBand(2));
9283 187 : return poMask.get();
9284 : }
9285 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
9286 : {
9287 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9288 : try
9289 : {
9290 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9291 46 : poDS->GetRasterBand(2)));
9292 : }
9293 0 : catch (const std::bad_alloc &)
9294 : {
9295 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9296 0 : poMask.reset();
9297 : }
9298 23 : return poMask.get();
9299 : }
9300 : }
9301 :
9302 97045 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
9303 3132 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
9304 194840 : this == poDS->GetRasterBand(3)) &&
9305 2450 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
9306 : {
9307 1571 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
9308 : {
9309 1515 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9310 1515 : poMask.resetNotOwned(poDS->GetRasterBand(4));
9311 1514 : return poMask.get();
9312 : }
9313 57 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
9314 : {
9315 42 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
9316 : try
9317 : {
9318 42 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
9319 84 : poDS->GetRasterBand(4)));
9320 : }
9321 0 : catch (const std::bad_alloc &)
9322 : {
9323 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9324 0 : poMask.reset();
9325 : }
9326 42 : return poMask.get();
9327 : }
9328 : }
9329 :
9330 : /* -------------------------------------------------------------------- */
9331 : /* Fallback to all valid case. */
9332 : /* -------------------------------------------------------------------- */
9333 95501 : nMaskFlags = GMF_ALL_VALID;
9334 : try
9335 : {
9336 95501 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
9337 : }
9338 0 : catch (const std::bad_alloc &)
9339 : {
9340 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
9341 0 : poMask.reset();
9342 : }
9343 :
9344 95501 : return poMask.get();
9345 : }
9346 :
9347 : /************************************************************************/
9348 : /* GDALGetMaskBand() */
9349 : /************************************************************************/
9350 :
9351 : /**
9352 : * \brief Return the mask band associated with the band.
9353 : *
9354 : * @see GDALRasterBand::GetMaskBand()
9355 : */
9356 :
9357 11042 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
9358 :
9359 : {
9360 11042 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
9361 :
9362 11042 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9363 11042 : return poBand->GetMaskBand();
9364 : }
9365 :
9366 : /************************************************************************/
9367 : /* GetMaskFlags() */
9368 : /************************************************************************/
9369 :
9370 : /**
9371 : * \brief Return the status flags of the mask band associated with the band.
9372 : *
9373 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
9374 : * the following available definitions that may be extended in the future:
9375 : * <ul>
9376 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
9377 : * 255. When used this will normally be the only flag set.
9378 : * </li>
9379 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
9380 : * dataset.
9381 : * </li>
9382 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
9383 : * and may have values other than 0 and 255.
9384 : * </li>
9385 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
9386 : * nodata values. (mutually exclusive of GMF_ALPHA)
9387 : * </li>
9388 : * </ul>
9389 : *
9390 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
9391 : * that returns one of four default implementations:
9392 : * <ul>
9393 : * <li>If a corresponding .msk file exists it will be used for the mask band.
9394 : * </li>
9395 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
9396 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
9397 : * GMF_NODATA | GMF_PER_DATASET.
9398 : * </li>
9399 : * <li>If the band has a nodata value set, an instance of the new
9400 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
9401 : * GMF_NODATA.
9402 : * </li>
9403 : * <li>If there is no nodata value, but the dataset has an alpha band that
9404 : * seems to apply to this band (specific rules yet to be determined) and that is
9405 : * of type GDT_UInt8 then that alpha band will be returned, and the flags
9406 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
9407 : * </li>
9408 : * <li>If neither of the above apply, an instance of the new
9409 : * GDALAllValidRasterBand class will be returned that has 255 values for all
9410 : * pixels. The null flags will return GMF_ALL_VALID.
9411 : * </li>
9412 : * </ul>
9413 : *
9414 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
9415 : * dataset, with the same name as the main dataset and suffixed with .msk,
9416 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
9417 : * main dataset.
9418 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9419 : * level, where xx matches the band number of a band of the main dataset. The
9420 : * value of those items is a combination of the flags GMF_ALL_VALID,
9421 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
9422 : * a band, then the other rules explained above will be used to generate a
9423 : * on-the-fly mask band.
9424 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
9425 : *
9426 : * This method is the same as the C function GDALGetMaskFlags().
9427 : *
9428 : *
9429 : * @return a valid mask band.
9430 : *
9431 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9432 : *
9433 : */
9434 157755 : int GDALRasterBand::GetMaskFlags()
9435 :
9436 : {
9437 : // If we don't have a band yet, force this now so that the masks value
9438 : // will be initialized.
9439 :
9440 157755 : if (poMask == nullptr)
9441 96813 : GetMaskBand();
9442 :
9443 157749 : return nMaskFlags;
9444 : }
9445 :
9446 : /************************************************************************/
9447 : /* GDALGetMaskFlags() */
9448 : /************************************************************************/
9449 :
9450 : /**
9451 : * \brief Return the status flags of the mask band associated with the band.
9452 : *
9453 : * @see GDALRasterBand::GetMaskFlags()
9454 : */
9455 :
9456 8838 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
9457 :
9458 : {
9459 8838 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
9460 :
9461 8838 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9462 8838 : return poBand->GetMaskFlags();
9463 : }
9464 :
9465 : /************************************************************************/
9466 : /* InvalidateMaskBand() */
9467 : /************************************************************************/
9468 :
9469 : //! @cond Doxygen_Suppress
9470 1850220 : void GDALRasterBand::InvalidateMaskBand()
9471 : {
9472 1850220 : poMask.reset();
9473 1850210 : nMaskFlags = 0;
9474 1850210 : }
9475 :
9476 : //! @endcond
9477 :
9478 : /************************************************************************/
9479 : /* CreateMaskBand() */
9480 : /************************************************************************/
9481 :
9482 : /**
9483 : * \brief Adds a mask band to the current band
9484 : *
9485 : * The default implementation of the CreateMaskBand() method is implemented
9486 : * based on similar rules to the .ovr handling implemented using the
9487 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
9488 : * be created with the same basename as the original file, and it will have
9489 : * as many bands as the original image (or just one for GMF_PER_DATASET).
9490 : * The mask images will be deflate compressed tiled images with the same
9491 : * block size as the original image if possible.
9492 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
9493 : * level, where xx matches the band number of a band of the main dataset. The
9494 : * value of those items will be the one of the nFlagsIn parameter.
9495 : *
9496 : * Note that if you got a mask band with a previous call to GetMaskBand(),
9497 : * it might be invalidated by CreateMaskBand(). So you have to call
9498 : * GetMaskBand() again.
9499 : *
9500 : * This method is the same as the C function GDALCreateMaskBand().
9501 : *
9502 : *
9503 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
9504 : *
9505 : * @return CE_None on success or CE_Failure on an error.
9506 : *
9507 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
9508 : * @see GDALDataset::CreateMaskBand()
9509 : *
9510 : */
9511 :
9512 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
9513 :
9514 : {
9515 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
9516 : {
9517 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
9518 10 : if (eErr != CE_None)
9519 1 : return eErr;
9520 :
9521 9 : InvalidateMaskBand();
9522 :
9523 9 : return CE_None;
9524 : }
9525 :
9526 0 : ReportError(CE_Failure, CPLE_NotSupported,
9527 : "CreateMaskBand() not supported for this band.");
9528 :
9529 0 : return CE_Failure;
9530 : }
9531 :
9532 : /************************************************************************/
9533 : /* GDALCreateMaskBand() */
9534 : /************************************************************************/
9535 :
9536 : /**
9537 : * \brief Adds a mask band to the current band
9538 : *
9539 : * @see GDALRasterBand::CreateMaskBand()
9540 : */
9541 :
9542 34 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
9543 :
9544 : {
9545 34 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
9546 :
9547 34 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9548 34 : return poBand->CreateMaskBand(nFlags);
9549 : }
9550 :
9551 : /************************************************************************/
9552 : /* IsMaskBand() */
9553 : /************************************************************************/
9554 :
9555 : /**
9556 : * \brief Returns whether a band is a mask band.
9557 : *
9558 : * Mask band must be understood in the broad term: it can be a per-dataset
9559 : * mask band, an alpha band, or an implicit mask band.
9560 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9561 : *
9562 : * This method is the same as the C function GDALIsMaskBand().
9563 : *
9564 : * @return true if the band is a mask band.
9565 : *
9566 : * @see GDALDataset::CreateMaskBand()
9567 : *
9568 : * @since GDAL 3.5.0
9569 : *
9570 : */
9571 :
9572 444 : bool GDALRasterBand::IsMaskBand() const
9573 : {
9574 : // The GeoTIFF driver, among others, override this method to
9575 : // also handle external .msk bands.
9576 444 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
9577 444 : GCI_AlphaBand;
9578 : }
9579 :
9580 : /************************************************************************/
9581 : /* GDALIsMaskBand() */
9582 : /************************************************************************/
9583 :
9584 : /**
9585 : * \brief Returns whether a band is a mask band.
9586 : *
9587 : * Mask band must be understood in the broad term: it can be a per-dataset
9588 : * mask band, an alpha band, or an implicit mask band.
9589 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
9590 : *
9591 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
9592 : *
9593 : * @return true if the band is a mask band.
9594 : *
9595 : * @see GDALRasterBand::IsMaskBand()
9596 : *
9597 : * @since GDAL 3.5.0
9598 : *
9599 : */
9600 :
9601 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
9602 :
9603 : {
9604 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
9605 :
9606 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9607 37 : return poBand->IsMaskBand();
9608 : }
9609 :
9610 : /************************************************************************/
9611 : /* GetMaskValueRange() */
9612 : /************************************************************************/
9613 :
9614 : /**
9615 : * \brief Returns the range of values that a mask band can take.
9616 : *
9617 : * @return the range of values that a mask band can take.
9618 : *
9619 : * @since GDAL 3.5.0
9620 : *
9621 : */
9622 :
9623 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
9624 : {
9625 0 : return GMVR_UNKNOWN;
9626 : }
9627 :
9628 : /************************************************************************/
9629 : /* GetIndexColorTranslationTo() */
9630 : /************************************************************************/
9631 :
9632 : /**
9633 : * \brief Compute translation table for color tables.
9634 : *
9635 : * When the raster band has a palette index, it may be useful to compute
9636 : * the "translation" of this palette to the palette of another band.
9637 : * The translation tries to do exact matching first, and then approximate
9638 : * matching if no exact matching is possible.
9639 : * This method returns a table such that table[i] = j where i is an index
9640 : * of the 'this' rasterband and j the corresponding index for the reference
9641 : * rasterband.
9642 : *
9643 : * This method is thought as internal to GDAL and is used for drivers
9644 : * like RPFTOC.
9645 : *
9646 : * The implementation only supports 1-byte palette rasterbands.
9647 : *
9648 : * @param poReferenceBand the raster band
9649 : * @param pTranslationTable an already allocated translation table (at least 256
9650 : * bytes), or NULL to let the method allocate it
9651 : * @param pApproximateMatching a pointer to a flag that is set if the matching
9652 : * is approximate. May be NULL.
9653 : *
9654 : * @return a translation table if the two bands are palette index and that they
9655 : * do not match or NULL in other cases. The table must be freed with CPLFree if
9656 : * NULL was passed for pTranslationTable.
9657 : */
9658 :
9659 : unsigned char *
9660 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
9661 : unsigned char *pTranslationTable,
9662 : int *pApproximateMatching)
9663 : {
9664 4 : if (poReferenceBand == nullptr)
9665 0 : return nullptr;
9666 :
9667 : // cppcheck-suppress knownConditionTrueFalse
9668 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
9669 : // cppcheck-suppress knownConditionTrueFalse
9670 4 : GetColorInterpretation() == GCI_PaletteIndex &&
9671 12 : poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
9672 4 : GetRasterDataType() == GDT_UInt8)
9673 : {
9674 4 : const GDALColorTable *srcColorTable = GetColorTable();
9675 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
9676 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
9677 : {
9678 4 : const int nEntries = srcColorTable->GetColorEntryCount();
9679 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
9680 :
9681 4 : int bHasNoDataValueSrc = FALSE;
9682 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
9683 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
9684 4 : dfNoDataValueSrc <= 255 &&
9685 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
9686 0 : bHasNoDataValueSrc = FALSE;
9687 4 : const int noDataValueSrc =
9688 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
9689 :
9690 4 : int bHasNoDataValueRef = FALSE;
9691 : const double dfNoDataValueRef =
9692 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
9693 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
9694 3 : dfNoDataValueRef <= 255 &&
9695 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
9696 1 : bHasNoDataValueRef = FALSE;
9697 4 : const int noDataValueRef =
9698 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
9699 :
9700 4 : bool samePalette = false;
9701 :
9702 4 : if (pApproximateMatching)
9703 3 : *pApproximateMatching = FALSE;
9704 :
9705 4 : if (nEntries == nRefEntries &&
9706 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
9707 3 : (bHasNoDataValueSrc == FALSE ||
9708 : noDataValueSrc == noDataValueRef))
9709 : {
9710 3 : samePalette = true;
9711 654 : for (int i = 0; i < nEntries; ++i)
9712 : {
9713 651 : if (noDataValueSrc == i)
9714 3 : continue;
9715 : const GDALColorEntry *entry =
9716 648 : srcColorTable->GetColorEntry(i);
9717 : const GDALColorEntry *entryRef =
9718 648 : destColorTable->GetColorEntry(i);
9719 648 : if (entry->c1 != entryRef->c1 ||
9720 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
9721 : {
9722 0 : samePalette = false;
9723 : }
9724 : }
9725 : }
9726 :
9727 4 : if (!samePalette)
9728 : {
9729 1 : if (pTranslationTable == nullptr)
9730 : {
9731 : pTranslationTable = static_cast<unsigned char *>(
9732 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
9733 1 : if (pTranslationTable == nullptr)
9734 1 : return nullptr;
9735 : }
9736 :
9737 : // Trying to remap the product palette on the subdataset
9738 : // palette.
9739 5 : for (int i = 0; i < nEntries; ++i)
9740 : {
9741 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
9742 : noDataValueSrc == i)
9743 0 : continue;
9744 : const GDALColorEntry *entry =
9745 4 : srcColorTable->GetColorEntry(i);
9746 4 : bool bMatchFound = false;
9747 13 : for (int j = 0; j < nRefEntries; ++j)
9748 : {
9749 10 : if (bHasNoDataValueRef && noDataValueRef == j)
9750 0 : continue;
9751 : const GDALColorEntry *entryRef =
9752 10 : destColorTable->GetColorEntry(j);
9753 10 : if (entry->c1 == entryRef->c1 &&
9754 2 : entry->c2 == entryRef->c2 &&
9755 2 : entry->c3 == entryRef->c3)
9756 : {
9757 1 : pTranslationTable[i] =
9758 : static_cast<unsigned char>(j);
9759 1 : bMatchFound = true;
9760 1 : break;
9761 : }
9762 : }
9763 4 : if (!bMatchFound)
9764 : {
9765 : // No exact match. Looking for closest color now.
9766 3 : int best_j = 0;
9767 3 : int best_distance = 0;
9768 3 : if (pApproximateMatching)
9769 0 : *pApproximateMatching = TRUE;
9770 12 : for (int j = 0; j < nRefEntries; ++j)
9771 : {
9772 : const GDALColorEntry *entryRef =
9773 9 : destColorTable->GetColorEntry(j);
9774 9 : int distance = (entry->c1 - entryRef->c1) *
9775 9 : (entry->c1 - entryRef->c1) +
9776 9 : (entry->c2 - entryRef->c2) *
9777 9 : (entry->c2 - entryRef->c2) +
9778 9 : (entry->c3 - entryRef->c3) *
9779 9 : (entry->c3 - entryRef->c3);
9780 9 : if (j == 0 || distance < best_distance)
9781 : {
9782 7 : best_j = j;
9783 7 : best_distance = distance;
9784 : }
9785 : }
9786 3 : pTranslationTable[i] =
9787 : static_cast<unsigned char>(best_j);
9788 : }
9789 : }
9790 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
9791 0 : pTranslationTable[noDataValueSrc] =
9792 : static_cast<unsigned char>(noDataValueRef);
9793 :
9794 1 : return pTranslationTable;
9795 : }
9796 : }
9797 : }
9798 3 : return nullptr;
9799 : }
9800 :
9801 : /************************************************************************/
9802 : /* SetFlushBlockErr() */
9803 : /************************************************************************/
9804 :
9805 : /**
9806 : * \brief Store that an error occurred while writing a dirty block.
9807 : *
9808 : * This function stores the fact that an error occurred while writing a dirty
9809 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
9810 : * flushed when the block cache get full, it is not convenient/possible to
9811 : * report that a dirty block could not be written correctly. This function
9812 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
9813 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
9814 : * places where the user can easily match the error with the relevant dataset.
9815 : */
9816 :
9817 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
9818 : {
9819 0 : eFlushBlockErr = eErr;
9820 0 : }
9821 :
9822 : /************************************************************************/
9823 : /* IncDirtyBlocks() */
9824 : /************************************************************************/
9825 :
9826 : /**
9827 : * \brief Increment/decrement the number of dirty blocks
9828 : */
9829 :
9830 796703 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9831 : {
9832 796703 : if (poBandBlockCache)
9833 796703 : poBandBlockCache->IncDirtyBlocks(nInc);
9834 796703 : }
9835 :
9836 : /************************************************************************/
9837 : /* ReportError() */
9838 : /************************************************************************/
9839 :
9840 : #ifndef DOXYGEN_XML
9841 : /**
9842 : * \brief Emits an error related to a raster band.
9843 : *
9844 : * This function is a wrapper for regular CPLError(). The only difference
9845 : * with CPLError() is that it prepends the error message with the dataset
9846 : * name and the band number.
9847 : *
9848 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9849 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9850 : * @param fmt a printf() style format string. Any additional arguments
9851 : * will be treated as arguments to fill in this format in a manner
9852 : * similar to printf().
9853 : *
9854 : */
9855 :
9856 2498 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9857 : const char *fmt, ...) const
9858 : {
9859 : va_list args;
9860 :
9861 2498 : va_start(args, fmt);
9862 :
9863 2498 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9864 2498 : pszDSName = CPLGetFilename(pszDSName);
9865 2498 : if (pszDSName[0] != '\0')
9866 : {
9867 2404 : CPLError(eErrClass, err_no, "%s",
9868 4808 : CPLString()
9869 2404 : .Printf("%s, band %d: ", pszDSName, GetBand())
9870 4808 : .append(CPLString().vPrintf(fmt, args))
9871 : .c_str());
9872 : }
9873 : else
9874 : {
9875 94 : CPLErrorV(eErrClass, err_no, fmt, args);
9876 : }
9877 :
9878 2498 : va_end(args);
9879 2498 : }
9880 : #endif
9881 :
9882 : /************************************************************************/
9883 : /* GetVirtualMemAuto() */
9884 : /************************************************************************/
9885 :
9886 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9887 : *
9888 : * Only supported on Linux and Unix systems with mmap() for now.
9889 : *
9890 : * This method allows creating a virtual memory object for a GDALRasterBand,
9891 : * that exposes the whole image data as a virtual array.
9892 : *
9893 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9894 : * specialized implementation, such as for raw files, may also directly use
9895 : * mechanisms of the operating system to create a view of the underlying file
9896 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9897 : *
9898 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9899 : * offer a specialized implementation with direct file mapping, provided that
9900 : * some requirements are met :
9901 : * - for all drivers, the dataset must be backed by a "real" file in the file
9902 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9903 : * must match the native ordering of the CPU.
9904 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9905 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9906 : * the file in sequential order, and be equally spaced (which is generally the
9907 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9908 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9909 : *
9910 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9911 : * CPLVirtualMemFree() must be called before the raster band object is
9912 : * destroyed.
9913 : *
9914 : * If p is such a pointer and base_type the type matching
9915 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9916 : * accessed with
9917 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9918 : *
9919 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9920 : *
9921 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9922 : * read/write the band.
9923 : *
9924 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9925 : * one pixel value in the buffer to the start of the next pixel value within a
9926 : * scanline.
9927 : *
9928 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9929 : * one scanline in the buffer to the start of the next.
9930 : *
9931 : * @param papszOptions NULL terminated list of options.
9932 : * If a specialized implementation exists, defining
9933 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9934 : * used. On the contrary, defining
9935 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9936 : * being used (thus only allowing efficient implementations to be used). When
9937 : * requiring or falling back to the default implementation, the following
9938 : * options are available : CACHE_SIZE (in bytes, defaults to
9939 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9940 : * to FALSE)
9941 : *
9942 : * @return a virtual memory object that must be unreferenced by
9943 : * CPLVirtualMemFree(), or NULL in case of failure.
9944 : *
9945 : */
9946 :
9947 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9948 : int *pnPixelSpace,
9949 : GIntBig *pnLineSpace,
9950 : char **papszOptions)
9951 : {
9952 9 : const char *pszImpl = CSLFetchNameValueDef(
9953 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9954 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9955 8 : EQUAL(pszImpl, "FALSE"))
9956 : {
9957 1 : return nullptr;
9958 : }
9959 :
9960 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9961 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9962 8 : if (pnPixelSpace)
9963 8 : *pnPixelSpace = nPixelSpace;
9964 8 : if (pnLineSpace)
9965 8 : *pnLineSpace = nLineSpace;
9966 : const size_t nCacheSize =
9967 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9968 : const size_t nPageSizeHint =
9969 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9970 8 : const bool bSingleThreadUsage = CPLTestBool(
9971 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9972 8 : return GDALRasterBandGetVirtualMem(
9973 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9974 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9975 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9976 8 : papszOptions);
9977 : }
9978 :
9979 : /************************************************************************/
9980 : /* GDALGetVirtualMemAuto() */
9981 : /************************************************************************/
9982 :
9983 : /**
9984 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9985 : *
9986 : * @see GDALRasterBand::GetVirtualMemAuto()
9987 : */
9988 :
9989 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9990 : int *pnPixelSpace, GIntBig *pnLineSpace,
9991 : CSLConstList papszOptions)
9992 : {
9993 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9994 :
9995 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9996 :
9997 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9998 31 : const_cast<char **>(papszOptions));
9999 : }
10000 :
10001 : /************************************************************************/
10002 : /* GDALGetDataCoverageStatus() */
10003 : /************************************************************************/
10004 :
10005 : /**
10006 : * \brief Get the coverage status of a sub-window of the raster.
10007 : *
10008 : * Returns whether a sub-window of the raster contains only data, only empty
10009 : * blocks or a mix of both. This function can be used to determine quickly
10010 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10011 : * be sparse.
10012 : *
10013 : * Empty blocks are blocks that are generally not physically present in the
10014 : * file, and when read through GDAL, contain only pixels whose value is the
10015 : * nodata value when it is set, or whose value is 0 when the nodata value is
10016 : * not set.
10017 : *
10018 : * The query is done in an efficient way without reading the actual pixel
10019 : * values. If not possible, or not implemented at all by the driver,
10020 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10021 : * be returned.
10022 : *
10023 : * The values that can be returned by the function are the following,
10024 : * potentially combined with the binary or operator :
10025 : * <ul>
10026 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10027 : * GetDataCoverageStatus(). This flag should be returned together with
10028 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10029 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10030 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10031 : * the queried window. This is typically identified by the concept of missing
10032 : * block in formats that supports it.
10033 : * </li>
10034 : * </ul>
10035 : *
10036 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10037 : * should be interpreted more as hint of potential presence of data. For example
10038 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10039 : * nodata value), instead of using the missing block mechanism,
10040 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10041 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10042 : *
10043 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10044 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10045 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10046 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10047 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10048 : * the function will exit, so that you can potentially refine the requested area
10049 : * to find which particular region(s) have missing blocks.
10050 : *
10051 : * @see GDALRasterBand::GetDataCoverageStatus()
10052 : *
10053 : * @param hBand raster band
10054 : *
10055 : * @param nXOff The pixel offset to the top left corner of the region
10056 : * of the band to be queried. This would be zero to start from the left side.
10057 : *
10058 : * @param nYOff The line offset to the top left corner of the region
10059 : * of the band to be queried. This would be zero to start from the top.
10060 : *
10061 : * @param nXSize The width of the region of the band to be queried in pixels.
10062 : *
10063 : * @param nYSize The height of the region of the band to be queried in lines.
10064 : *
10065 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10066 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10067 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10068 : * as the computation of the coverage matches the mask, the computation will be
10069 : * stopped. *pdfDataPct will not be valid in that case.
10070 : *
10071 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10072 : * to the (approximate) percentage in [0,100] of pixels in the queried
10073 : * sub-window that have valid values. The implementation might not always be
10074 : * able to compute it, in which case it will be set to a negative value.
10075 : *
10076 : * @return a binary-or'ed combination of possible values
10077 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10078 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10079 : */
10080 :
10081 29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
10082 : int nYOff, int nXSize, int nYSize,
10083 : int nMaskFlagStop, double *pdfDataPct)
10084 : {
10085 29 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
10086 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
10087 :
10088 29 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10089 :
10090 29 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
10091 29 : nMaskFlagStop, pdfDataPct);
10092 : }
10093 :
10094 : /************************************************************************/
10095 : /* GetDataCoverageStatus() */
10096 : /************************************************************************/
10097 :
10098 : /**
10099 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
10100 : * int nYOff,
10101 : * int nXSize,
10102 : * int nYSize,
10103 : * int nMaskFlagStop,
10104 : * double* pdfDataPct)
10105 : * \brief Get the coverage status of a sub-window of the raster.
10106 : *
10107 : * Returns whether a sub-window of the raster contains only data, only empty
10108 : * blocks or a mix of both. This function can be used to determine quickly
10109 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10110 : * be sparse.
10111 : *
10112 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10113 : * value when it is set, or whose value is 0 when the nodata value is not set.
10114 : *
10115 : * The query is done in an efficient way without reading the actual pixel
10116 : * values. If not possible, or not implemented at all by the driver,
10117 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10118 : * be returned.
10119 : *
10120 : * The values that can be returned by the function are the following,
10121 : * potentially combined with the binary or operator :
10122 : * <ul>
10123 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10124 : * GetDataCoverageStatus(). This flag should be returned together with
10125 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10126 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10127 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10128 : * the queried window. This is typically identified by the concept of missing
10129 : * block in formats that supports it.
10130 : * </li>
10131 : * </ul>
10132 : *
10133 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10134 : * should be interpreted more as hint of potential presence of data. For example
10135 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10136 : * nodata value), instead of using the missing block mechanism,
10137 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10138 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10139 : *
10140 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10141 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10142 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10143 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10144 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10145 : * the function will exit, so that you can potentially refine the requested area
10146 : * to find which particular region(s) have missing blocks.
10147 : *
10148 : * @see GDALGetDataCoverageStatus()
10149 : *
10150 : * @param nXOff The pixel offset to the top left corner of the region
10151 : * of the band to be queried. This would be zero to start from the left side.
10152 : *
10153 : * @param nYOff The line offset to the top left corner of the region
10154 : * of the band to be queried. This would be zero to start from the top.
10155 : *
10156 : * @param nXSize The width of the region of the band to be queried in pixels.
10157 : *
10158 : * @param nYSize The height of the region of the band to be queried in lines.
10159 : *
10160 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10161 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10162 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10163 : * as the computation of the coverage matches the mask, the computation will be
10164 : * stopped. *pdfDataPct will not be valid in that case.
10165 : *
10166 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10167 : * to the (approximate) percentage in [0,100] of pixels in the queried
10168 : * sub-window that have valid values. The implementation might not always be
10169 : * able to compute it, in which case it will be set to a negative value.
10170 : *
10171 : * @return a binary-or'ed combination of possible values
10172 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10173 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10174 : */
10175 :
10176 : /**
10177 : * \brief Get the coverage status of a sub-window of the raster.
10178 : *
10179 : * Returns whether a sub-window of the raster contains only data, only empty
10180 : * blocks or a mix of both. This function can be used to determine quickly
10181 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
10182 : * be sparse.
10183 : *
10184 : * Empty blocks are blocks that contain only pixels whose value is the nodata
10185 : * value when it is set, or whose value is 0 when the nodata value is not set.
10186 : *
10187 : * The query is done in an efficient way without reading the actual pixel
10188 : * values. If not possible, or not implemented at all by the driver,
10189 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
10190 : * be returned.
10191 : *
10192 : * The values that can be returned by the function are the following,
10193 : * potentially combined with the binary or operator :
10194 : * <ul>
10195 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
10196 : * GetDataCoverageStatus(). This flag should be returned together with
10197 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
10198 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
10199 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
10200 : * the queried window. This is typically identified by the concept of missing
10201 : * block in formats that supports it.
10202 : * </li>
10203 : * </ul>
10204 : *
10205 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
10206 : * should be interpreted more as hint of potential presence of data. For example
10207 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
10208 : * nodata value), instead of using the missing block mechanism,
10209 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
10210 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
10211 : *
10212 : * The nMaskFlagStop should be generally set to 0. It can be set to a
10213 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
10214 : * the function as soon as the computed mask matches the nMaskFlagStop. For
10215 : * example, you can issue a request on the whole raster with nMaskFlagStop =
10216 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
10217 : * the function will exit, so that you can potentially refine the requested area
10218 : * to find which particular region(s) have missing blocks.
10219 : *
10220 : * @see GDALGetDataCoverageStatus()
10221 : *
10222 : * @param nXOff The pixel offset to the top left corner of the region
10223 : * of the band to be queried. This would be zero to start from the left side.
10224 : *
10225 : * @param nYOff The line offset to the top left corner of the region
10226 : * of the band to be queried. This would be zero to start from the top.
10227 : *
10228 : * @param nXSize The width of the region of the band to be queried in pixels.
10229 : *
10230 : * @param nYSize The height of the region of the band to be queried in lines.
10231 : *
10232 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
10233 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10234 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
10235 : * as the computation of the coverage matches the mask, the computation will be
10236 : * stopped. *pdfDataPct will not be valid in that case.
10237 : *
10238 : * @param pdfDataPct Optional output parameter whose pointed value will be set
10239 : * to the (approximate) percentage in [0,100] of pixels in the queried
10240 : * sub-window that have valid values. The implementation might not always be
10241 : * able to compute it, in which case it will be set to a negative value.
10242 : *
10243 : * @return a binary-or'ed combination of possible values
10244 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
10245 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
10246 : */
10247 :
10248 4705 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
10249 : int nYSize, int nMaskFlagStop,
10250 : double *pdfDataPct)
10251 : {
10252 4705 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
10253 4705 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
10254 4705 : nYOff + nYSize > nRasterYSize)
10255 : {
10256 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
10257 0 : if (pdfDataPct)
10258 0 : *pdfDataPct = 0.0;
10259 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10260 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
10261 : }
10262 4705 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
10263 4705 : pdfDataPct);
10264 : }
10265 :
10266 : /************************************************************************/
10267 : /* IGetDataCoverageStatus() */
10268 : /************************************************************************/
10269 :
10270 685 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
10271 : int /*nXSize*/, int /*nYSize*/,
10272 : int /*nMaskFlagStop*/,
10273 : double *pdfDataPct)
10274 : {
10275 685 : if (pdfDataPct != nullptr)
10276 0 : *pdfDataPct = 100.0;
10277 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
10278 685 : GDAL_DATA_COVERAGE_STATUS_DATA;
10279 : }
10280 :
10281 : //! @cond Doxygen_Suppress
10282 : /************************************************************************/
10283 : /* EnterReadWrite() */
10284 : /************************************************************************/
10285 :
10286 7760910 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
10287 : {
10288 7760910 : if (poDS != nullptr)
10289 7037670 : return poDS->EnterReadWrite(eRWFlag);
10290 723239 : return FALSE;
10291 : }
10292 :
10293 : /************************************************************************/
10294 : /* LeaveReadWrite() */
10295 : /************************************************************************/
10296 :
10297 1129220 : void GDALRasterBand::LeaveReadWrite()
10298 : {
10299 1129220 : if (poDS != nullptr)
10300 1129220 : poDS->LeaveReadWrite();
10301 1129220 : }
10302 :
10303 : /************************************************************************/
10304 : /* InitRWLock() */
10305 : /************************************************************************/
10306 :
10307 3978320 : void GDALRasterBand::InitRWLock()
10308 : {
10309 3978320 : if (poDS != nullptr)
10310 3977910 : poDS->InitRWLock();
10311 3978320 : }
10312 :
10313 : //! @endcond
10314 :
10315 : // clang-format off
10316 :
10317 : /**
10318 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
10319 : * \brief Set metadata.
10320 : *
10321 : * CAUTION: depending on the format, older values of the updated information
10322 : * might still be found in the file in a "ghost" state, even if no longer
10323 : * accessible through the GDAL API. This is for example the case of the GTiff
10324 : * format (this is not a exhaustive list)
10325 : *
10326 : * The C function GDALSetMetadata() does the same thing as this method.
10327 : *
10328 : * @param papszMetadata the metadata in name=value string list format to
10329 : * apply.
10330 : * @param pszDomain the domain of interest. Use "" or NULL for the default
10331 : * domain.
10332 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
10333 : * metadata has been accepted, but is likely not maintained persistently
10334 : * by the underlying object between sessions.
10335 : */
10336 :
10337 : /**
10338 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
10339 : * \brief Set single metadata item.
10340 : *
10341 : * CAUTION: depending on the format, older values of the updated information
10342 : * might still be found in the file in a "ghost" state, even if no longer
10343 : * accessible through the GDAL API. This is for example the case of the GTiff
10344 : * format (this is not a exhaustive list)
10345 : *
10346 : * The C function GDALSetMetadataItem() does the same thing as this method.
10347 : *
10348 : * @param pszName the key for the metadata item to fetch.
10349 : * @param pszValue the value to assign to the key.
10350 : * @param pszDomain the domain to set within, use NULL for the default domain.
10351 : *
10352 : * @return CE_None on success, or an error code on failure.
10353 : */
10354 :
10355 : // clang-format on
10356 :
10357 : //! @cond Doxygen_Suppress
10358 : /************************************************************************/
10359 : /* EnablePixelTypeSignedByteWarning() */
10360 : /************************************************************************/
10361 :
10362 157203 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
10363 : {
10364 157203 : m_bEnablePixelTypeSignedByteWarning = b;
10365 157203 : }
10366 :
10367 4904 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
10368 : {
10369 4904 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
10370 4904 : }
10371 :
10372 : //! @endcond
10373 :
10374 : /************************************************************************/
10375 : /* GetMetadataItem() */
10376 : /************************************************************************/
10377 :
10378 621360 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
10379 : const char *pszDomain)
10380 : {
10381 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
10382 621360 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
10383 462695 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
10384 322053 : EQUAL(pszName, "PIXELTYPE"))
10385 : {
10386 2 : CPLError(CE_Warning, CPLE_AppDefined,
10387 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
10388 : "used to signal signed 8-bit raster. Change your code to "
10389 : "test for the new GDT_Int8 data type instead.");
10390 : }
10391 621360 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
10392 : }
10393 :
10394 : /************************************************************************/
10395 : /* WindowIterator */
10396 : /************************************************************************/
10397 :
10398 : //! @cond Doxygen_Suppress
10399 :
10400 576 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
10401 : int nRasterYSize,
10402 : int nBlockXSize, int nBlockYSize,
10403 576 : int nRow, int nCol)
10404 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
10405 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
10406 576 : m_col(nCol)
10407 : {
10408 576 : }
10409 :
10410 784 : bool GDALRasterBand::WindowIterator::operator==(
10411 : const WindowIterator &other) const
10412 : {
10413 259 : return m_row == other.m_row && m_col == other.m_col &&
10414 259 : m_nRasterXSize == other.m_nRasterXSize &&
10415 259 : m_nRasterYSize == other.m_nRasterYSize &&
10416 1302 : m_nBlockXSize == other.m_nBlockXSize &&
10417 1043 : m_nBlockYSize == other.m_nBlockYSize;
10418 : }
10419 :
10420 758 : bool GDALRasterBand::WindowIterator::operator!=(
10421 : const WindowIterator &other) const
10422 : {
10423 758 : return !(*this == other);
10424 : }
10425 :
10426 : GDALRasterBand::WindowIterator::value_type
10427 524 : GDALRasterBand::WindowIterator::operator*() const
10428 : {
10429 : GDALRasterWindow ret;
10430 524 : ret.nXOff = m_col * m_nBlockXSize;
10431 524 : ret.nYOff = m_row * m_nBlockYSize;
10432 524 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
10433 524 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
10434 :
10435 524 : return ret;
10436 : }
10437 :
10438 522 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
10439 : {
10440 522 : m_col++;
10441 522 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
10442 : {
10443 438 : m_col = 0;
10444 438 : m_row++;
10445 : }
10446 522 : return *this;
10447 : }
10448 :
10449 305 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
10450 305 : const GDALRasterBand &band, size_t maxSize)
10451 305 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
10452 305 : m_nBlockXSize(-1), m_nBlockYSize(-1)
10453 : {
10454 : #ifdef CSA_BUILD
10455 : assert(this);
10456 : #endif
10457 : int nXSize, nYSize;
10458 :
10459 305 : CPLErrorStateBackuper state(CPLQuietErrorHandler);
10460 305 : band.GetBlockSize(&nXSize, &nYSize);
10461 305 : if (nXSize < 1 || nYSize < 0)
10462 : {
10463 : // If invalid block size is reported, assume scanlines
10464 4 : nXSize = m_nRasterXSize;
10465 4 : nYSize = 1;
10466 : }
10467 :
10468 305 : if (maxSize == 0)
10469 : {
10470 234 : m_nBlockXSize = nXSize;
10471 234 : m_nBlockYSize = nYSize;
10472 234 : return;
10473 : }
10474 :
10475 71 : const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
10476 71 : const double dfBlocksPerChunk =
10477 71 : static_cast<double>(maxSize) /
10478 71 : (static_cast<double>(nXSize) * static_cast<double>(nYSize));
10479 :
10480 71 : if (dfBlocksPerChunk < dfBlocksPerRow)
10481 : {
10482 14 : m_nBlockXSize = static_cast<int>(std::min<double>(
10483 14 : m_nRasterXSize,
10484 14 : nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
10485 14 : m_nBlockYSize = nYSize;
10486 : }
10487 : else
10488 : {
10489 57 : m_nBlockXSize = m_nRasterXSize;
10490 57 : m_nBlockYSize = static_cast<int>(std::min<double>(
10491 57 : m_nRasterYSize,
10492 57 : nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
10493 : }
10494 : if constexpr (sizeof(size_t) < sizeof(uint64_t))
10495 : {
10496 : if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
10497 : {
10498 : nXSize = m_nRasterXSize;
10499 : nYSize = 1;
10500 : }
10501 : }
10502 : }
10503 :
10504 : GDALRasterBand::WindowIterator
10505 274 : GDALRasterBand::WindowIteratorWrapper::begin() const
10506 : {
10507 274 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10508 274 : m_nBlockYSize, 0, 0);
10509 : }
10510 :
10511 : GDALRasterBand::WindowIterator
10512 274 : GDALRasterBand::WindowIteratorWrapper::end() const
10513 : {
10514 274 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
10515 274 : m_nBlockYSize,
10516 274 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
10517 : }
10518 :
10519 63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
10520 : {
10521 63 : return static_cast<uint64_t>(
10522 63 : cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
10523 63 : static_cast<uint64_t>(
10524 63 : cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
10525 : }
10526 :
10527 : //! @endcond
10528 :
10529 : /** Return an object whose begin() and end() methods can be used to iterate
10530 : * over GDALRasterWindow objects that are aligned with blocks in this raster
10531 : * band. The iteration order is from left to right, then from top to bottom.
10532 : *
10533 : \code{.cpp}
10534 : std::vector<double> pixelValues;
10535 : for (const auto& window : poBand->IterateWindows()) {
10536 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
10537 : window.nXSize, window.nYSize);
10538 : // check eErr
10539 : }
10540 : \endcode
10541 : *
10542 : *
10543 : * @param maxSize The maximum number of pixels in each window. If set to
10544 : * zero (the default), or a number smaller than the block size,
10545 : * the window size will be the same as the block size.
10546 : * @since GDAL 3.12
10547 : */
10548 : GDALRasterBand::WindowIteratorWrapper
10549 305 : GDALRasterBand::IterateWindows(size_t maxSize) const
10550 : {
10551 305 : return WindowIteratorWrapper(*this, maxSize);
10552 : }
10553 :
10554 : /************************************************************************/
10555 : /* GDALMDArrayFromRasterBand */
10556 : /************************************************************************/
10557 :
10558 : class GDALMDArrayFromRasterBand final : public GDALMDArray
10559 : {
10560 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
10561 :
10562 : GDALDataset *m_poDS;
10563 : GDALRasterBand *m_poBand;
10564 : GDALExtendedDataType m_dt;
10565 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
10566 : std::string m_osUnit;
10567 : std::vector<GByte> m_pabyNoData{};
10568 : std::shared_ptr<GDALMDArray> m_varX{};
10569 : std::shared_ptr<GDALMDArray> m_varY{};
10570 : std::string m_osFilename{};
10571 :
10572 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
10573 : const size_t *count, const GInt64 *arrayStep,
10574 : const GPtrDiff_t *bufferStride,
10575 : const GDALExtendedDataType &bufferDataType,
10576 : void *pBuffer) const;
10577 :
10578 : protected:
10579 34 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
10580 68 : : GDALAbstractMDArray(std::string(),
10581 68 : std::string(poDS->GetDescription()) +
10582 : CPLSPrintf(" band %d", poBand->GetBand())),
10583 68 : GDALMDArray(std::string(),
10584 68 : std::string(poDS->GetDescription()) +
10585 : CPLSPrintf(" band %d", poBand->GetBand())),
10586 : m_poDS(poDS), m_poBand(poBand),
10587 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
10588 170 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
10589 : {
10590 34 : m_poDS->Reference();
10591 :
10592 34 : int bHasNoData = false;
10593 34 : if (m_poBand->GetRasterDataType() == GDT_Int64)
10594 : {
10595 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
10596 0 : if (bHasNoData)
10597 : {
10598 0 : m_pabyNoData.resize(m_dt.GetSize());
10599 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
10600 : m_dt.GetNumericDataType(), 0, 1);
10601 : }
10602 : }
10603 34 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
10604 : {
10605 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
10606 0 : if (bHasNoData)
10607 : {
10608 0 : m_pabyNoData.resize(m_dt.GetSize());
10609 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
10610 : m_dt.GetNumericDataType(), 0, 1);
10611 : }
10612 : }
10613 : else
10614 : {
10615 34 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
10616 34 : if (bHasNoData)
10617 : {
10618 1 : m_pabyNoData.resize(m_dt.GetSize());
10619 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
10620 : m_dt.GetNumericDataType(), 0, 1);
10621 : }
10622 : }
10623 :
10624 34 : const int nXSize = poBand->GetXSize();
10625 34 : const int nYSize = poBand->GetYSize();
10626 :
10627 34 : auto poSRS = m_poDS->GetSpatialRef();
10628 68 : std::string osTypeY;
10629 68 : std::string osTypeX;
10630 68 : std::string osDirectionY;
10631 68 : std::string osDirectionX;
10632 34 : if (poSRS && poSRS->GetAxesCount() == 2)
10633 : {
10634 24 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
10635 24 : OGRAxisOrientation eOrientation1 = OAO_Other;
10636 24 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
10637 24 : OGRAxisOrientation eOrientation2 = OAO_Other;
10638 24 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
10639 24 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
10640 : {
10641 8 : if (mapping == std::vector<int>{1, 2})
10642 : {
10643 8 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10644 8 : osDirectionY = "NORTH";
10645 8 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10646 8 : osDirectionX = "EAST";
10647 : }
10648 : }
10649 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
10650 : {
10651 16 : if (mapping == std::vector<int>{2, 1})
10652 : {
10653 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
10654 16 : osDirectionY = "NORTH";
10655 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
10656 16 : osDirectionX = "EAST";
10657 : }
10658 : }
10659 : }
10660 :
10661 170 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
10662 : "/", "Y", osTypeY, osDirectionY, nYSize),
10663 68 : std::make_shared<GDALDimensionWeakIndexingVar>(
10664 102 : "/", "X", osTypeX, osDirectionX, nXSize)};
10665 :
10666 34 : GDALGeoTransform gt;
10667 34 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
10668 : {
10669 50 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
10670 50 : gt[0], gt[1], 0.5);
10671 25 : m_dims[1]->SetIndexingVariable(m_varX);
10672 :
10673 50 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
10674 50 : gt[3], gt[5], 0.5);
10675 25 : m_dims[0]->SetIndexingVariable(m_varY);
10676 : }
10677 34 : }
10678 :
10679 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
10680 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10681 : const GDALExtendedDataType &bufferDataType,
10682 : void *pDstBuffer) const override;
10683 :
10684 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
10685 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10686 : const GDALExtendedDataType &bufferDataType,
10687 : const void *pSrcBuffer) override
10688 : {
10689 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
10690 : bufferStride, bufferDataType,
10691 1 : const_cast<void *>(pSrcBuffer));
10692 : }
10693 :
10694 : public:
10695 68 : ~GDALMDArrayFromRasterBand() override
10696 34 : {
10697 34 : m_poDS->ReleaseRef();
10698 68 : }
10699 :
10700 34 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
10701 : GDALRasterBand *poBand)
10702 : {
10703 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
10704 68 : new GDALMDArrayFromRasterBand(poDS, poBand)));
10705 34 : array->SetSelf(array);
10706 68 : return array;
10707 : }
10708 :
10709 5 : bool IsWritable() const override
10710 : {
10711 5 : return m_poDS->GetAccess() == GA_Update;
10712 : }
10713 :
10714 122 : const std::string &GetFilename() const override
10715 : {
10716 122 : return m_osFilename;
10717 : }
10718 :
10719 : const std::vector<std::shared_ptr<GDALDimension>> &
10720 343 : GetDimensions() const override
10721 : {
10722 343 : return m_dims;
10723 : }
10724 :
10725 158 : const GDALExtendedDataType &GetDataType() const override
10726 : {
10727 158 : return m_dt;
10728 : }
10729 :
10730 5 : const std::string &GetUnit() const override
10731 : {
10732 5 : return m_osUnit;
10733 : }
10734 :
10735 32 : const void *GetRawNoDataValue() const override
10736 : {
10737 32 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
10738 : }
10739 :
10740 4 : double GetOffset(bool *pbHasOffset,
10741 : GDALDataType *peStorageType) const override
10742 : {
10743 4 : int bHasOffset = false;
10744 4 : double dfRes = m_poBand->GetOffset(&bHasOffset);
10745 4 : if (pbHasOffset)
10746 4 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
10747 4 : if (peStorageType)
10748 1 : *peStorageType = GDT_Unknown;
10749 4 : return dfRes;
10750 : }
10751 :
10752 4 : double GetScale(bool *pbHasScale,
10753 : GDALDataType *peStorageType) const override
10754 : {
10755 4 : int bHasScale = false;
10756 4 : double dfRes = m_poBand->GetScale(&bHasScale);
10757 4 : if (pbHasScale)
10758 4 : *pbHasScale = CPL_TO_BOOL(bHasScale);
10759 4 : if (peStorageType)
10760 1 : *peStorageType = GDT_Unknown;
10761 4 : return dfRes;
10762 : }
10763 :
10764 88 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
10765 : {
10766 88 : auto poSrcSRS = m_poDS->GetSpatialRef();
10767 88 : if (!poSrcSRS)
10768 2 : return nullptr;
10769 172 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
10770 :
10771 172 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
10772 86 : constexpr int iYDim = 0;
10773 86 : constexpr int iXDim = 1;
10774 258 : for (auto &m : axisMapping)
10775 : {
10776 172 : if (m == 1)
10777 86 : m = iXDim + 1;
10778 86 : else if (m == 2)
10779 86 : m = iYDim + 1;
10780 : else
10781 0 : m = 0;
10782 : }
10783 86 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
10784 86 : return poSRS;
10785 : }
10786 :
10787 32 : std::vector<GUInt64> GetBlockSize() const override
10788 : {
10789 32 : int nBlockXSize = 0;
10790 32 : int nBlockYSize = 0;
10791 32 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
10792 32 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
10793 32 : static_cast<GUInt64>(nBlockXSize)};
10794 : }
10795 :
10796 : std::vector<std::shared_ptr<GDALAttribute>>
10797 23 : GetAttributes(CSLConstList) const override
10798 : {
10799 23 : std::vector<std::shared_ptr<GDALAttribute>> res;
10800 23 : auto papszMD = m_poBand->GetMetadata();
10801 25 : for (auto iter = papszMD; iter && iter[0]; ++iter)
10802 : {
10803 2 : char *pszKey = nullptr;
10804 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
10805 2 : if (pszKey && pszValue)
10806 : {
10807 : res.emplace_back(
10808 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
10809 : }
10810 2 : CPLFree(pszKey);
10811 : }
10812 23 : return res;
10813 : }
10814 : };
10815 :
10816 39 : bool GDALMDArrayFromRasterBand::IRead(
10817 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
10818 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
10819 : void *pDstBuffer) const
10820 : {
10821 39 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
10822 39 : bufferDataType, pDstBuffer);
10823 : }
10824 :
10825 : /************************************************************************/
10826 : /* ReadWrite() */
10827 : /************************************************************************/
10828 :
10829 40 : bool GDALMDArrayFromRasterBand::ReadWrite(
10830 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
10831 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
10832 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
10833 : {
10834 40 : constexpr size_t iDimX = 1;
10835 40 : constexpr size_t iDimY = 0;
10836 40 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10837 : arrayStartIdx, count, arrayStep, bufferStride,
10838 40 : bufferDataType, pBuffer);
10839 : }
10840 :
10841 : /************************************************************************/
10842 : /* GDALMDRasterIOFromBand() */
10843 : /************************************************************************/
10844 :
10845 73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10846 : size_t iDimX, size_t iDimY,
10847 : const GUInt64 *arrayStartIdx, const size_t *count,
10848 : const GInt64 *arrayStep,
10849 : const GPtrDiff_t *bufferStride,
10850 : const GDALExtendedDataType &bufferDataType,
10851 : void *pBuffer)
10852 : {
10853 73 : const auto eDT(bufferDataType.GetNumericDataType());
10854 73 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10855 73 : const int nX =
10856 73 : arrayStep[iDimX] > 0
10857 73 : ? static_cast<int>(arrayStartIdx[iDimX])
10858 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10859 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10860 73 : const int nY =
10861 73 : arrayStep[iDimY] > 0
10862 73 : ? static_cast<int>(arrayStartIdx[iDimY])
10863 6 : : static_cast<int>(arrayStartIdx[iDimY] -
10864 6 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10865 73 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10866 73 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10867 73 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10868 73 : int nStrideXSign = 1;
10869 73 : if (arrayStep[iDimX] < 0)
10870 : {
10871 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10872 2 : nStrideXSign = -1;
10873 : }
10874 73 : int nStrideYSign = 1;
10875 73 : if (arrayStep[iDimY] < 0)
10876 : {
10877 6 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10878 6 : nStrideYSign = -1;
10879 : }
10880 :
10881 146 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10882 73 : static_cast<int>(count[iDimX]),
10883 73 : static_cast<int>(count[iDimY]), eDT,
10884 : static_cast<GSpacing>(
10885 73 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10886 : static_cast<GSpacing>(
10887 73 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10888 73 : nullptr) == CE_None;
10889 : }
10890 :
10891 : /************************************************************************/
10892 : /* AsMDArray() */
10893 : /************************************************************************/
10894 :
10895 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10896 : *
10897 : * The band must be linked to a GDALDataset. If this dataset is not already
10898 : * marked as shared, it will be, so that the returned array holds a reference
10899 : * to it.
10900 : *
10901 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10902 : * returned array will have an associated indexing variable.
10903 : *
10904 : * This is the same as the C function GDALRasterBandAsMDArray().
10905 : *
10906 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10907 : *
10908 : * @return a new array, or nullptr.
10909 : *
10910 : * @since GDAL 3.1
10911 : */
10912 34 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10913 : {
10914 34 : if (!poDS)
10915 : {
10916 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10917 0 : return nullptr;
10918 : }
10919 34 : if (!poDS->GetShared())
10920 : {
10921 33 : poDS->MarkAsShared();
10922 : }
10923 : return GDALMDArrayFromRasterBand::Create(
10924 34 : poDS, const_cast<GDALRasterBand *>(this));
10925 : }
10926 :
10927 : /************************************************************************/
10928 : /* InterpolateAtPoint() */
10929 : /************************************************************************/
10930 :
10931 : /**
10932 : * \brief Interpolates the value between pixels using a resampling algorithm,
10933 : * taking pixel/line coordinates as input.
10934 : *
10935 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10936 : * @param dfLine line coordinate as a double, where interpolation should be done.
10937 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10938 : * @param pdfRealValue pointer to real part of interpolated value
10939 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10940 : *
10941 : * @return CE_None on success, or an error code on failure.
10942 : * @since GDAL 3.10
10943 : */
10944 :
10945 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10946 : GDALRIOResampleAlg eInterpolation,
10947 : double *pdfRealValue,
10948 : double *pdfImagValue) const
10949 : {
10950 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10951 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10952 : eInterpolation != GRIORA_CubicSpline)
10953 : {
10954 2 : CPLError(CE_Failure, CPLE_AppDefined,
10955 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10956 : "methods "
10957 : "allowed");
10958 :
10959 2 : return CE_Failure;
10960 : }
10961 :
10962 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10963 165 : if (!m_poPointsCache)
10964 85 : m_poPointsCache = new GDALDoublePointsCache();
10965 :
10966 : const bool res =
10967 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10968 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10969 :
10970 165 : return res ? CE_None : CE_Failure;
10971 : }
10972 :
10973 : /************************************************************************/
10974 : /* GDALRasterInterpolateAtPoint() */
10975 : /************************************************************************/
10976 :
10977 : /**
10978 : * \brief Interpolates the value between pixels using
10979 : * a resampling algorithm
10980 : *
10981 : * @see GDALRasterBand::InterpolateAtPoint()
10982 : * @since GDAL 3.10
10983 : */
10984 :
10985 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10986 : double dfLine,
10987 : GDALRIOResampleAlg eInterpolation,
10988 : double *pdfRealValue, double *pdfImagValue)
10989 : {
10990 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10991 :
10992 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10993 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10994 144 : pdfRealValue, pdfImagValue);
10995 : }
10996 :
10997 : /************************************************************************/
10998 : /* InterpolateAtGeolocation() */
10999 : /************************************************************************/
11000 :
11001 : /**
11002 : * \brief Interpolates the value between pixels using a resampling algorithm,
11003 : * taking georeferenced coordinates as input.
11004 : *
11005 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
11006 : * must be in the "natural" SRS of the dataset, that is the one returned by
11007 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
11008 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
11009 : * array (generally WGS 84) if there is a geolocation array.
11010 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
11011 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
11012 : * be a easting, and dfGeolocY a northing.
11013 : *
11014 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
11015 : * expressed in that CRS, and that tuple must be conformant with the
11016 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
11017 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
11018 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
11019 : * before calling this method, and in that case, dfGeolocX must be a longitude
11020 : * or an easting value, and dfGeolocX a latitude or a northing value.
11021 : *
11022 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
11023 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
11024 : * it for details on how that transformation is done.
11025 : *
11026 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
11027 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11028 : * where interpolation should be done.
11029 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
11030 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
11031 : * where interpolation should be done.
11032 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
11033 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
11034 : * @param pdfRealValue pointer to real part of interpolated value
11035 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
11036 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
11037 : *
11038 : * @return CE_None on success, or an error code on failure.
11039 : * @since GDAL 3.11
11040 : */
11041 :
11042 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
11043 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
11044 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
11045 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
11046 : {
11047 : double dfPixel;
11048 : double dfLine;
11049 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
11050 : &dfLine,
11051 15 : papszTransformerOptions) != CE_None)
11052 : {
11053 1 : return CE_Failure;
11054 : }
11055 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
11056 14 : pdfImagValue);
11057 : }
11058 :
11059 : /************************************************************************/
11060 : /* GDALRasterInterpolateAtGeolocation() */
11061 : /************************************************************************/
11062 :
11063 : /**
11064 : * \brief Interpolates the value between pixels using a resampling algorithm,
11065 : * taking georeferenced coordinates as input.
11066 : *
11067 : * @see GDALRasterBand::InterpolateAtGeolocation()
11068 : * @since GDAL 3.11
11069 : */
11070 :
11071 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
11072 : double dfGeolocX, double dfGeolocY,
11073 : OGRSpatialReferenceH hSRS,
11074 : GDALRIOResampleAlg eInterpolation,
11075 : double *pdfRealValue,
11076 : double *pdfImagValue,
11077 : CSLConstList papszTransformerOptions)
11078 : {
11079 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
11080 :
11081 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
11082 15 : return poBand->InterpolateAtGeolocation(
11083 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
11084 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
11085 : }
11086 :
11087 : /************************************************************************/
11088 : /* GDALRasterBand::SplitRasterIO() */
11089 : /************************************************************************/
11090 :
11091 : //! @cond Doxygen_Suppress
11092 :
11093 : /** Implements IRasterIO() by dividing the request in 2.
11094 : *
11095 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
11096 : *
11097 : * Return CE_Warning if the split could not be done, CE_None in case of
11098 : * success and CE_Failure in case of error.
11099 : *
11100 : * @since 3.12
11101 : */
11102 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
11103 : [[maybe_unused]] int nXSize,
11104 : [[maybe_unused]] int nYSize, void *pData,
11105 : int nBufXSize, int nBufYSize,
11106 : GDALDataType eBufType,
11107 : GSpacing nPixelSpace, GSpacing nLineSpace,
11108 : GDALRasterIOExtraArg *psExtraArg)
11109 : {
11110 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
11111 :
11112 999 : GByte *pabyData = static_cast<GByte *>(pData);
11113 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
11114 : {
11115 : GDALRasterIOExtraArg sArg;
11116 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
11117 499 : const int nHalfHeight = nBufYSize / 2;
11118 :
11119 499 : sArg.pfnProgress = GDALScaledProgress;
11120 499 : sArg.pProgressData = GDALCreateScaledProgress(
11121 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11122 499 : if (sArg.pProgressData == nullptr)
11123 499 : sArg.pfnProgress = nullptr;
11124 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
11125 : pabyData, nBufXSize, nHalfHeight, eBufType,
11126 499 : nPixelSpace, nLineSpace, &sArg);
11127 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11128 :
11129 499 : if (eErr == CE_None)
11130 : {
11131 499 : sArg.pfnProgress = GDALScaledProgress;
11132 499 : sArg.pProgressData = GDALCreateScaledProgress(
11133 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11134 499 : if (sArg.pProgressData == nullptr)
11135 499 : sArg.pfnProgress = nullptr;
11136 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
11137 : nBufYSize - nHalfHeight,
11138 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
11139 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
11140 499 : nLineSpace, &sArg);
11141 499 : GDALDestroyScaledProgress(sArg.pProgressData);
11142 : }
11143 499 : return eErr;
11144 : }
11145 500 : else if (nBufXSize >= 2)
11146 : {
11147 : GDALRasterIOExtraArg sArg;
11148 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
11149 500 : const int nHalfWidth = nBufXSize / 2;
11150 :
11151 500 : sArg.pfnProgress = GDALScaledProgress;
11152 500 : sArg.pProgressData = GDALCreateScaledProgress(
11153 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11154 500 : if (sArg.pProgressData == nullptr)
11155 500 : sArg.pfnProgress = nullptr;
11156 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
11157 : pabyData, nHalfWidth, nBufYSize, eBufType,
11158 500 : nPixelSpace, nLineSpace, &sArg);
11159 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11160 :
11161 500 : if (eErr == CE_None)
11162 : {
11163 500 : sArg.pfnProgress = GDALScaledProgress;
11164 500 : sArg.pProgressData = GDALCreateScaledProgress(
11165 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
11166 500 : if (sArg.pProgressData == nullptr)
11167 500 : sArg.pfnProgress = nullptr;
11168 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
11169 : nBufXSize - nHalfWidth, nBufYSize,
11170 500 : pabyData + nHalfWidth * nPixelSpace,
11171 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
11172 500 : nPixelSpace, nLineSpace, &sArg);
11173 500 : GDALDestroyScaledProgress(sArg.pProgressData);
11174 : }
11175 500 : return eErr;
11176 : }
11177 :
11178 0 : return CE_Warning;
11179 : }
11180 :
11181 : //! @endcond
11182 :
11183 : /************************************************************************/
11184 : /* ThrowIfNotSameDimensions() */
11185 : /************************************************************************/
11186 :
11187 : //! @cond Doxygen_Suppress
11188 : /* static */
11189 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
11190 : const GDALRasterBand &second)
11191 : {
11192 320 : if (first.GetXSize() != second.GetXSize() ||
11193 151 : first.GetYSize() != second.GetYSize())
11194 : {
11195 36 : throw std::runtime_error("Bands do not have the same dimensions");
11196 : }
11197 133 : }
11198 :
11199 : //! @endcond
11200 :
11201 : /************************************************************************/
11202 : /* GDALRasterBandUnaryOp() */
11203 : /************************************************************************/
11204 :
11205 : /** Apply a unary operation on this band.
11206 : *
11207 : * The resulting band is lazy evaluated. A reference is taken on the input
11208 : * dataset.
11209 : *
11210 : * @since 3.12
11211 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11212 : */
11213 : GDALComputedRasterBandH
11214 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
11215 : GDALRasterAlgebraUnaryOperation eOp)
11216 : {
11217 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11218 6 : GDALComputedRasterBand::Operation cppOp{};
11219 6 : switch (eOp)
11220 : {
11221 2 : case GRAUO_LOGICAL_NOT:
11222 : return new GDALComputedRasterBand(
11223 : GDALComputedRasterBand::Operation::OP_NE,
11224 2 : *(GDALRasterBand::FromHandle(hBand)), true);
11225 1 : case GRAUO_ABS:
11226 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
11227 1 : break;
11228 1 : case GRAUO_SQRT:
11229 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
11230 1 : break;
11231 1 : case GRAUO_LOG:
11232 : #ifndef HAVE_MUPARSER
11233 : CPLError(
11234 : CE_Failure, CPLE_NotSupported,
11235 : "log(band) not available on a GDAL build without muparser");
11236 : return nullptr;
11237 : #else
11238 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
11239 1 : break;
11240 : #endif
11241 1 : case GRAUO_LOG10:
11242 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
11243 1 : break;
11244 : }
11245 : return new GDALComputedRasterBand(cppOp,
11246 4 : *(GDALRasterBand::FromHandle(hBand)));
11247 : }
11248 :
11249 : /************************************************************************/
11250 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
11251 : /************************************************************************/
11252 :
11253 : static GDALComputedRasterBand::Operation
11254 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
11255 : GDALRasterAlgebraBinaryOperation eOp)
11256 : {
11257 120 : switch (eOp)
11258 : {
11259 26 : case GRABO_ADD:
11260 26 : return GDALComputedRasterBand::Operation::OP_ADD;
11261 2 : case GRABO_SUB:
11262 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
11263 24 : case GRABO_MUL:
11264 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
11265 3 : case GRABO_DIV:
11266 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
11267 6 : case GRABO_GT:
11268 6 : return GDALComputedRasterBand::Operation::OP_GT;
11269 8 : case GRABO_GE:
11270 8 : return GDALComputedRasterBand::Operation::OP_GE;
11271 6 : case GRABO_LT:
11272 6 : return GDALComputedRasterBand::Operation::OP_LT;
11273 6 : case GRABO_LE:
11274 6 : return GDALComputedRasterBand::Operation::OP_LE;
11275 6 : case GRABO_EQ:
11276 6 : return GDALComputedRasterBand::Operation::OP_EQ;
11277 6 : case GRABO_NE:
11278 6 : break;
11279 12 : case GRABO_LOGICAL_AND:
11280 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
11281 12 : case GRABO_LOGICAL_OR:
11282 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
11283 3 : case GRABO_POW:
11284 3 : return GDALComputedRasterBand::Operation::OP_POW;
11285 : }
11286 6 : return GDALComputedRasterBand::Operation::OP_NE;
11287 : }
11288 :
11289 : /************************************************************************/
11290 : /* GDALRasterBandBinaryOpBand() */
11291 : /************************************************************************/
11292 :
11293 : /** Apply a binary operation on this band with another one.
11294 : *
11295 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
11296 : * "hBand1 - hBand2".
11297 : *
11298 : * The resulting band is lazy evaluated. A reference is taken on both input
11299 : * datasets.
11300 : *
11301 : * @since 3.12
11302 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11303 : */
11304 : GDALComputedRasterBandH
11305 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
11306 : GDALRasterAlgebraBinaryOperation eOp,
11307 : GDALRasterBandH hOtherBand)
11308 : {
11309 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11310 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
11311 : #ifndef HAVE_MUPARSER
11312 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11313 : {
11314 : CPLError(
11315 : CE_Failure, CPLE_NotSupported,
11316 : "Band comparison operators not available on a GDAL build without "
11317 : "muparser");
11318 : return nullptr;
11319 : }
11320 : else if (eOp == GRABO_POW)
11321 : {
11322 : CPLError(
11323 : CE_Failure, CPLE_NotSupported,
11324 : "pow(band, band) not available on a GDAL build without muparser");
11325 : return nullptr;
11326 : }
11327 : #endif
11328 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
11329 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
11330 : try
11331 : {
11332 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
11333 : }
11334 13 : catch (const std::exception &e)
11335 : {
11336 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11337 13 : return nullptr;
11338 : }
11339 : return new GDALComputedRasterBand(
11340 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
11341 44 : secondBand);
11342 : }
11343 :
11344 : /************************************************************************/
11345 : /* GDALRasterBandBinaryOpDouble() */
11346 : /************************************************************************/
11347 :
11348 : /** Apply a binary operation on this band with a constant
11349 : *
11350 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
11351 : * "hBand - constant".
11352 : *
11353 : * The resulting band is lazy evaluated. A reference is taken on the input
11354 : * dataset.
11355 : *
11356 : * @since 3.12
11357 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11358 : */
11359 : GDALComputedRasterBandH
11360 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
11361 : GDALRasterAlgebraBinaryOperation eOp,
11362 : double constant)
11363 : {
11364 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11365 : #ifndef HAVE_MUPARSER
11366 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11367 : {
11368 : CPLError(
11369 : CE_Failure, CPLE_NotSupported,
11370 : "Band comparison operators not available on a GDAL build without "
11371 : "muparser");
11372 : return nullptr;
11373 : }
11374 : #endif
11375 : return new GDALComputedRasterBand(
11376 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11377 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
11378 : }
11379 :
11380 : /************************************************************************/
11381 : /* GDALRasterBandBinaryOpDoubleToBand() */
11382 : /************************************************************************/
11383 :
11384 : /** Apply a binary operation on the constant with this band
11385 : *
11386 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
11387 : * "constant - hBand".
11388 : *
11389 : * The resulting band is lazy evaluated. A reference is taken on the input
11390 : * dataset.
11391 : *
11392 : * @since 3.12
11393 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11394 : */
11395 : GDALComputedRasterBandH
11396 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
11397 : GDALRasterAlgebraBinaryOperation eOp,
11398 : GDALRasterBandH hBand)
11399 : {
11400 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11401 : #ifndef HAVE_MUPARSER
11402 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
11403 : {
11404 : CPLError(
11405 : CE_Failure, CPLE_NotSupported,
11406 : "Band comparison operators not available on a GDAL build without "
11407 : "muparser");
11408 : return nullptr;
11409 : }
11410 : #endif
11411 18 : switch (eOp)
11412 : {
11413 15 : case GRABO_ADD:
11414 : case GRABO_MUL:
11415 : {
11416 : return new GDALComputedRasterBand(
11417 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
11418 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
11419 : }
11420 :
11421 2 : case GRABO_DIV:
11422 : case GRABO_GT:
11423 : case GRABO_GE:
11424 : case GRABO_LT:
11425 : case GRABO_LE:
11426 : case GRABO_EQ:
11427 : case GRABO_NE:
11428 : case GRABO_LOGICAL_AND:
11429 : case GRABO_LOGICAL_OR:
11430 : case GRABO_POW:
11431 : {
11432 : return new GDALComputedRasterBand(
11433 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
11434 2 : *(GDALRasterBand::FromHandle(hBand)));
11435 : }
11436 :
11437 1 : case GRABO_SUB:
11438 : {
11439 1 : break;
11440 : }
11441 : }
11442 :
11443 : return new GDALComputedRasterBand(
11444 : GDALComputedRasterBand::Operation::OP_ADD,
11445 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
11446 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
11447 1 : constant);
11448 : }
11449 :
11450 : /************************************************************************/
11451 : /* operator+() */
11452 : /************************************************************************/
11453 :
11454 : /** Add this band with another one.
11455 : *
11456 : * The resulting band is lazy evaluated. A reference is taken on both input
11457 : * datasets.
11458 : *
11459 : * @since 3.12
11460 : * @throw std::runtime_error if both bands do not have the same dimensions.
11461 : */
11462 : GDALComputedRasterBand
11463 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
11464 : {
11465 8 : ThrowIfNotSameDimensions(*this, other);
11466 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11467 7 : *this, other);
11468 : }
11469 :
11470 : /************************************************************************/
11471 : /* operator+() */
11472 : /************************************************************************/
11473 :
11474 : /** Add this band with a constant.
11475 : *
11476 : * The resulting band is lazy evaluated. A reference is taken on the input
11477 : * dataset.
11478 : *
11479 : * @since 3.12
11480 : */
11481 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
11482 : {
11483 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
11484 13 : *this, constant);
11485 : }
11486 :
11487 : /************************************************************************/
11488 : /* operator+() */
11489 : /************************************************************************/
11490 :
11491 : /** Add a band with a constant.
11492 : *
11493 : * The resulting band is lazy evaluated. A reference is taken on the input
11494 : * dataset.
11495 : *
11496 : * @since 3.12
11497 : */
11498 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
11499 : {
11500 1 : return other + constant;
11501 : }
11502 :
11503 : /************************************************************************/
11504 : /* operator-() */
11505 : /************************************************************************/
11506 :
11507 : /** Return a band whose value is the opposite value of the band for each
11508 : * pixel.
11509 : *
11510 : * The resulting band is lazy evaluated. A reference is taken on the input
11511 : * dataset.
11512 : *
11513 : * @since 3.12
11514 : */
11515 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
11516 : {
11517 2 : return 0 - *this;
11518 : }
11519 :
11520 : /************************************************************************/
11521 : /* operator-() */
11522 : /************************************************************************/
11523 :
11524 : /** Subtract this band with another one.
11525 : *
11526 : * The resulting band is lazy evaluated. A reference is taken on both input
11527 : * datasets.
11528 : *
11529 : * @since 3.12
11530 : * @throw std::runtime_error if both bands do not have the same dimensions.
11531 : */
11532 : GDALComputedRasterBand
11533 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
11534 : {
11535 2 : ThrowIfNotSameDimensions(*this, other);
11536 : return GDALComputedRasterBand(
11537 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
11538 : }
11539 :
11540 : /************************************************************************/
11541 : /* operator-() */
11542 : /************************************************************************/
11543 :
11544 : /** Subtract this band with a constant.
11545 : *
11546 : * The resulting band is lazy evaluated. A reference is taken on the input
11547 : * dataset.
11548 : *
11549 : * @since 3.12
11550 : */
11551 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
11552 : {
11553 : return GDALComputedRasterBand(
11554 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
11555 : }
11556 :
11557 : /************************************************************************/
11558 : /* operator-() */
11559 : /************************************************************************/
11560 :
11561 : /** Subtract a constant with a band.
11562 : *
11563 : * The resulting band is lazy evaluated. A reference is taken on the input
11564 : * dataset.
11565 : *
11566 : * @since 3.12
11567 : */
11568 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
11569 : {
11570 6 : return other * (-1.0) + constant;
11571 : }
11572 :
11573 : /************************************************************************/
11574 : /* operator*() */
11575 : /************************************************************************/
11576 :
11577 : /** Multiply this band with another one.
11578 : *
11579 : * The resulting band is lazy evaluated. A reference is taken on both input
11580 : * datasets.
11581 : *
11582 : * @since 3.12
11583 : * @throw std::runtime_error if both bands do not have the same dimensions.
11584 : */
11585 : GDALComputedRasterBand
11586 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
11587 : {
11588 2 : ThrowIfNotSameDimensions(*this, other);
11589 : return GDALComputedRasterBand(
11590 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
11591 : }
11592 :
11593 : /************************************************************************/
11594 : /* operator*() */
11595 : /************************************************************************/
11596 :
11597 : /** Multiply this band by a constant.
11598 : *
11599 : * The resulting band is lazy evaluated. A reference is taken on the input
11600 : * dataset.
11601 : *
11602 : * @since 3.12
11603 : */
11604 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
11605 : {
11606 : return GDALComputedRasterBand(
11607 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
11608 : }
11609 :
11610 : /************************************************************************/
11611 : /* operator*() */
11612 : /************************************************************************/
11613 :
11614 : /** Multiply a band with a constant.
11615 : *
11616 : * The resulting band is lazy evaluated. A reference is taken on the input
11617 : * dataset.
11618 : *
11619 : * @since 3.12
11620 : */
11621 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
11622 : {
11623 2 : return other * constant;
11624 : }
11625 :
11626 : /************************************************************************/
11627 : /* operator/() */
11628 : /************************************************************************/
11629 :
11630 : /** Divide this band with another one.
11631 : *
11632 : * The resulting band is lazy evaluated. A reference is taken on both input
11633 : * datasets.
11634 : *
11635 : * @since 3.12
11636 : * @throw std::runtime_error if both bands do not have the same dimensions.
11637 : */
11638 : GDALComputedRasterBand
11639 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
11640 : {
11641 2 : ThrowIfNotSameDimensions(*this, other);
11642 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11643 2 : *this, other);
11644 : }
11645 :
11646 : /************************************************************************/
11647 : /* operator/() */
11648 : /************************************************************************/
11649 :
11650 : /** Divide this band by a constant.
11651 : *
11652 : * The resulting band is lazy evaluated. A reference is taken on the input
11653 : * dataset.
11654 : *
11655 : * @since 3.12
11656 : */
11657 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
11658 : {
11659 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11660 0 : *this, constant);
11661 : }
11662 :
11663 : /************************************************************************/
11664 : /* operator/() */
11665 : /************************************************************************/
11666 :
11667 : /** Divide a constant by a band.
11668 : *
11669 : * The resulting band is lazy evaluated. A reference is taken on the input
11670 : * dataset.
11671 : *
11672 : * @since 3.12
11673 : */
11674 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
11675 : {
11676 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
11677 1 : constant, other);
11678 : }
11679 :
11680 : /************************************************************************/
11681 : /* ThrowIfNotMuparser() */
11682 : /************************************************************************/
11683 :
11684 : #ifndef HAVE_MUPARSER
11685 : static GDALComputedRasterBand ThrowIfNotMuparser()
11686 : {
11687 : throw std::runtime_error("Operator not available on a "
11688 : "GDAL build without muparser");
11689 : }
11690 : #endif
11691 :
11692 : /************************************************************************/
11693 : /* operator>() */
11694 : /************************************************************************/
11695 :
11696 : /** Return a band whose value is 1 if the pixel value of the left operand
11697 : * is greater than the pixel value of the right operand.
11698 : *
11699 : * The resulting band is lazy evaluated. A reference is taken on the input
11700 : * dataset.
11701 : *
11702 : * @since 3.12
11703 : */
11704 : GDALComputedRasterBand
11705 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
11706 : {
11707 : #ifndef HAVE_MUPARSER
11708 : (void)other;
11709 : return ThrowIfNotMuparser();
11710 : #else
11711 3 : ThrowIfNotSameDimensions(*this, other);
11712 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11713 2 : *this, other);
11714 : #endif
11715 : }
11716 :
11717 : /************************************************************************/
11718 : /* operator>() */
11719 : /************************************************************************/
11720 :
11721 : /** Return a band whose value is 1 if the pixel value of the left operand
11722 : * is greater than the constant.
11723 : *
11724 : * The resulting band is lazy evaluated. A reference is taken on the input
11725 : * dataset.
11726 : *
11727 : * @since 3.12
11728 : */
11729 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
11730 : {
11731 : #ifndef HAVE_MUPARSER
11732 : (void)constant;
11733 : return ThrowIfNotMuparser();
11734 : #else
11735 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11736 3 : *this, constant);
11737 : #endif
11738 : }
11739 :
11740 : /************************************************************************/
11741 : /* operator>() */
11742 : /************************************************************************/
11743 :
11744 : /** Return a band whose value is 1 if the constant is greater than the pixel
11745 : * value of the right operand.
11746 : *
11747 : * The resulting band is lazy evaluated. A reference is taken on the input
11748 : * dataset.
11749 : *
11750 : * @since 3.12
11751 : */
11752 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
11753 : {
11754 : #ifndef HAVE_MUPARSER
11755 : (void)constant;
11756 : (void)other;
11757 : return ThrowIfNotMuparser();
11758 : #else
11759 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
11760 2 : constant, other);
11761 : #endif
11762 : }
11763 :
11764 : /************************************************************************/
11765 : /* operator>=() */
11766 : /************************************************************************/
11767 :
11768 : /** Return a band whose value is 1 if the pixel value of the left operand
11769 : * is greater or equal to the pixel value of the right operand.
11770 : *
11771 : * The resulting band is lazy evaluated. A reference is taken on the input
11772 : * dataset.
11773 : *
11774 : * @since 3.12
11775 : */
11776 : GDALComputedRasterBand
11777 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
11778 : {
11779 : #ifndef HAVE_MUPARSER
11780 : (void)other;
11781 : return ThrowIfNotMuparser();
11782 : #else
11783 4 : ThrowIfNotSameDimensions(*this, other);
11784 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11785 3 : *this, other);
11786 : #endif
11787 : }
11788 :
11789 : /************************************************************************/
11790 : /* operator>=() */
11791 : /************************************************************************/
11792 :
11793 : /** Return a band whose value is 1 if the pixel value of the left operand
11794 : * is greater or equal to the constant.
11795 : *
11796 : * The resulting band is lazy evaluated. A reference is taken on the input
11797 : * dataset.
11798 : *
11799 : * @since 3.12
11800 : */
11801 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
11802 : {
11803 : #ifndef HAVE_MUPARSER
11804 : (void)constant;
11805 : return ThrowIfNotMuparser();
11806 : #else
11807 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11808 3 : *this, constant);
11809 : #endif
11810 : }
11811 :
11812 : /************************************************************************/
11813 : /* operator>=() */
11814 : /************************************************************************/
11815 :
11816 : /** Return a band whose value is 1 if the constant is greater or equal to
11817 : * the pixel value of the right operand.
11818 : *
11819 : * The resulting band is lazy evaluated. A reference is taken on the input
11820 : * dataset.
11821 : *
11822 : * @since 3.12
11823 : */
11824 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
11825 : {
11826 : #ifndef HAVE_MUPARSER
11827 : (void)constant;
11828 : (void)other;
11829 : return ThrowIfNotMuparser();
11830 : #else
11831 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
11832 2 : constant, other);
11833 : #endif
11834 : }
11835 :
11836 : /************************************************************************/
11837 : /* operator<() */
11838 : /************************************************************************/
11839 :
11840 : /** Return a band whose value is 1 if the pixel value of the left operand
11841 : * is lesser than the pixel value of the right operand.
11842 : *
11843 : * The resulting band is lazy evaluated. A reference is taken on the input
11844 : * dataset.
11845 : *
11846 : * @since 3.12
11847 : */
11848 : GDALComputedRasterBand
11849 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
11850 : {
11851 : #ifndef HAVE_MUPARSER
11852 : (void)other;
11853 : return ThrowIfNotMuparser();
11854 : #else
11855 3 : ThrowIfNotSameDimensions(*this, other);
11856 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11857 2 : *this, other);
11858 : #endif
11859 : }
11860 :
11861 : /************************************************************************/
11862 : /* operator<() */
11863 : /************************************************************************/
11864 :
11865 : /** Return a band whose value is 1 if the pixel value of the left operand
11866 : * is lesser than the constant.
11867 : *
11868 : * The resulting band is lazy evaluated. A reference is taken on the input
11869 : * dataset.
11870 : *
11871 : * @since 3.12
11872 : */
11873 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11874 : {
11875 : #ifndef HAVE_MUPARSER
11876 : (void)constant;
11877 : return ThrowIfNotMuparser();
11878 : #else
11879 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11880 3 : *this, constant);
11881 : #endif
11882 : }
11883 :
11884 : /************************************************************************/
11885 : /* operator<() */
11886 : /************************************************************************/
11887 :
11888 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11889 : * value of the right operand.
11890 : *
11891 : * The resulting band is lazy evaluated. A reference is taken on the input
11892 : * dataset.
11893 : *
11894 : * @since 3.12
11895 : */
11896 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11897 : {
11898 : #ifndef HAVE_MUPARSER
11899 : (void)constant;
11900 : (void)other;
11901 : return ThrowIfNotMuparser();
11902 : #else
11903 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11904 2 : constant, other);
11905 : #endif
11906 : }
11907 :
11908 : /************************************************************************/
11909 : /* operator<=() */
11910 : /************************************************************************/
11911 :
11912 : /** Return a band whose value is 1 if the pixel value of the left operand
11913 : * is lesser or equal to the pixel value of the right operand.
11914 : *
11915 : * The resulting band is lazy evaluated. A reference is taken on the input
11916 : * dataset.
11917 : *
11918 : * @since 3.12
11919 : */
11920 : GDALComputedRasterBand
11921 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11922 : {
11923 : #ifndef HAVE_MUPARSER
11924 : (void)other;
11925 : return ThrowIfNotMuparser();
11926 : #else
11927 4 : ThrowIfNotSameDimensions(*this, other);
11928 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11929 3 : *this, other);
11930 : #endif
11931 : }
11932 :
11933 : /************************************************************************/
11934 : /* operator<=() */
11935 : /************************************************************************/
11936 :
11937 : /** Return a band whose value is 1 if the pixel value of the left operand
11938 : * is lesser or equal to the constant.
11939 : *
11940 : * The resulting band is lazy evaluated. A reference is taken on the input
11941 : * dataset.
11942 : *
11943 : * @since 3.12
11944 : */
11945 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11946 : {
11947 : #ifndef HAVE_MUPARSER
11948 : (void)constant;
11949 : return ThrowIfNotMuparser();
11950 : #else
11951 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11952 3 : *this, constant);
11953 : #endif
11954 : }
11955 :
11956 : /************************************************************************/
11957 : /* operator<=() */
11958 : /************************************************************************/
11959 :
11960 : /** Return a band whose value is 1 if the constant is lesser or equal to
11961 : * the pixel value of the right operand.
11962 : *
11963 : * The resulting band is lazy evaluated. A reference is taken on the input
11964 : * dataset.
11965 : *
11966 : * @since 3.12
11967 : */
11968 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11969 : {
11970 : #ifndef HAVE_MUPARSER
11971 : (void)constant;
11972 : (void)other;
11973 : return ThrowIfNotMuparser();
11974 : #else
11975 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11976 2 : constant, other);
11977 : #endif
11978 : }
11979 :
11980 : /************************************************************************/
11981 : /* operator==() */
11982 : /************************************************************************/
11983 :
11984 : /** Return a band whose value is 1 if the pixel value of the left operand
11985 : * is equal to the pixel value of the right operand.
11986 : *
11987 : * The resulting band is lazy evaluated. A reference is taken on the input
11988 : * dataset.
11989 : *
11990 : * @since 3.12
11991 : */
11992 : GDALComputedRasterBand
11993 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11994 : {
11995 : #ifndef HAVE_MUPARSER
11996 : (void)other;
11997 : return ThrowIfNotMuparser();
11998 : #else
11999 3 : ThrowIfNotSameDimensions(*this, other);
12000 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12001 2 : *this, other);
12002 : #endif
12003 : }
12004 :
12005 : /************************************************************************/
12006 : /* operator==() */
12007 : /************************************************************************/
12008 :
12009 : /** Return a band whose value is 1 if the pixel value of the left operand
12010 : * is equal to the constant.
12011 : *
12012 : * The resulting band is lazy evaluated. A reference is taken on the input
12013 : * dataset.
12014 : *
12015 : * @since 3.12
12016 : */
12017 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
12018 : {
12019 : #ifndef HAVE_MUPARSER
12020 : (void)constant;
12021 : return ThrowIfNotMuparser();
12022 : #else
12023 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12024 8 : *this, constant);
12025 : #endif
12026 : }
12027 :
12028 : /************************************************************************/
12029 : /* operator==() */
12030 : /************************************************************************/
12031 :
12032 : /** Return a band whose value is 1 if the constant is equal to
12033 : * the pixel value of the right operand.
12034 : *
12035 : * The resulting band is lazy evaluated. A reference is taken on the input
12036 : * dataset.
12037 : *
12038 : * @since 3.12
12039 : */
12040 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
12041 : {
12042 : #ifndef HAVE_MUPARSER
12043 : (void)constant;
12044 : (void)other;
12045 : return ThrowIfNotMuparser();
12046 : #else
12047 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
12048 2 : constant, other);
12049 : #endif
12050 : }
12051 :
12052 : /************************************************************************/
12053 : /* operator!=() */
12054 : /************************************************************************/
12055 :
12056 : /** Return a band whose value is 1 if the pixel value of the left operand
12057 : * is different from the pixel value of the right operand.
12058 : *
12059 : * The resulting band is lazy evaluated. A reference is taken on the input
12060 : * dataset.
12061 : *
12062 : * @since 3.12
12063 : */
12064 : GDALComputedRasterBand
12065 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
12066 : {
12067 : #ifndef HAVE_MUPARSER
12068 : (void)other;
12069 : return ThrowIfNotMuparser();
12070 : #else
12071 3 : ThrowIfNotSameDimensions(*this, other);
12072 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12073 2 : *this, other);
12074 : #endif
12075 : }
12076 :
12077 : /************************************************************************/
12078 : /* operator!=() */
12079 : /************************************************************************/
12080 :
12081 : /** Return a band whose value is 1 if the pixel value of the left operand
12082 : * is different from the constant.
12083 : *
12084 : * The resulting band is lazy evaluated. A reference is taken on the input
12085 : * dataset.
12086 : *
12087 : * @since 3.12
12088 : */
12089 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
12090 : {
12091 : #ifndef HAVE_MUPARSER
12092 : (void)constant;
12093 : return ThrowIfNotMuparser();
12094 : #else
12095 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12096 6 : *this, constant);
12097 : #endif
12098 : }
12099 :
12100 : /************************************************************************/
12101 : /* operator!=() */
12102 : /************************************************************************/
12103 :
12104 : /** Return a band whose value is 1 if the constant is different from
12105 : * the pixel value of the right operand.
12106 : *
12107 : * The resulting band is lazy evaluated. A reference is taken on the input
12108 : * dataset.
12109 : *
12110 : * @since 3.12
12111 : */
12112 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
12113 : {
12114 : #ifndef HAVE_MUPARSER
12115 : (void)constant;
12116 : (void)other;
12117 : return ThrowIfNotMuparser();
12118 : #else
12119 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12120 2 : constant, other);
12121 : #endif
12122 : }
12123 :
12124 : #if defined(__GNUC__)
12125 : #pragma GCC diagnostic push
12126 : #pragma GCC diagnostic ignored "-Weffc++"
12127 : #endif
12128 :
12129 : /************************************************************************/
12130 : /* operator&&() */
12131 : /************************************************************************/
12132 :
12133 : /** Return a band whose value is 1 if the pixel value of the left and right
12134 : * operands is true.
12135 : *
12136 : * The resulting band is lazy evaluated. A reference is taken on the input
12137 : * dataset.
12138 : *
12139 : * @since 3.12
12140 : */
12141 : GDALComputedRasterBand
12142 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
12143 : {
12144 : #ifndef HAVE_MUPARSER
12145 : (void)other;
12146 : return ThrowIfNotMuparser();
12147 : #else
12148 3 : ThrowIfNotSameDimensions(*this, other);
12149 : return GDALComputedRasterBand(
12150 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
12151 : #endif
12152 : }
12153 :
12154 : /************************************************************************/
12155 : /* operator&&() */
12156 : /************************************************************************/
12157 :
12158 : /** Return a band whose value is 1 if the pixel value of the left operand
12159 : * is true, as well as the constant
12160 : *
12161 : * The resulting band is lazy evaluated. A reference is taken on the input
12162 : * dataset.
12163 : *
12164 : * @since 3.12
12165 : */
12166 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
12167 : {
12168 : #ifndef HAVE_MUPARSER
12169 : (void)constant;
12170 : return ThrowIfNotMuparser();
12171 : #else
12172 : return GDALComputedRasterBand(
12173 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
12174 : #endif
12175 : }
12176 :
12177 : /************************************************************************/
12178 : /* operator&&() */
12179 : /************************************************************************/
12180 :
12181 : /** Return a band whose value is 1 if the constant is true, as well as
12182 : * the pixel value of the right operand.
12183 : *
12184 : * The resulting band is lazy evaluated. A reference is taken on the input
12185 : * dataset.
12186 : *
12187 : * @since 3.12
12188 : */
12189 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
12190 : {
12191 : #ifndef HAVE_MUPARSER
12192 : (void)constant;
12193 : (void)other;
12194 : return ThrowIfNotMuparser();
12195 : #else
12196 : return GDALComputedRasterBand(
12197 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
12198 : #endif
12199 : }
12200 :
12201 : /************************************************************************/
12202 : /* operator||() */
12203 : /************************************************************************/
12204 :
12205 : /** Return a band whose value is 1 if the pixel value of the left or right
12206 : * operands is true.
12207 : *
12208 : * The resulting band is lazy evaluated. A reference is taken on the input
12209 : * dataset.
12210 : *
12211 : * @since 3.12
12212 : */
12213 : GDALComputedRasterBand
12214 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
12215 : {
12216 : #ifndef HAVE_MUPARSER
12217 : (void)other;
12218 : return ThrowIfNotMuparser();
12219 : #else
12220 4 : ThrowIfNotSameDimensions(*this, other);
12221 : return GDALComputedRasterBand(
12222 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
12223 : #endif
12224 : }
12225 :
12226 : /************************************************************************/
12227 : /* operator||() */
12228 : /************************************************************************/
12229 :
12230 : /** Return a band whose value is 1 if the pixel value of the left operand
12231 : * is true, or if the constant is true
12232 : *
12233 : * The resulting band is lazy evaluated. A reference is taken on the input
12234 : * dataset.
12235 : *
12236 : * @since 3.12
12237 : */
12238 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
12239 : {
12240 : #ifndef HAVE_MUPARSER
12241 : (void)constant;
12242 : return ThrowIfNotMuparser();
12243 : #else
12244 : return GDALComputedRasterBand(
12245 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
12246 : #endif
12247 : }
12248 :
12249 : /************************************************************************/
12250 : /* operator||() */
12251 : /************************************************************************/
12252 :
12253 : /** Return a band whose value is 1 if the constant is true, or
12254 : * the pixel value of the right operand is true
12255 : *
12256 : * The resulting band is lazy evaluated. A reference is taken on the input
12257 : * dataset.
12258 : *
12259 : * @since 3.12
12260 : */
12261 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
12262 : {
12263 : #ifndef HAVE_MUPARSER
12264 : (void)constant;
12265 : (void)other;
12266 : return ThrowIfNotMuparser();
12267 : #else
12268 : return GDALComputedRasterBand(
12269 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
12270 : #endif
12271 : }
12272 :
12273 : #if defined(__GNUC__)
12274 : #pragma GCC diagnostic pop
12275 : #endif
12276 :
12277 : /************************************************************************/
12278 : /* operator!() */
12279 : /************************************************************************/
12280 :
12281 : /** Return a band whose value is the logical negation of the pixel value
12282 : *
12283 : * The resulting band is lazy evaluated. A reference is taken on the input
12284 : * dataset.
12285 : *
12286 : * @since 3.12
12287 : */
12288 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
12289 : {
12290 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
12291 2 : *this, true);
12292 : }
12293 :
12294 : namespace gdal
12295 : {
12296 :
12297 : /************************************************************************/
12298 : /* IfThenElse() */
12299 : /************************************************************************/
12300 :
12301 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12302 : * is not zero, or the one from elseBand otherwise.
12303 : *
12304 : * Variants of this method exits where thenBand and/or elseBand can be double
12305 : * values.
12306 : *
12307 : * The resulting band is lazy evaluated. A reference is taken on the input
12308 : * datasets.
12309 : *
12310 : * This method is the same as the C function GDALRasterBandIfThenElse()
12311 : *
12312 : * @since 3.12
12313 : */
12314 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12315 : const GDALRasterBand &thenBand,
12316 : const GDALRasterBand &elseBand)
12317 : {
12318 : #ifndef HAVE_MUPARSER
12319 : (void)condBand;
12320 : (void)thenBand;
12321 : (void)elseBand;
12322 : return ThrowIfNotMuparser();
12323 : #else
12324 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12325 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12326 : return GDALComputedRasterBand(
12327 : GDALComputedRasterBand::Operation::OP_TERNARY,
12328 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12329 : #endif
12330 : }
12331 :
12332 : //! @cond Doxygen_Suppress
12333 :
12334 : /************************************************************************/
12335 : /* IfThenElse() */
12336 : /************************************************************************/
12337 :
12338 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12339 : * is not zero, or the one from elseBand otherwise.
12340 : *
12341 : * The resulting band is lazy evaluated. A reference is taken on the input
12342 : * datasets.
12343 : *
12344 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12345 : * with thenBand = (condBand * 0) + thenValue
12346 : *
12347 : * @since 3.12
12348 : */
12349 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12350 : double thenValue,
12351 : const GDALRasterBand &elseBand)
12352 : {
12353 : #ifndef HAVE_MUPARSER
12354 : (void)condBand;
12355 : (void)thenValue;
12356 : (void)elseBand;
12357 : return ThrowIfNotMuparser();
12358 : #else
12359 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12360 : auto thenBand =
12361 1 : (condBand * 0)
12362 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12363 1 : thenValue;
12364 : return GDALComputedRasterBand(
12365 : GDALComputedRasterBand::Operation::OP_TERNARY,
12366 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12367 : #endif
12368 : }
12369 :
12370 : /************************************************************************/
12371 : /* IfThenElse() */
12372 : /************************************************************************/
12373 :
12374 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
12375 : * is not zero, or the one from elseValue otherwise.
12376 : *
12377 : * The resulting band is lazy evaluated. A reference is taken on the input
12378 : * datasets.
12379 : *
12380 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12381 : * with elseBand = (condBand * 0) + elseValue
12382 :
12383 : * @since 3.12
12384 : */
12385 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12386 : const GDALRasterBand &thenBand,
12387 : double elseValue)
12388 : {
12389 : #ifndef HAVE_MUPARSER
12390 : (void)condBand;
12391 : (void)thenBand;
12392 : (void)elseValue;
12393 : return ThrowIfNotMuparser();
12394 : #else
12395 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12396 : auto elseBand =
12397 1 : (condBand * 0)
12398 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12399 1 : elseValue;
12400 : return GDALComputedRasterBand(
12401 : GDALComputedRasterBand::Operation::OP_TERNARY,
12402 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12403 : #endif
12404 : }
12405 :
12406 : /************************************************************************/
12407 : /* IfThenElse() */
12408 : /************************************************************************/
12409 :
12410 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
12411 : * is not zero, or the one from elseValue otherwise.
12412 : *
12413 : * The resulting band is lazy evaluated. A reference is taken on the input
12414 : * datasets.
12415 : *
12416 : * This method is the same as the C function GDALRasterBandIfThenElse(),
12417 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
12418 : *
12419 : * @since 3.12
12420 : */
12421 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
12422 : double thenValue, double elseValue)
12423 : {
12424 : #ifndef HAVE_MUPARSER
12425 : (void)condBand;
12426 : (void)thenValue;
12427 : (void)elseValue;
12428 : return ThrowIfNotMuparser();
12429 : #else
12430 : auto thenBand =
12431 3 : (condBand * 0)
12432 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
12433 6 : thenValue;
12434 : auto elseBand =
12435 3 : (condBand * 0)
12436 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
12437 3 : elseValue;
12438 : return GDALComputedRasterBand(
12439 : GDALComputedRasterBand::Operation::OP_TERNARY,
12440 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12441 : #endif
12442 : }
12443 :
12444 : //! @endcond
12445 :
12446 : } // namespace gdal
12447 :
12448 : /************************************************************************/
12449 : /* GDALRasterBandIfThenElse() */
12450 : /************************************************************************/
12451 :
12452 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
12453 : * is not zero, or the one from hElseBand otherwise.
12454 : *
12455 : * The resulting band is lazy evaluated. A reference is taken on the input
12456 : * datasets.
12457 : *
12458 : * This function is the same as the C++ method gdal::IfThenElse()
12459 : *
12460 : * @since 3.12
12461 : */
12462 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
12463 : GDALRasterBandH hThenBand,
12464 : GDALRasterBandH hElseBand)
12465 : {
12466 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
12467 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
12468 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
12469 : #ifndef HAVE_MUPARSER
12470 : CPLError(CE_Failure, CPLE_NotSupported,
12471 : "Band comparison operators not available on a GDAL build without "
12472 : "muparser");
12473 : return nullptr;
12474 : #else
12475 :
12476 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
12477 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
12478 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
12479 : try
12480 : {
12481 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
12482 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
12483 : }
12484 2 : catch (const std::exception &e)
12485 : {
12486 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12487 2 : return nullptr;
12488 : }
12489 : return new GDALComputedRasterBand(
12490 : GDALComputedRasterBand::Operation::OP_TERNARY,
12491 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
12492 : #endif
12493 : }
12494 :
12495 : /************************************************************************/
12496 : /* GDALRasterBand::AsType() */
12497 : /************************************************************************/
12498 :
12499 : /** Cast this band to another type.
12500 : *
12501 : * The resulting band is lazy evaluated. A reference is taken on the input
12502 : * dataset.
12503 : *
12504 : * This method is the same as the C function GDALRasterBandAsDataType()
12505 : *
12506 : * @since 3.12
12507 : */
12508 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
12509 : {
12510 10 : if (dt == GDT_Unknown)
12511 : {
12512 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
12513 : }
12514 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
12515 9 : *this, dt);
12516 : }
12517 :
12518 : /************************************************************************/
12519 : /* GDALRasterBandAsDataType() */
12520 : /************************************************************************/
12521 :
12522 : /** Cast this band to another type.
12523 : *
12524 : * The resulting band is lazy evaluated. A reference is taken on the input
12525 : * dataset.
12526 : *
12527 : * This function is the same as the C++ method GDALRasterBand::AsType()
12528 : *
12529 : * @since 3.12
12530 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12531 : */
12532 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
12533 : GDALDataType eDT)
12534 : {
12535 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
12536 16 : if (eDT == GDT_Unknown)
12537 : {
12538 1 : CPLError(CE_Failure, CPLE_NotSupported,
12539 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
12540 1 : return nullptr;
12541 : }
12542 : return new GDALComputedRasterBand(
12543 : GDALComputedRasterBand::Operation::OP_CAST,
12544 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
12545 : }
12546 :
12547 : /************************************************************************/
12548 : /* GetBandVector() */
12549 : /************************************************************************/
12550 :
12551 : static std::vector<const GDALRasterBand *>
12552 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
12553 : {
12554 10 : std::vector<const GDALRasterBand *> bands;
12555 27 : for (size_t i = 0; i < nBandCount; ++i)
12556 : {
12557 20 : if (i > 0)
12558 : {
12559 10 : GDALRasterBand::ThrowIfNotSameDimensions(
12560 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
12561 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
12562 : }
12563 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
12564 : }
12565 7 : return bands;
12566 : }
12567 :
12568 : /************************************************************************/
12569 : /* GDALOperationOnNBands() */
12570 : /************************************************************************/
12571 :
12572 : static GDALComputedRasterBandH
12573 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
12574 : GDALRasterBandH *pahBands)
12575 : {
12576 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
12577 11 : if (nBandCount == 0)
12578 : {
12579 1 : CPLError(CE_Failure, CPLE_AppDefined,
12580 : "At least one band should be passed");
12581 1 : return nullptr;
12582 : }
12583 :
12584 20 : std::vector<const GDALRasterBand *> bands;
12585 : try
12586 : {
12587 10 : bands = GetBandVector(nBandCount, pahBands);
12588 : }
12589 3 : catch (const std::exception &e)
12590 : {
12591 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
12592 3 : return nullptr;
12593 : }
12594 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
12595 : }
12596 :
12597 : /************************************************************************/
12598 : /* GDALMaximumOfNBands() */
12599 : /************************************************************************/
12600 :
12601 : /** Return a band whose each pixel value is the maximum of the corresponding
12602 : * pixel values in the input bands.
12603 : *
12604 : * The resulting band is lazy evaluated. A reference is taken on input
12605 : * datasets.
12606 : *
12607 : * This function is the same as the C ++ method gdal::max()
12608 : *
12609 : * @since 3.12
12610 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12611 : */
12612 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
12613 : GDALRasterBandH *pahBands)
12614 : {
12615 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
12616 4 : nBandCount, pahBands);
12617 : }
12618 :
12619 : /************************************************************************/
12620 : /* gdal::max() */
12621 : /************************************************************************/
12622 :
12623 : namespace gdal
12624 : {
12625 : /** Return a band whose each pixel value is the maximum of the corresponding
12626 : * pixel values in the inputs (bands or constants)
12627 : *
12628 : * The resulting band is lazy evaluated. A reference is taken on input
12629 : * datasets.
12630 : *
12631 : * Two or more bands can be passed.
12632 : *
12633 : * This method is the same as the C function GDALMaximumOfNBands()
12634 : *
12635 : * @since 3.12
12636 : * @throw std::runtime_error if bands do not have the same dimensions.
12637 : */
12638 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
12639 : const GDALRasterBand &second)
12640 : {
12641 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12642 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
12643 1 : first, second);
12644 : }
12645 : } // namespace gdal
12646 :
12647 : /************************************************************************/
12648 : /* GDALRasterBandMaxConstant() */
12649 : /************************************************************************/
12650 :
12651 : /** Return a band whose each pixel value is the maximum of the corresponding
12652 : * pixel values in the input band and the constant.
12653 : *
12654 : * The resulting band is lazy evaluated. A reference is taken on the input
12655 : * dataset.
12656 : *
12657 : * This function is the same as the C ++ method gdal::max()
12658 : *
12659 : * @since 3.12
12660 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12661 : */
12662 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
12663 : double dfConstant)
12664 : {
12665 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12666 : GDALComputedRasterBand::Operation::OP_MAX,
12667 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12668 6 : dfConstant));
12669 : }
12670 :
12671 : /************************************************************************/
12672 : /* GDALMinimumOfNBands() */
12673 : /************************************************************************/
12674 :
12675 : /** Return a band whose each pixel value is the minimum of the corresponding
12676 : * pixel values in the input bands.
12677 : *
12678 : * The resulting band is lazy evaluated. A reference is taken on input
12679 : * datasets.
12680 : *
12681 : * This function is the same as the C ++ method gdal::min()
12682 : *
12683 : * @since 3.12
12684 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12685 : */
12686 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
12687 : GDALRasterBandH *pahBands)
12688 : {
12689 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
12690 4 : nBandCount, pahBands);
12691 : }
12692 :
12693 : /************************************************************************/
12694 : /* gdal::min() */
12695 : /************************************************************************/
12696 :
12697 : namespace gdal
12698 : {
12699 : /** Return a band whose each pixel value is the minimum of the corresponding
12700 : * pixel values in the inputs (bands or constants)
12701 : *
12702 : * The resulting band is lazy evaluated. A reference is taken on input
12703 : * datasets.
12704 : *
12705 : * Two or more bands can be passed.
12706 : *
12707 : * This method is the same as the C function GDALMinimumOfNBands()
12708 : *
12709 : * @since 3.12
12710 : * @throw std::runtime_error if bands do not have the same dimensions.
12711 : */
12712 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
12713 : const GDALRasterBand &second)
12714 : {
12715 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12716 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
12717 0 : first, second);
12718 : }
12719 : } // namespace gdal
12720 :
12721 : /************************************************************************/
12722 : /* GDALRasterBandMinConstant() */
12723 : /************************************************************************/
12724 :
12725 : /** Return a band whose each pixel value is the minimum of the corresponding
12726 : * pixel values in the input band and the constant.
12727 : *
12728 : * The resulting band is lazy evaluated. A reference is taken on the input
12729 : * dataset.
12730 : *
12731 : * This function is the same as the C ++ method gdal::min()
12732 : *
12733 : * @since 3.12
12734 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12735 : */
12736 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
12737 : double dfConstant)
12738 : {
12739 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
12740 : GDALComputedRasterBand::Operation::OP_MIN,
12741 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
12742 6 : dfConstant));
12743 : }
12744 :
12745 : /************************************************************************/
12746 : /* GDALMeanOfNBands() */
12747 : /************************************************************************/
12748 :
12749 : /** Return a band whose each pixel value is the arithmetic mean of the
12750 : * corresponding pixel values in the input bands.
12751 : *
12752 : * The resulting band is lazy evaluated. A reference is taken on input
12753 : * datasets.
12754 : *
12755 : * This function is the same as the C ++ method gdal::mean()
12756 : *
12757 : * @since 3.12
12758 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
12759 : */
12760 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
12761 : GDALRasterBandH *pahBands)
12762 : {
12763 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
12764 3 : nBandCount, pahBands);
12765 : }
12766 :
12767 : /************************************************************************/
12768 : /* gdal::mean() */
12769 : /************************************************************************/
12770 :
12771 : namespace gdal
12772 : {
12773 :
12774 : /** Return a band whose each pixel value is the arithmetic mean of the
12775 : * corresponding pixel values in the input bands.
12776 : *
12777 : * The resulting band is lazy evaluated. A reference is taken on input
12778 : * datasets.
12779 : *
12780 : * Two or more bands can be passed.
12781 : *
12782 : * This method is the same as the C function GDALMeanOfNBands()
12783 : *
12784 : * @since 3.12
12785 : * @throw std::runtime_error if bands do not have the same dimensions.
12786 : */
12787 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
12788 : const GDALRasterBand &second)
12789 : {
12790 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
12791 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
12792 0 : first, second);
12793 : }
12794 : } // namespace gdal
12795 :
12796 : /************************************************************************/
12797 : /* gdal::abs() */
12798 : /************************************************************************/
12799 :
12800 : namespace gdal
12801 : {
12802 :
12803 : /** Return a band whose each pixel value is the absolute value (or module
12804 : * for complex data type) of the corresponding pixel value in the input band.
12805 : *
12806 : * The resulting band is lazy evaluated. A reference is taken on input
12807 : * datasets.
12808 : *
12809 : * @since 3.12
12810 : */
12811 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
12812 : {
12813 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12814 1 : band);
12815 : }
12816 : } // namespace gdal
12817 :
12818 : /************************************************************************/
12819 : /* gdal::fabs() */
12820 : /************************************************************************/
12821 :
12822 : namespace gdal
12823 : {
12824 :
12825 : /** Return a band whose each pixel value is the absolute value (or module
12826 : * for complex data type) of the corresponding pixel value in the input band.
12827 : *
12828 : * The resulting band is lazy evaluated. A reference is taken on input
12829 : * datasets.
12830 : *
12831 : * @since 3.12
12832 : */
12833 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
12834 : {
12835 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12836 1 : band);
12837 : }
12838 : } // namespace gdal
12839 :
12840 : /************************************************************************/
12841 : /* gdal::sqrt() */
12842 : /************************************************************************/
12843 :
12844 : namespace gdal
12845 : {
12846 :
12847 : /** Return a band whose each pixel value is the square root of the
12848 : * corresponding pixel value in the input band.
12849 : *
12850 : * The resulting band is lazy evaluated. A reference is taken on input
12851 : * datasets.
12852 : *
12853 : * @since 3.12
12854 : */
12855 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12856 : {
12857 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12858 1 : band);
12859 : }
12860 : } // namespace gdal
12861 :
12862 : /************************************************************************/
12863 : /* gdal::log() */
12864 : /************************************************************************/
12865 :
12866 : namespace gdal
12867 : {
12868 :
12869 : /** Return a band whose each pixel value is the natural logarithm of the
12870 : * corresponding pixel value in the input band.
12871 : *
12872 : * The resulting band is lazy evaluated. A reference is taken on input
12873 : * datasets.
12874 : *
12875 : * @since 3.12
12876 : */
12877 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12878 : {
12879 : #ifndef HAVE_MUPARSER
12880 : (void)band;
12881 : return ThrowIfNotMuparser();
12882 : #else
12883 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12884 1 : band);
12885 : #endif
12886 : }
12887 : } // namespace gdal
12888 :
12889 : /************************************************************************/
12890 : /* gdal::log10() */
12891 : /************************************************************************/
12892 :
12893 : namespace gdal
12894 : {
12895 :
12896 : /** Return a band whose each pixel value is the logarithm base 10 of the
12897 : * corresponding pixel value in the input band.
12898 : *
12899 : * The resulting band is lazy evaluated. A reference is taken on input
12900 : * datasets.
12901 : *
12902 : * @since 3.12
12903 : */
12904 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12905 : {
12906 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12907 1 : band);
12908 : }
12909 : } // namespace gdal
12910 :
12911 : /************************************************************************/
12912 : /* gdal::pow() */
12913 : /************************************************************************/
12914 :
12915 : namespace gdal
12916 : {
12917 :
12918 : #ifndef DOXYGEN_SKIP
12919 : /** Return a band whose each pixel value is the constant raised to the power of
12920 : * the corresponding pixel value in the input band.
12921 : *
12922 : * The resulting band is lazy evaluated. A reference is taken on input
12923 : * datasets.
12924 : *
12925 : * @since 3.12
12926 : */
12927 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12928 : {
12929 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12930 1 : constant, band);
12931 : }
12932 : #endif
12933 :
12934 : } // namespace gdal
12935 :
12936 : /************************************************************************/
12937 : /* gdal::pow() */
12938 : /************************************************************************/
12939 :
12940 : namespace gdal
12941 : {
12942 :
12943 : /** Return a band whose each pixel value is the the corresponding pixel value
12944 : * in the input band raised to the power of the constant.
12945 : *
12946 : * The resulting band is lazy evaluated. A reference is taken on input
12947 : * datasets.
12948 : *
12949 : * @since 3.12
12950 : */
12951 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12952 : {
12953 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12954 1 : band, constant);
12955 : }
12956 : } // namespace gdal
12957 :
12958 : /************************************************************************/
12959 : /* gdal::pow() */
12960 : /************************************************************************/
12961 :
12962 : namespace gdal
12963 : {
12964 :
12965 : #ifndef DOXYGEN_SKIP
12966 : /** Return a band whose each pixel value is the the corresponding pixel value
12967 : * in the input band1 raised to the power of the corresponding pixel value
12968 : * in the input band2
12969 : *
12970 : * The resulting band is lazy evaluated. A reference is taken on input
12971 : * datasets.
12972 : *
12973 : * @since 3.12
12974 : * @throw std::runtime_error if bands do not have the same dimensions.
12975 : */
12976 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12977 : const GDALRasterBand &band2)
12978 : {
12979 : #ifndef HAVE_MUPARSER
12980 : (void)band1;
12981 : (void)band2;
12982 : return ThrowIfNotMuparser();
12983 : #else
12984 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12985 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12986 1 : band1, band2);
12987 : #endif
12988 : }
12989 : #endif
12990 : } // namespace gdal
|