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 : #include "gdal_priv.h"
18 :
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_rat.h"
41 : #include "gdal_priv_templates.hpp"
42 : #include "gdal_interpolateatpoint.h"
43 : #include "gdal_minmax_element.hpp"
44 :
45 : /************************************************************************/
46 : /* GDALRasterBand() */
47 : /************************************************************************/
48 :
49 : /*! Constructor. Applications should never create GDALRasterBands directly. */
50 :
51 1640300 : GDALRasterBand::GDALRasterBand()
52 : : GDALRasterBand(
53 1640300 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
54 : {
55 1640150 : }
56 :
57 : /** Constructor. Applications should never create GDALRasterBands directly.
58 : * @param bForceCachedIOIn Whether cached IO should be forced.
59 : */
60 1911390 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
61 1911390 : : bForceCachedIO(bForceCachedIOIn)
62 :
63 : {
64 1911250 : }
65 :
66 : /************************************************************************/
67 : /* ~GDALRasterBand() */
68 : /************************************************************************/
69 :
70 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
71 : instead destroy the GDALDataset. */
72 :
73 1911390 : GDALRasterBand::~GDALRasterBand()
74 :
75 : {
76 1911390 : if (poDS && poDS->IsMarkedSuppressOnClose())
77 : {
78 530 : if (poBandBlockCache)
79 461 : poBandBlockCache->DisableDirtyBlockWriting();
80 : }
81 1911390 : GDALRasterBand::FlushCache(true);
82 :
83 1911390 : delete poBandBlockCache;
84 :
85 1911390 : if (static_cast<GIntBig>(nBlockReads) >
86 1911390 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
87 219 : nBand == 1 && poDS != nullptr)
88 : {
89 318 : CPLDebug(
90 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
91 159 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
92 159 : poDS->GetDescription());
93 : }
94 :
95 1911390 : InvalidateMaskBand();
96 1911390 : nBand = -nBand;
97 :
98 1911390 : delete m_poPointsCache;
99 1911390 : }
100 :
101 : /************************************************************************/
102 : /* RasterIO() */
103 : /************************************************************************/
104 :
105 : /**
106 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
107 : * int nXOff, int nYOff, int nXSize, int nYSize,
108 : * void * pData, int nBufXSize, int nBufYSize,
109 : * GDALDataType eBufType,
110 : * GSpacing nPixelSpace,
111 : * GSpacing nLineSpace,
112 : * GDALRasterIOExtraArg* psExtraArg )
113 : * \brief Read/write a region of image data for this band.
114 : *
115 : * This method allows reading a region of a GDALRasterBand into a buffer,
116 : * or writing data from a buffer into a region of a GDALRasterBand. It
117 : * automatically takes care of data type translation if the data type
118 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
119 : * The method also takes care of image decimation / replication if the
120 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
121 : * region being accessed (nXSize x nYSize).
122 : *
123 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
124 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
125 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
126 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
127 : * Or use nLineSpace and a possibly shifted pData value.
128 : *
129 : * The nPixelSpace and nLineSpace parameters allow reading into or
130 : * writing from unusually organized buffers. This is primarily used
131 : * for buffers containing more than one bands raster data in interleaved
132 : * format.
133 : *
134 : * Some formats may efficiently implement decimation into a buffer by
135 : * reading from lower resolution overview images. The logic of the default
136 : * implementation in the base class GDALRasterBand is the following one. It
137 : * computes a target_downscaling_factor from the window of interest and buffer
138 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
139 : * It then walks through overviews and will select the first one whose
140 : * downscaling factor is greater than target_downscaling_factor / 1.2.
141 : *
142 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
143 : * The relationship between target_downscaling_factor and the select overview
144 : * level is the following one:
145 : *
146 : * target_downscaling_factor | selected_overview
147 : * ------------------------- | -----------------
148 : * ]0, 2 / 1.2] | full resolution band
149 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
150 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
151 : * ]8 / 1.2, infinity[ | 8x downsampled band
152 : *
153 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
154 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
155 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
156 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
157 : * this oversampling threshold defaults to 1. Consequently if there are overviews
158 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
159 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
160 : *
161 : * For highest performance full resolution data access, read and write
162 : * on "block boundaries" as returned by GetBlockSize(), or use the
163 : * ReadBlock() and WriteBlock() methods.
164 : *
165 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
166 : * functions.
167 : *
168 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
169 : * write a region of data.
170 : *
171 : * @param nXOff The pixel offset to the top left corner of the region
172 : * of the band to be accessed. This would be zero to start from the left side.
173 : *
174 : * @param nYOff The line offset to the top left corner of the region
175 : * of the band to be accessed. This would be zero to start from the top.
176 : *
177 : * @param nXSize The width of the region of the band to be accessed in pixels.
178 : *
179 : * @param nYSize The height of the region of the band to be accessed in lines.
180 : *
181 : * @param pData The buffer into which the data should be read, or from which
182 : * it should be written. This buffer must contain at least nBufXSize *
183 : * nBufYSize words of type eBufType. It is organized in left to right,
184 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
185 : * and nLineSpace parameters.
186 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
187 : * temporarily modified during the execution of this method (and eventually
188 : * restored back to its original content), so it is not safe to use a buffer
189 : * stored in a read-only section of the calling program.
190 : *
191 : * @param nBufXSize the width of the buffer image into which the desired region
192 : * is to be read, or from which it is to be written.
193 : *
194 : * @param nBufYSize the height of the buffer image into which the desired region
195 : * is to be read, or from which it is to be written.
196 : *
197 : * @param eBufType the type of the pixel values in the pData data buffer. The
198 : * pixel values will automatically be translated to/from the GDALRasterBand
199 : * data type as needed. Most driver implementations will use GDALCopyWords64()
200 : * to perform data type translation.
201 : *
202 : * @param nPixelSpace The byte offset from the start of one pixel value in
203 : * pData to the start of the next pixel value within a scanline. If defaulted
204 : * (0) the size of the datatype eBufType is used.
205 : *
206 : * @param nLineSpace The byte offset from the start of one scanline in
207 : * pData to the start of the next. If defaulted (0) the size of the datatype
208 : * eBufType * nBufXSize is used.
209 : *
210 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
211 : * structure with additional arguments to specify resampling and progress
212 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
213 : * configuration option can also be defined to override the default resampling
214 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
215 : *
216 : * @return CE_Failure if the access fails, otherwise CE_None.
217 : */
218 :
219 : /**
220 : * \brief Read/write a region of image data for this band.
221 : *
222 : * This method allows reading a region of a GDALRasterBand into a buffer,
223 : * or writing data from a buffer into a region of a GDALRasterBand. It
224 : * automatically takes care of data type translation if the data type
225 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
226 : * The method also takes care of image decimation / replication if the
227 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
228 : * region being accessed (nXSize x nYSize).
229 : *
230 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
231 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
232 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
233 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
234 : * Or use nLineSpace and a possibly shifted pData value.
235 : *
236 : * The nPixelSpace and nLineSpace parameters allow reading into or
237 : * writing from unusually organized buffers. This is primarily used
238 : * for buffers containing more than one bands raster data in interleaved
239 : * format.
240 : *
241 : * Some formats may efficiently implement decimation into a buffer by
242 : * reading from lower resolution overview images. The logic of the default
243 : * implementation in the base class GDALRasterBand is the following one. It
244 : * computes a target_downscaling_factor from the window of interest and buffer
245 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
246 : * It then walks through overviews and will select the first one whose
247 : * downscaling factor is greater than target_downscaling_factor / 1.2.
248 : *
249 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
250 : * The relationship between target_downscaling_factor and the select overview
251 : * level is the following one:
252 : *
253 : * target_downscaling_factor | selected_overview
254 : * ------------------------- | -----------------
255 : * ]0, 2 / 1.2] | full resolution band
256 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
257 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
258 : * ]8 / 1.2, infinity[ | 8x downsampled band
259 : *
260 : * For highest performance full resolution data access, read and write
261 : * on "block boundaries" as returned by GetBlockSize(), or use the
262 : * ReadBlock() and WriteBlock() methods.
263 : *
264 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
265 : * functions.
266 : *
267 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
268 : * more convenient to use for most common use cases.
269 : *
270 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
271 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
272 : * instance of this dataset) concurrently from several threads.
273 : *
274 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
275 : * write a region of data.
276 : *
277 : * @param nXOff The pixel offset to the top left corner of the region
278 : * of the band to be accessed. This would be zero to start from the left side.
279 : *
280 : * @param nYOff The line offset to the top left corner of the region
281 : * of the band to be accessed. This would be zero to start from the top.
282 : *
283 : * @param nXSize The width of the region of the band to be accessed in pixels.
284 : *
285 : * @param nYSize The height of the region of the band to be accessed in lines.
286 : *
287 : * @param[in,out] pData The buffer into which the data should be read, or from
288 : * which it should be written. This buffer must contain at least nBufXSize *
289 : * nBufYSize words of type eBufType. It is organized in left to right,
290 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
291 : * and nLineSpace parameters.
292 : *
293 : * @param nBufXSize the width of the buffer image into which the desired region
294 : * is to be read, or from which it is to be written.
295 : *
296 : * @param nBufYSize the height of the buffer image into which the desired region
297 : * is to be read, or from which it is to be written.
298 : *
299 : * @param eBufType the type of the pixel values in the pData data buffer. The
300 : * pixel values will automatically be translated to/from the GDALRasterBand
301 : * data type as needed.
302 : *
303 : * @param nPixelSpace The byte offset from the start of one pixel value in
304 : * pData to the start of the next pixel value within a scanline. If defaulted
305 : * (0) the size of the datatype eBufType is used.
306 : *
307 : * @param nLineSpace The byte offset from the start of one scanline in
308 : * pData to the start of the next. If defaulted (0) the size of the datatype
309 : * eBufType * nBufXSize is used.
310 : *
311 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
312 : * structure with additional arguments to specify resampling and progress
313 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
314 : * configuration option can also be defined to override the default resampling
315 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
316 : *
317 : * @return CE_Failure if the access fails, otherwise CE_None.
318 : *
319 : * @see GDALRasterBand::ReadRaster()
320 : */
321 :
322 4416200 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
323 : int nXSize, int nYSize, void *pData,
324 : int nBufXSize, int nBufYSize,
325 : GDALDataType eBufType, GSpacing nPixelSpace,
326 : GSpacing nLineSpace,
327 : GDALRasterIOExtraArg *psExtraArg)
328 :
329 : {
330 : GDALRasterIOExtraArg sExtraArg;
331 4416200 : if (psExtraArg == nullptr)
332 : {
333 3819760 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
334 3819760 : psExtraArg = &sExtraArg;
335 : }
336 596444 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
337 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
338 : {
339 0 : ReportError(CE_Failure, CPLE_AppDefined,
340 : "Unhandled version of GDALRasterIOExtraArg");
341 0 : return CE_Failure;
342 : }
343 :
344 4416200 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
345 : nBufYSize);
346 :
347 4416480 : if (CPL_UNLIKELY(nullptr == pData))
348 : {
349 0 : ReportError(CE_Failure, CPLE_AppDefined,
350 : "The buffer into which the data should be read is null");
351 0 : return CE_Failure;
352 : }
353 :
354 : /* -------------------------------------------------------------------- */
355 : /* Some size values are "noop". Lets just return to avoid */
356 : /* stressing lower level functions. */
357 : /* -------------------------------------------------------------------- */
358 4416480 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
359 : nBufYSize < 1))
360 : {
361 2 : CPLDebug("GDAL",
362 : "RasterIO() skipped for odd window or buffer size.\n"
363 : " Window = (%d,%d)x%dx%d\n"
364 : " Buffer = %dx%d\n",
365 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
366 :
367 2 : return CE_None;
368 : }
369 :
370 4416480 : if (eRWFlag == GF_Write)
371 : {
372 359461 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
373 : {
374 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
375 : "An error occurred while writing a dirty block "
376 : "from GDALRasterBand::RasterIO");
377 0 : CPLErr eErr = eFlushBlockErr;
378 0 : eFlushBlockErr = CE_None;
379 0 : return eErr;
380 : }
381 359461 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
382 : {
383 7 : return CE_Failure;
384 : }
385 : }
386 :
387 : /* -------------------------------------------------------------------- */
388 : /* If pixel and line spacing are defaulted assign reasonable */
389 : /* value assuming a packed buffer. */
390 : /* -------------------------------------------------------------------- */
391 4416910 : if (nPixelSpace == 0)
392 : {
393 4015080 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
394 : }
395 :
396 4415640 : if (nLineSpace == 0)
397 : {
398 4003020 : nLineSpace = nPixelSpace * nBufXSize;
399 : }
400 :
401 : /* -------------------------------------------------------------------- */
402 : /* Do some validation of parameters. */
403 : /* -------------------------------------------------------------------- */
404 4415640 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
405 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
406 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
407 : {
408 15 : ReportError(CE_Failure, CPLE_IllegalArg,
409 : "Access window out of range in RasterIO(). Requested\n"
410 : "(%d,%d) of size %dx%d on raster of %dx%d.",
411 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
412 15 : return CE_Failure;
413 : }
414 :
415 4415620 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
416 : {
417 0 : ReportError(
418 : CE_Failure, CPLE_IllegalArg,
419 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
420 : eRWFlag);
421 0 : return CE_Failure;
422 : }
423 4415620 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
424 : {
425 2 : ReportError(CE_Failure, CPLE_IllegalArg,
426 : "Illegal GDT_Unknown/GDT_TypeCount argument");
427 2 : return CE_Failure;
428 : }
429 :
430 4415620 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
431 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
432 4414420 : nLineSpace, psExtraArg);
433 : }
434 :
435 : /************************************************************************/
436 : /* RasterIOInternal() */
437 : /************************************************************************/
438 :
439 4413420 : CPLErr GDALRasterBand::RasterIOInternal(
440 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
441 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
442 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
443 : {
444 : /* -------------------------------------------------------------------- */
445 : /* Call the format specific function. */
446 : /* -------------------------------------------------------------------- */
447 :
448 4413420 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
449 :
450 : CPLErr eErr;
451 4414360 : if (bForceCachedIO)
452 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
453 : pData, nBufXSize, nBufYSize, eBufType,
454 : nPixelSpace, nLineSpace, psExtraArg);
455 : else
456 : eErr =
457 4415600 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
458 4414340 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
459 :
460 4415620 : if (bCallLeaveReadWrite)
461 599570 : LeaveReadWrite();
462 :
463 4411300 : return eErr;
464 : }
465 :
466 : /************************************************************************/
467 : /* GDALRasterIO() */
468 : /************************************************************************/
469 :
470 : /**
471 : * \brief Read/write a region of image data for this band.
472 : *
473 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
474 : * resolution, progress callback, etc. are needed)
475 : *
476 : * @see GDALRasterBand::RasterIO()
477 : */
478 :
479 3410200 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
480 : int nXOff, int nYOff, int nXSize, int nYSize,
481 : void *pData, int nBufXSize, int nBufYSize,
482 : GDALDataType eBufType, int nPixelSpace,
483 : int nLineSpace)
484 :
485 : {
486 3410200 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
487 :
488 3410200 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
489 :
490 3411860 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
491 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
492 3403120 : nLineSpace, nullptr));
493 : }
494 :
495 : /************************************************************************/
496 : /* GDALRasterIOEx() */
497 : /************************************************************************/
498 :
499 : /**
500 : * \brief Read/write a region of image data for this band.
501 : *
502 : * @see GDALRasterBand::RasterIO()
503 : * @since GDAL 2.0
504 : */
505 :
506 39487 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
507 : int nXOff, int nYOff, int nXSize, int nYSize,
508 : void *pData, int nBufXSize, int nBufYSize,
509 : GDALDataType eBufType, GSpacing nPixelSpace,
510 : GSpacing nLineSpace,
511 : GDALRasterIOExtraArg *psExtraArg)
512 :
513 : {
514 39487 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
515 :
516 39487 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
517 :
518 39487 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
519 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
520 39482 : nLineSpace, psExtraArg));
521 : }
522 :
523 : /************************************************************************/
524 : /* GetGDTFromCppType() */
525 : /************************************************************************/
526 :
527 : namespace
528 : {
529 : template <class T> struct GetGDTFromCppType;
530 :
531 : #define DEFINE_GetGDTFromCppType(T, eDT) \
532 : template <> struct GetGDTFromCppType<T> \
533 : { \
534 : static constexpr GDALDataType GDT = eDT; \
535 : }
536 :
537 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
538 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
539 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
540 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
541 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
542 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
543 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
544 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
545 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
546 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
547 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
548 : // Not allowed by C++ standard
549 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
550 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
551 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
552 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
553 : } // namespace
554 :
555 : /************************************************************************/
556 : /* ReadRaster() */
557 : /************************************************************************/
558 :
559 : // clang-format off
560 : /** Read a region of image data for this band.
561 : *
562 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
563 : * for common use cases, like reading a whole band.
564 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
565 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
566 : * float, double, std::complex<float|double>.
567 : *
568 : * 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>&,
569 : * and can allocate memory automatically.
570 : *
571 : * To read a whole band (assuming it fits into memory), as an array of double:
572 : *
573 : \code{.cpp}
574 : double* myArray = static_cast<double*>(
575 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
576 : // TODO: check here that myArray != nullptr
577 : const size_t nArrayEltCount =
578 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
579 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
580 : {
581 : // do something
582 : }
583 : VSIFree(myArray)
584 : \endcode
585 : *
586 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
587 : *
588 : \code{.cpp}
589 : double* myArray = static_cast<double*>(
590 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
591 : // TODO: check here that myArray != nullptr
592 : const size_t nArrayEltCount = 128 * 128;
593 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
594 : {
595 : // do something
596 : }
597 : VSIFree(myArray)
598 : \endcode
599 : *
600 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
601 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
602 : * instance of this dataset) concurrently from several threads.
603 : *
604 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
605 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
606 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
607 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
608 : * Or use nLineSpace and a possibly shifted pData value.
609 : *
610 : * @param[out] pData The buffer into which the data should be written.
611 : * This buffer must contain at least nBufXSize *
612 : * nBufYSize words of type T. It is organized in left to right,
613 : * top to bottom pixel order, and fully packed.
614 : * The type of the buffer does not need to be the one of GetDataType(). The
615 : * method will perform data type translation (with potential rounding, clamping)
616 : * if needed.
617 : *
618 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
619 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
620 : * return in error if it is not. If set to zero, then pData is trusted to be
621 : * large enough.
622 : *
623 : * @param dfXOff The pixel offset to the top left corner of the region
624 : * of the band to be accessed. This would be zero to start from the left side.
625 : * Defaults to 0.
626 : *
627 : * @param dfYOff The line offset to the top left corner of the region
628 : * of the band to be accessed. This would be zero to start from the top.
629 : * Defaults to 0.
630 : *
631 : * @param dfXSize The width of the region of the band to be accessed in pixels.
632 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
633 : * dfXSize is set to the band width.
634 : *
635 : * @param dfYSize The height of the region of the band to be accessed in lines.
636 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
637 : * dfYSize is set to the band height.
638 : *
639 : * @param nBufXSize the width of the buffer image into which the desired region
640 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
641 : * then nBufXSize is initialized with dfXSize.
642 : *
643 : * @param nBufYSize the height of the buffer image into which the desired region
644 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
645 : * then nBufYSize is initialized with dfYSize.
646 : *
647 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
648 : *
649 : * @param pfnProgress Progress function. May be nullptr.
650 : *
651 : * @param pProgressData User data of pfnProgress. May be nullptr.
652 : *
653 : * @return CE_Failure if the access fails, otherwise CE_None.
654 : *
655 : * @see GDALRasterBand::RasterIO()
656 : * @since GDAL 3.10
657 : */
658 : // clang-format on
659 :
660 : template <class T>
661 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
662 : double dfXOff, double dfYOff, double dfXSize,
663 : double dfYSize, size_t nBufXSize,
664 : size_t nBufYSize,
665 : GDALRIOResampleAlg eResampleAlg,
666 : GDALProgressFunc pfnProgress,
667 : void *pProgressData) const
668 : {
669 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
670 : {
671 2 : return CE_Failure;
672 : }
673 :
674 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
675 : {
676 16 : dfXSize = nRasterXSize;
677 16 : dfYSize = nRasterYSize;
678 : }
679 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
680 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
681 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
682 2 : dfYOff + dfYSize > INT_MAX)
683 : {
684 0 : return CE_Failure;
685 : }
686 :
687 : GDALRasterIOExtraArg sExtraArg;
688 18 : sExtraArg.nVersion = 1;
689 18 : sExtraArg.eResampleAlg = eResampleAlg;
690 18 : sExtraArg.pfnProgress = pfnProgress;
691 18 : sExtraArg.pProgressData = pProgressData;
692 18 : sExtraArg.bFloatingPointWindowValidity = true;
693 18 : sExtraArg.dfXOff = dfXOff;
694 18 : sExtraArg.dfYOff = dfYOff;
695 18 : sExtraArg.dfXSize = dfXSize;
696 18 : sExtraArg.dfYSize = dfYSize;
697 18 : const int nXOff = static_cast<int>(dfXOff);
698 18 : const int nYOff = static_cast<int>(dfYOff);
699 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
700 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
701 18 : if (nBufXSize == 0 && nBufYSize == 0)
702 : {
703 17 : if (static_cast<int>(dfXSize) == dfXSize &&
704 17 : static_cast<int>(dfYSize) == dfYSize)
705 : {
706 17 : nBufXSize = static_cast<int>(dfXSize);
707 17 : nBufYSize = static_cast<int>(dfYSize);
708 : }
709 : else
710 : {
711 0 : CPLError(CE_Failure, CPLE_AppDefined,
712 : "nBufXSize and nBufYSize must be provided if dfXSize or "
713 : "dfYSize is not an integer value");
714 0 : return CE_Failure;
715 : }
716 : }
717 18 : if (nBufXSize == 0 || nBufYSize == 0)
718 : {
719 0 : CPLDebug("GDAL",
720 : "RasterIO() skipped for odd window or buffer size.\n"
721 : " Window = (%d,%d)x%dx%d\n"
722 : " Buffer = %dx%d\n",
723 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
724 : static_cast<int>(nBufYSize));
725 :
726 0 : return CE_None;
727 : }
728 :
729 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
730 : {
731 1 : CPLError(CE_Failure, CPLE_AppDefined,
732 : "Provided array is not large enough");
733 1 : return CE_Failure;
734 : }
735 :
736 17 : constexpr GSpacing nPixelSpace = sizeof(T);
737 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
738 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
739 :
740 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
741 :
742 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
743 : static_cast<int>(nBufXSize),
744 : static_cast<int>(nBufYSize), eBufType,
745 17 : nPixelSpace, nLineSpace, &sExtraArg);
746 : }
747 :
748 : //! @cond Doxygen_Suppress
749 :
750 : #define INSTANTIATE_READ_RASTER(T) \
751 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
752 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
753 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
754 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
755 : void *pProgressData) const;
756 :
757 : INSTANTIATE_READ_RASTER(uint8_t)
758 : INSTANTIATE_READ_RASTER(int8_t)
759 : INSTANTIATE_READ_RASTER(uint16_t)
760 : INSTANTIATE_READ_RASTER(int16_t)
761 : INSTANTIATE_READ_RASTER(uint32_t)
762 : INSTANTIATE_READ_RASTER(int32_t)
763 : INSTANTIATE_READ_RASTER(uint64_t)
764 : INSTANTIATE_READ_RASTER(int64_t)
765 : INSTANTIATE_READ_RASTER(GFloat16)
766 : INSTANTIATE_READ_RASTER(float)
767 : INSTANTIATE_READ_RASTER(double)
768 : // Not allowed by C++ standard
769 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
770 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
771 : INSTANTIATE_READ_RASTER(std::complex<float>)
772 : INSTANTIATE_READ_RASTER(std::complex<double>)
773 :
774 : //! @endcond
775 :
776 : /************************************************************************/
777 : /* ReadRaster() */
778 : /************************************************************************/
779 :
780 : /** Read a region of image data for this band.
781 : *
782 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
783 : * for common use cases, like reading a whole band.
784 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
785 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
786 : * float, double, std::complex<float|double>.
787 : *
788 : * To read a whole band (assuming it fits into memory), as a vector of double:
789 : *
790 : \code
791 : std::vector<double> myArray;
792 : if (poBand->ReadRaster(myArray) == CE_None)
793 : {
794 : // do something
795 : }
796 : \endcode
797 : *
798 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
799 : *
800 : \code{.cpp}
801 : std::vector<double> myArray;
802 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
803 : {
804 : // do something
805 : }
806 : \endcode
807 : *
808 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
809 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
810 : * instance of this dataset) concurrently from several threads.
811 : *
812 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
813 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
814 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
815 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
816 : * Or use nLineSpace and a possibly shifted pData value.
817 : *
818 : * @param[out] vData The vector into which the data should be written.
819 : * The vector will be resized, if needed, to contain at least nBufXSize *
820 : * nBufYSize values. The values in the vector are organized in left to right,
821 : * top to bottom pixel order, and fully packed.
822 : * The type of the vector does not need to be the one of GetDataType(). The
823 : * method will perform data type translation (with potential rounding, clamping)
824 : * if needed.
825 : *
826 : * @param dfXOff The pixel offset to the top left corner of the region
827 : * of the band to be accessed. This would be zero to start from the left side.
828 : * Defaults to 0.
829 : *
830 : * @param dfYOff The line offset to the top left corner of the region
831 : * of the band to be accessed. This would be zero to start from the top.
832 : * Defaults to 0.
833 : *
834 : * @param dfXSize The width of the region of the band to be accessed in pixels.
835 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
836 : * dfXSize is set to the band width.
837 : *
838 : * @param dfYSize The height of the region of the band to be accessed in lines.
839 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
840 : * dfYSize is set to the band height.
841 : *
842 : * @param nBufXSize the width of the buffer image into which the desired region
843 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
844 : * then nBufXSize is initialized with dfXSize.
845 : *
846 : * @param nBufYSize the height of the buffer image into which the desired region
847 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
848 : * then nBufYSize is initialized with dfYSize.
849 : *
850 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
851 : *
852 : * @param pfnProgress Progress function. May be nullptr.
853 : *
854 : * @param pProgressData User data of pfnProgress. May be nullptr.
855 : *
856 : * @return CE_Failure if the access fails, otherwise CE_None.
857 : *
858 : * @see GDALRasterBand::RasterIO()
859 : * @since GDAL 3.10
860 : */
861 : template <class T>
862 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
863 : double dfYOff, double dfXSize, double dfYSize,
864 : size_t nBufXSize, size_t nBufYSize,
865 : GDALRIOResampleAlg eResampleAlg,
866 : GDALProgressFunc pfnProgress,
867 : void *pProgressData) const
868 : {
869 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
870 : {
871 2 : return CE_Failure;
872 : }
873 :
874 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
875 : {
876 13 : dfXSize = nRasterXSize;
877 13 : dfYSize = nRasterYSize;
878 : }
879 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
880 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
881 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
882 7 : dfYOff + dfYSize > INT_MAX)
883 : {
884 0 : return CE_Failure;
885 : }
886 :
887 : GDALRasterIOExtraArg sExtraArg;
888 20 : sExtraArg.nVersion = 1;
889 20 : sExtraArg.eResampleAlg = eResampleAlg;
890 20 : sExtraArg.pfnProgress = pfnProgress;
891 20 : sExtraArg.pProgressData = pProgressData;
892 20 : sExtraArg.bFloatingPointWindowValidity = true;
893 20 : sExtraArg.dfXOff = dfXOff;
894 20 : sExtraArg.dfYOff = dfYOff;
895 20 : sExtraArg.dfXSize = dfXSize;
896 20 : sExtraArg.dfYSize = dfYSize;
897 20 : const int nXOff = static_cast<int>(dfXOff);
898 20 : const int nYOff = static_cast<int>(dfYOff);
899 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
900 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
901 20 : if (nBufXSize == 0 && nBufYSize == 0)
902 : {
903 16 : if (static_cast<int>(dfXSize) == dfXSize &&
904 15 : static_cast<int>(dfYSize) == dfYSize)
905 : {
906 15 : nBufXSize = static_cast<int>(dfXSize);
907 15 : nBufYSize = static_cast<int>(dfYSize);
908 : }
909 : else
910 : {
911 1 : CPLError(CE_Failure, CPLE_AppDefined,
912 : "nBufXSize and nBufYSize must be provided if "
913 : "dfXSize or dfYSize is not an integer value");
914 1 : return CE_Failure;
915 : }
916 : }
917 19 : if (nBufXSize == 0 || nBufYSize == 0)
918 : {
919 0 : CPLDebug("GDAL",
920 : "RasterIO() skipped for odd window or buffer size.\n"
921 : " Window = (%d,%d)x%dx%d\n"
922 : " Buffer = %dx%d\n",
923 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
924 : static_cast<int>(nBufYSize));
925 :
926 0 : return CE_None;
927 : }
928 :
929 : if constexpr (SIZEOF_VOIDP < 8)
930 : {
931 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
932 : {
933 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
934 : return CE_Failure;
935 : }
936 : }
937 :
938 19 : if (vData.size() < nBufXSize * nBufYSize)
939 : {
940 : try
941 : {
942 17 : vData.resize(nBufXSize * nBufYSize);
943 : }
944 1 : catch (const std::exception &)
945 : {
946 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
947 1 : return CE_Failure;
948 : }
949 : }
950 :
951 18 : constexpr GSpacing nPixelSpace = sizeof(T);
952 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
953 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
954 :
955 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
956 :
957 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
958 : vData.data(), static_cast<int>(nBufXSize),
959 : static_cast<int>(nBufYSize), eBufType,
960 18 : nPixelSpace, nLineSpace, &sExtraArg);
961 : }
962 :
963 : //! @cond Doxygen_Suppress
964 :
965 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
966 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
967 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
968 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
969 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
970 : void *pProgressData) const;
971 :
972 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
973 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
974 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
975 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
976 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
977 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
978 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
979 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
981 : INSTANTIATE_READ_RASTER_VECTOR(float)
982 : INSTANTIATE_READ_RASTER_VECTOR(double)
983 : // Not allowed by C++ standard
984 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
985 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
986 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
987 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
988 :
989 : //! @endcond
990 :
991 : /************************************************************************/
992 : /* ReadBlock() */
993 : /************************************************************************/
994 :
995 : /**
996 : * \brief Read a block of image data efficiently.
997 : *
998 : * This method accesses a "natural" block from the raster band without
999 : * resampling, or data type conversion. For a more generalized, but
1000 : * potentially less efficient access use RasterIO().
1001 : *
1002 : * This method is the same as the C GDALReadBlock() function.
1003 : *
1004 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1005 : * block oriented data without an extra copy into an application buffer.
1006 : *
1007 : * The following code would efficiently compute a histogram of eight bit
1008 : * raster data. Note that the final block may be partial ... data beyond
1009 : * the edge of the underlying raster band in these edge blocks is of an
1010 : * undetermined value.
1011 : *
1012 : \code{.cpp}
1013 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1014 :
1015 : {
1016 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1017 :
1018 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1019 :
1020 : int nXBlockSize, nYBlockSize;
1021 :
1022 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1023 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1024 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1025 :
1026 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1027 :
1028 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1029 : {
1030 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1031 : {
1032 : int nXValid, nYValid;
1033 :
1034 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1035 :
1036 : // Compute the portion of the block that is valid
1037 : // for partial edge blocks.
1038 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1039 :
1040 : // Collect the histogram counts.
1041 : for( int iY = 0; iY < nYValid; iY++ )
1042 : {
1043 : for( int iX = 0; iX < nXValid; iX++ )
1044 : {
1045 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1046 : }
1047 : }
1048 : }
1049 : }
1050 : }
1051 : \endcode
1052 : *
1053 : * @param nXBlockOff the horizontal block offset, with zero indicating
1054 : * the left most block, 1 the next block and so forth.
1055 : *
1056 : * @param nYBlockOff the vertical block offset, with zero indicating
1057 : * the top most block, 1 the next block and so forth.
1058 : *
1059 : * @param pImage the buffer into which the data will be read. The buffer
1060 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1061 : * of type GetRasterDataType().
1062 : *
1063 : * @return CE_None on success or CE_Failure on an error.
1064 : */
1065 :
1066 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1067 :
1068 : {
1069 : /* -------------------------------------------------------------------- */
1070 : /* Validate arguments. */
1071 : /* -------------------------------------------------------------------- */
1072 894 : CPLAssert(pImage != nullptr);
1073 :
1074 894 : if (!InitBlockInfo())
1075 0 : return CE_Failure;
1076 :
1077 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1078 : {
1079 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1080 : "Illegal nXBlockOff value (%d) in "
1081 : "GDALRasterBand::ReadBlock()\n",
1082 : nXBlockOff);
1083 :
1084 0 : return (CE_Failure);
1085 : }
1086 :
1087 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1088 : {
1089 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1090 : "Illegal nYBlockOff value (%d) in "
1091 : "GDALRasterBand::ReadBlock()\n",
1092 : nYBlockOff);
1093 :
1094 0 : return (CE_Failure);
1095 : }
1096 :
1097 : /* -------------------------------------------------------------------- */
1098 : /* Invoke underlying implementation method. */
1099 : /* -------------------------------------------------------------------- */
1100 :
1101 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1102 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1103 894 : if (bCallLeaveReadWrite)
1104 4 : LeaveReadWrite();
1105 894 : return eErr;
1106 : }
1107 :
1108 : /************************************************************************/
1109 : /* GDALReadBlock() */
1110 : /************************************************************************/
1111 :
1112 : /**
1113 : * \brief Read a block of image data efficiently.
1114 : *
1115 : * @see GDALRasterBand::ReadBlock()
1116 : */
1117 :
1118 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1119 : void *pData)
1120 :
1121 : {
1122 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1123 :
1124 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1125 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1126 : }
1127 :
1128 : /************************************************************************/
1129 : /* IReadBlock() */
1130 : /************************************************************************/
1131 :
1132 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1133 : * ) \brief Read a block of data.
1134 : *
1135 : * Default internal implementation ... to be overridden by
1136 : * subclasses that support reading.
1137 : * @param nBlockXOff Block X Offset
1138 : * @param nBlockYOff Block Y Offset
1139 : * @param pData Pixel buffer into which to place read data.
1140 : * @return CE_None on success or CE_Failure on an error.
1141 : */
1142 :
1143 : /************************************************************************/
1144 : /* IWriteBlock() */
1145 : /************************************************************************/
1146 :
1147 : /**
1148 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1149 : * Write a block of data.
1150 : *
1151 : * Default internal implementation ... to be overridden by
1152 : * subclasses that support writing.
1153 : * @param nBlockXOff Block X Offset
1154 : * @param nBlockYOff Block Y Offset
1155 : * @param pData Pixel buffer to write
1156 : * @return CE_None on success or CE_Failure on an error.
1157 : */
1158 :
1159 : /**/
1160 : /**/
1161 :
1162 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1163 : void * /*pData*/)
1164 :
1165 : {
1166 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1167 0 : ReportError(CE_Failure, CPLE_NotSupported,
1168 : "WriteBlock() not supported for this dataset.");
1169 :
1170 0 : return (CE_Failure);
1171 : }
1172 :
1173 : /************************************************************************/
1174 : /* WriteBlock() */
1175 : /************************************************************************/
1176 :
1177 : /**
1178 : * \brief Write a block of image data efficiently.
1179 : *
1180 : * This method accesses a "natural" block from the raster band without
1181 : * resampling, or data type conversion. For a more generalized, but
1182 : * potentially less efficient access use RasterIO().
1183 : *
1184 : * This method is the same as the C GDALWriteBlock() function.
1185 : *
1186 : * See ReadBlock() for an example of block oriented data access.
1187 : *
1188 : * @param nXBlockOff the horizontal block offset, with zero indicating
1189 : * the left most block, 1 the next block and so forth.
1190 : *
1191 : * @param nYBlockOff the vertical block offset, with zero indicating
1192 : * the left most block, 1 the next block and so forth.
1193 : *
1194 : * @param pImage the buffer from which the data will be written. The buffer
1195 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1196 : * of type GetRasterDataType(). Note that the content of the buffer might be
1197 : * temporarily modified during the execution of this method (and eventually
1198 : * restored back to its original content), so it is not safe to use a buffer
1199 : * stored in a read-only section of the calling program.
1200 : *
1201 : * @return CE_None on success or CE_Failure on an error.
1202 : */
1203 :
1204 4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1205 :
1206 : {
1207 : /* -------------------------------------------------------------------- */
1208 : /* Validate arguments. */
1209 : /* -------------------------------------------------------------------- */
1210 4888 : CPLAssert(pImage != nullptr);
1211 :
1212 4888 : if (!InitBlockInfo())
1213 0 : return CE_Failure;
1214 :
1215 4888 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1216 : {
1217 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1218 : "Illegal nXBlockOff value (%d) in "
1219 : "GDALRasterBand::WriteBlock()\n",
1220 : nXBlockOff);
1221 :
1222 0 : return (CE_Failure);
1223 : }
1224 :
1225 4888 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1226 : {
1227 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1228 : "Illegal nYBlockOff value (%d) in "
1229 : "GDALRasterBand::WriteBlock()\n",
1230 : nYBlockOff);
1231 :
1232 0 : return (CE_Failure);
1233 : }
1234 :
1235 4888 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1236 : {
1237 0 : return CE_Failure;
1238 : }
1239 :
1240 4888 : if (eFlushBlockErr != CE_None)
1241 : {
1242 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1243 : "An error occurred while writing a dirty block "
1244 : "from GDALRasterBand::WriteBlock");
1245 0 : CPLErr eErr = eFlushBlockErr;
1246 0 : eFlushBlockErr = CE_None;
1247 0 : return eErr;
1248 : }
1249 :
1250 : /* -------------------------------------------------------------------- */
1251 : /* Invoke underlying implementation method. */
1252 : /* -------------------------------------------------------------------- */
1253 :
1254 4888 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1255 4888 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1256 4888 : if (bCallLeaveReadWrite)
1257 4888 : LeaveReadWrite();
1258 :
1259 4888 : return eErr;
1260 : }
1261 :
1262 : /************************************************************************/
1263 : /* GDALWriteBlock() */
1264 : /************************************************************************/
1265 :
1266 : /**
1267 : * \brief Write a block of image data efficiently.
1268 : *
1269 : * @see GDALRasterBand::WriteBlock()
1270 : */
1271 :
1272 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1273 : void *pData)
1274 :
1275 : {
1276 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1277 :
1278 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1279 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1280 : }
1281 :
1282 : /************************************************************************/
1283 : /* EmitErrorMessageIfWriteNotSupported() */
1284 : /************************************************************************/
1285 :
1286 : /**
1287 : * Emit an error message if a write operation to this band is not supported.
1288 : *
1289 : * The base implementation will emit an error message if the access mode is
1290 : * read-only. Derived classes may implement it to provide a custom message.
1291 : *
1292 : * @param pszCaller Calling function.
1293 : * @return true if an error message has been emitted.
1294 : */
1295 633252 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1296 : const char *pszCaller) const
1297 : {
1298 633252 : if (eAccess == GA_ReadOnly)
1299 : {
1300 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1301 : "%s: attempt to write to dataset opened in read-only mode.",
1302 : pszCaller);
1303 :
1304 4 : return true;
1305 : }
1306 633248 : return false;
1307 : }
1308 :
1309 : /************************************************************************/
1310 : /* GetActualBlockSize() */
1311 : /************************************************************************/
1312 : /**
1313 : * \brief Fetch the actual block size for a given block offset.
1314 : *
1315 : * Handles partial blocks at the edges of the raster and returns the true
1316 : * number of pixels
1317 : *
1318 : * @param nXBlockOff the horizontal block offset for which to calculate the
1319 : * number of valid pixels, with zero indicating the left most block, 1 the next
1320 : * block and so forth.
1321 : *
1322 : * @param nYBlockOff the vertical block offset, with zero indicating
1323 : * the top most block, 1 the next block and so forth.
1324 : *
1325 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1326 : * the x direction will be stored
1327 : *
1328 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1329 : * the y direction will be stored
1330 : *
1331 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1332 : *
1333 : * @since GDAL 2.2
1334 : */
1335 51518 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1336 : int *pnXValid, int *pnYValid) const
1337 : {
1338 103035 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1339 103033 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1340 103030 : nYBlockOff < 0 || nBlockYSize == 0 ||
1341 51515 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1342 : {
1343 4 : return CE_Failure;
1344 : }
1345 :
1346 51514 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1347 51514 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1348 :
1349 51514 : *pnXValid = nBlockXSize;
1350 51514 : *pnYValid = nBlockYSize;
1351 :
1352 51514 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1353 : {
1354 50126 : *pnXValid = nRasterXSize - nXPixelOff;
1355 : }
1356 :
1357 51514 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1358 : {
1359 3517 : *pnYValid = nRasterYSize - nYPixelOff;
1360 : }
1361 :
1362 51514 : return CE_None;
1363 : }
1364 :
1365 : /************************************************************************/
1366 : /* GDALGetActualBlockSize() */
1367 : /************************************************************************/
1368 :
1369 : /**
1370 : * \brief Retrieve the actual block size for a given block offset.
1371 : *
1372 : * @see GDALRasterBand::GetActualBlockSize()
1373 : */
1374 :
1375 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1376 : int nYBlockOff, int *pnXValid,
1377 : int *pnYValid)
1378 :
1379 : {
1380 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1381 :
1382 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1383 : return (
1384 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1385 : }
1386 :
1387 : /************************************************************************/
1388 : /* GetSuggestedBlockAccessPattern() */
1389 : /************************************************************************/
1390 :
1391 : /**
1392 : * \brief Return the suggested/most efficient access pattern to blocks
1393 : * (for read operations).
1394 : *
1395 : * While all GDAL drivers have to expose a block size, not all can guarantee
1396 : * efficient random access (GSBAP_RANDOM) to any block.
1397 : * Some drivers for example decompress sequentially a compressed stream from
1398 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1399 : * case best performance will be achieved while reading blocks in that order.
1400 : * (accessing blocks in random access in such rasters typically causes the
1401 : * decoding to be re-initialized from the start if accessing blocks in
1402 : * a non-sequential order)
1403 : *
1404 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1405 : * returned by drivers that expose a somewhat artificial block size, because
1406 : * they can extract any part of a raster, but in a rather inefficient way.
1407 : *
1408 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1409 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1410 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1411 : * most efficient strategy is to read as many pixels as possible in the less
1412 : * RasterIO() operations.
1413 : *
1414 : * The return of this method is for example used to determine the swath size
1415 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1416 : *
1417 : * @since GDAL 3.6
1418 : */
1419 :
1420 : GDALSuggestedBlockAccessPattern
1421 2357 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1422 : {
1423 2357 : return GSBAP_UNKNOWN;
1424 : }
1425 :
1426 : /************************************************************************/
1427 : /* GetRasterDataType() */
1428 : /************************************************************************/
1429 :
1430 : /**
1431 : * \brief Fetch the pixel data type for this band.
1432 : *
1433 : * This method is the same as the C function GDALGetRasterDataType().
1434 : *
1435 : * @return the data type of pixels for this band.
1436 : */
1437 :
1438 9018490 : GDALDataType GDALRasterBand::GetRasterDataType() const
1439 :
1440 : {
1441 9018490 : return eDataType;
1442 : }
1443 :
1444 : /************************************************************************/
1445 : /* GDALGetRasterDataType() */
1446 : /************************************************************************/
1447 :
1448 : /**
1449 : * \brief Fetch the pixel data type for this band.
1450 : *
1451 : * @see GDALRasterBand::GetRasterDataType()
1452 : */
1453 :
1454 904167 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1455 :
1456 : {
1457 904167 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1458 :
1459 904167 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1460 904167 : return poBand->GetRasterDataType();
1461 : }
1462 :
1463 : /************************************************************************/
1464 : /* GetBlockSize() */
1465 : /************************************************************************/
1466 :
1467 : /**
1468 : * \brief Fetch the "natural" block size of this band.
1469 : *
1470 : * GDAL contains a concept of the natural block size of rasters so that
1471 : * applications can organized data access efficiently for some file formats.
1472 : * The natural block size is the block size that is most efficient for
1473 : * accessing the format. For many formats this is simple a whole scanline
1474 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1475 : *
1476 : * However, for tiled images this will typically be the tile size.
1477 : *
1478 : * Note that the X and Y block sizes don't have to divide the image size
1479 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1480 : * See ReadBlock() for an example of code dealing with these issues.
1481 : *
1482 : * This method is the same as the C function GDALGetBlockSize().
1483 : *
1484 : * @param pnXSize integer to put the X block size into or NULL.
1485 : *
1486 : * @param pnYSize integer to put the Y block size into or NULL.
1487 : */
1488 :
1489 5547730 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1490 :
1491 : {
1492 5547730 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1493 : {
1494 7322 : ReportError(CE_Failure, CPLE_AppDefined,
1495 7322 : "Invalid block dimension : %d * %d", nBlockXSize,
1496 7322 : nBlockYSize);
1497 0 : if (pnXSize != nullptr)
1498 0 : *pnXSize = 0;
1499 0 : if (pnYSize != nullptr)
1500 0 : *pnYSize = 0;
1501 : }
1502 : else
1503 : {
1504 5540400 : if (pnXSize != nullptr)
1505 5538160 : *pnXSize = nBlockXSize;
1506 5540400 : if (pnYSize != nullptr)
1507 5541600 : *pnYSize = nBlockYSize;
1508 : }
1509 5540400 : }
1510 :
1511 : /************************************************************************/
1512 : /* GDALGetBlockSize() */
1513 : /************************************************************************/
1514 :
1515 : /**
1516 : * \brief Fetch the "natural" block size of this band.
1517 : *
1518 : * @see GDALRasterBand::GetBlockSize()
1519 : */
1520 :
1521 41109 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1522 : int *pnYSize)
1523 :
1524 : {
1525 41109 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1526 :
1527 41109 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1528 41109 : poBand->GetBlockSize(pnXSize, pnYSize);
1529 : }
1530 :
1531 : /************************************************************************/
1532 : /* InitBlockInfo() */
1533 : /************************************************************************/
1534 :
1535 : //! @cond Doxygen_Suppress
1536 3668120 : int GDALRasterBand::InitBlockInfo()
1537 :
1538 : {
1539 3668120 : if (poBandBlockCache != nullptr)
1540 3430400 : return poBandBlockCache->IsInitOK();
1541 :
1542 : /* Do some validation of raster and block dimensions in case the driver */
1543 : /* would have neglected to do it itself */
1544 237722 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1545 : {
1546 4 : ReportError(CE_Failure, CPLE_AppDefined,
1547 : "Invalid block dimension : %d * %d", nBlockXSize,
1548 : nBlockYSize);
1549 0 : return FALSE;
1550 : }
1551 :
1552 237718 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1553 : {
1554 1 : ReportError(CE_Failure, CPLE_AppDefined,
1555 : "Invalid raster dimension : %d * %d", nRasterXSize,
1556 : nRasterYSize);
1557 0 : return FALSE;
1558 : }
1559 :
1560 237717 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1561 237717 : if (nDataTypeSize == 0)
1562 : {
1563 0 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1564 0 : return FALSE;
1565 : }
1566 :
1567 : #if SIZEOF_VOIDP == 4
1568 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1569 : {
1570 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1571 : * multiplication in other cases */
1572 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1573 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1574 : {
1575 : ReportError(CE_Failure, CPLE_NotSupported,
1576 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1577 : nBlockYSize);
1578 : return FALSE;
1579 : }
1580 : }
1581 : #endif
1582 :
1583 237717 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1584 237717 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1585 :
1586 : const char *pszBlockStrategy =
1587 237717 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1588 237721 : bool bUseArray = true;
1589 237721 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1590 : {
1591 237681 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1592 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1593 : {
1594 237662 : GUIntBig nBlockCount =
1595 237662 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1596 237662 : if (poDS != nullptr)
1597 237462 : nBlockCount *= poDS->GetRasterCount();
1598 237663 : bUseArray = (nBlockCount < 1024 * 1024);
1599 : }
1600 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1601 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1602 : {
1603 0 : bUseArray = false;
1604 237682 : }
1605 : }
1606 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1607 40 : bUseArray = false;
1608 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1609 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1610 : pszBlockStrategy);
1611 :
1612 237719 : if (bUseArray)
1613 237648 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1614 : else
1615 : {
1616 71 : if (nBand == 1)
1617 26 : CPLDebug("GDAL", "Use hashset band block cache");
1618 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1619 : }
1620 237721 : if (poBandBlockCache == nullptr)
1621 0 : return FALSE;
1622 237721 : return poBandBlockCache->Init();
1623 : }
1624 :
1625 : //! @endcond
1626 :
1627 : /************************************************************************/
1628 : /* FlushCache() */
1629 : /************************************************************************/
1630 :
1631 : /**
1632 : * \brief Flush raster data cache.
1633 : *
1634 : * This call will recover memory used to cache data blocks for this raster
1635 : * band, and ensure that new requests are referred to the underlying driver.
1636 : *
1637 : * This method is the same as the C function GDALFlushRasterCache().
1638 : *
1639 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1640 : * @return CE_None on success.
1641 : */
1642 :
1643 5701820 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1644 :
1645 : {
1646 5815120 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1647 113306 : poBandBlockCache)
1648 2920 : poBandBlockCache->DisableDirtyBlockWriting();
1649 :
1650 5701200 : CPLErr eGlobalErr = eFlushBlockErr;
1651 :
1652 5701200 : if (eFlushBlockErr != CE_None)
1653 : {
1654 0 : ReportError(
1655 : eFlushBlockErr, CPLE_AppDefined,
1656 : "An error occurred while writing a dirty block from FlushCache");
1657 0 : eFlushBlockErr = CE_None;
1658 : }
1659 :
1660 5701200 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1661 4937300 : return eGlobalErr;
1662 :
1663 763906 : return poBandBlockCache->FlushCache();
1664 : }
1665 :
1666 : /************************************************************************/
1667 : /* GDALFlushRasterCache() */
1668 : /************************************************************************/
1669 :
1670 : /**
1671 : * \brief Flush raster data cache.
1672 : *
1673 : * @see GDALRasterBand::FlushCache()
1674 : */
1675 :
1676 487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1677 :
1678 : {
1679 487 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1680 :
1681 487 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1682 : }
1683 :
1684 : /************************************************************************/
1685 : /* DropCache() */
1686 : /************************************************************************/
1687 :
1688 : /**
1689 : * \brief Drop raster data cache : data in cache will be lost.
1690 : *
1691 : * This call will recover memory used to cache data blocks for this raster
1692 : * band, and ensure that new requests are referred to the underlying driver.
1693 : *
1694 : * This method is the same as the C function GDALDropRasterCache().
1695 : *
1696 : * @return CE_None on success.
1697 : * @since 3.9
1698 : */
1699 :
1700 1 : CPLErr GDALRasterBand::DropCache()
1701 :
1702 : {
1703 1 : CPLErr result = CE_None;
1704 :
1705 1 : if (poBandBlockCache)
1706 1 : poBandBlockCache->DisableDirtyBlockWriting();
1707 :
1708 1 : CPLErr eGlobalErr = eFlushBlockErr;
1709 :
1710 1 : if (eFlushBlockErr != CE_None)
1711 : {
1712 0 : ReportError(
1713 : eFlushBlockErr, CPLE_AppDefined,
1714 : "An error occurred while writing a dirty block from DropCache");
1715 0 : eFlushBlockErr = CE_None;
1716 : }
1717 :
1718 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1719 0 : result = eGlobalErr;
1720 : else
1721 1 : result = poBandBlockCache->FlushCache();
1722 :
1723 1 : if (poBandBlockCache)
1724 1 : poBandBlockCache->EnableDirtyBlockWriting();
1725 :
1726 1 : return result;
1727 : }
1728 :
1729 : /************************************************************************/
1730 : /* GDALDropRasterCache() */
1731 : /************************************************************************/
1732 :
1733 : /**
1734 : * \brief Drop raster data cache.
1735 : *
1736 : * @see GDALRasterBand::DropCache()
1737 : * @since 3.9
1738 : */
1739 :
1740 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1741 :
1742 : {
1743 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1744 :
1745 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1746 : }
1747 :
1748 : /************************************************************************/
1749 : /* UnreferenceBlock() */
1750 : /* */
1751 : /* Unreference the block from our array of blocks */
1752 : /* This method should only be called by */
1753 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1754 : /* the block cache mutex) */
1755 : /************************************************************************/
1756 :
1757 29820 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1758 : {
1759 : #ifdef notdef
1760 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1761 : {
1762 : if (poBandBlockCache == nullptr)
1763 : printf("poBandBlockCache == NULL\n"); /*ok*/
1764 : else
1765 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1766 : printf("caller = %s\n", pszCaller); /*ok*/
1767 : printf("GDALRasterBand: %p\n", this); /*ok*/
1768 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1769 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1770 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1771 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1772 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1773 : poBlock->DumpBlock();
1774 : if (GetDataset() != nullptr)
1775 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1776 : GDALRasterBlock::Verify();
1777 : abort();
1778 : }
1779 : #endif
1780 29820 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1781 29820 : return poBandBlockCache->UnreferenceBlock(poBlock);
1782 : }
1783 :
1784 : /************************************************************************/
1785 : /* AddBlockToFreeList() */
1786 : /* */
1787 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1788 : /* finished with a block about to be free'd, they pass it to that */
1789 : /* method. */
1790 : /************************************************************************/
1791 :
1792 : //! @cond Doxygen_Suppress
1793 29820 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1794 : {
1795 29820 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1796 29820 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1797 : }
1798 :
1799 : //! @endcond
1800 :
1801 : /************************************************************************/
1802 : /* FlushBlock() */
1803 : /************************************************************************/
1804 :
1805 : /** Flush a block out of the block cache.
1806 : * @param nXBlockOff block x offset
1807 : * @param nYBlockOff blocky offset
1808 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1809 : * @return CE_None in case of success, an error code otherwise.
1810 : */
1811 2310 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1812 : int bWriteDirtyBlock)
1813 :
1814 : {
1815 2310 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1816 0 : return (CE_Failure);
1817 :
1818 : /* -------------------------------------------------------------------- */
1819 : /* Validate the request */
1820 : /* -------------------------------------------------------------------- */
1821 2310 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1822 : {
1823 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1824 : "Illegal nBlockXOff value (%d) in "
1825 : "GDALRasterBand::FlushBlock()\n",
1826 : nXBlockOff);
1827 :
1828 0 : return (CE_Failure);
1829 : }
1830 :
1831 2310 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1832 : {
1833 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1834 : "Illegal nBlockYOff value (%d) in "
1835 : "GDALRasterBand::FlushBlock()\n",
1836 : nYBlockOff);
1837 :
1838 0 : return (CE_Failure);
1839 : }
1840 :
1841 2310 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1842 2310 : bWriteDirtyBlock);
1843 : }
1844 :
1845 : /************************************************************************/
1846 : /* TryGetLockedBlockRef() */
1847 : /************************************************************************/
1848 :
1849 : /**
1850 : * \brief Try fetching block ref.
1851 : *
1852 : * This method will returned the requested block (locked) if it is already
1853 : * in the block cache for the layer. If not, nullptr is returned.
1854 : *
1855 : * If a non-NULL value is returned, then a lock for the block will have been
1856 : * acquired on behalf of the caller. It is absolutely imperative that the
1857 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1858 : * severe problems may result.
1859 : *
1860 : * @param nXBlockOff the horizontal block offset, with zero indicating
1861 : * the left most block, 1 the next block and so forth.
1862 : *
1863 : * @param nYBlockOff the vertical block offset, with zero indicating
1864 : * the top most block, 1 the next block and so forth.
1865 : *
1866 : * @return NULL if block not available, or locked block pointer.
1867 : */
1868 :
1869 10655000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1870 : int nYBlockOff)
1871 :
1872 : {
1873 10655000 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1874 171618 : return nullptr;
1875 :
1876 : /* -------------------------------------------------------------------- */
1877 : /* Validate the request */
1878 : /* -------------------------------------------------------------------- */
1879 10484700 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1880 : {
1881 797 : ReportError(CE_Failure, CPLE_IllegalArg,
1882 : "Illegal nBlockXOff value (%d) in "
1883 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1884 : nXBlockOff);
1885 :
1886 0 : return (nullptr);
1887 : }
1888 :
1889 10483900 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1890 : {
1891 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1892 : "Illegal nBlockYOff value (%d) in "
1893 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1894 : nYBlockOff);
1895 :
1896 0 : return (nullptr);
1897 : }
1898 :
1899 10483900 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1900 : }
1901 :
1902 : /************************************************************************/
1903 : /* GetLockedBlockRef() */
1904 : /************************************************************************/
1905 :
1906 : /**
1907 : * \brief Fetch a pointer to an internally cached raster block.
1908 : *
1909 : * This method will returned the requested block (locked) if it is already
1910 : * in the block cache for the layer. If not, the block will be read from
1911 : * the driver, and placed in the layer block cached, then returned. If an
1912 : * error occurs reading the block from the driver, a NULL value will be
1913 : * returned.
1914 : *
1915 : * If a non-NULL value is returned, then a lock for the block will have been
1916 : * acquired on behalf of the caller. It is absolutely imperative that the
1917 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1918 : * severe problems may result.
1919 : *
1920 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1921 : * enable caching.
1922 : *
1923 : * @param nXBlockOff the horizontal block offset, with zero indicating
1924 : * the left most block, 1 the next block and so forth.
1925 : *
1926 : * @param nYBlockOff the vertical block offset, with zero indicating
1927 : * the top most block, 1 the next block and so forth.
1928 : *
1929 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1930 : * but not actually read from the source. This is useful when it will just
1931 : * be completely set and written back.
1932 : *
1933 : * @return pointer to the block object, or NULL on failure.
1934 : */
1935 :
1936 10345900 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1937 : int nYBlockOff,
1938 : int bJustInitialize)
1939 :
1940 : {
1941 : /* -------------------------------------------------------------------- */
1942 : /* Try and fetch from cache. */
1943 : /* -------------------------------------------------------------------- */
1944 10345900 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1945 :
1946 : /* -------------------------------------------------------------------- */
1947 : /* If we didn't find it in our memory cache, instantiate a */
1948 : /* block (potentially load from disk) and "adopt" it into the */
1949 : /* cache. */
1950 : /* -------------------------------------------------------------------- */
1951 10349900 : if (poBlock == nullptr)
1952 : {
1953 3391430 : if (!InitBlockInfo())
1954 0 : return (nullptr);
1955 :
1956 : /* --------------------------------------------------------------------
1957 : */
1958 : /* Validate the request */
1959 : /* --------------------------------------------------------------------
1960 : */
1961 3391420 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1962 : {
1963 33 : ReportError(CE_Failure, CPLE_IllegalArg,
1964 : "Illegal nBlockXOff value (%d) in "
1965 : "GDALRasterBand::GetLockedBlockRef()\n",
1966 : nXBlockOff);
1967 :
1968 0 : return (nullptr);
1969 : }
1970 :
1971 3391390 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1972 : {
1973 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1974 : "Illegal nBlockYOff value (%d) in "
1975 : "GDALRasterBand::GetLockedBlockRef()\n",
1976 : nYBlockOff);
1977 :
1978 0 : return (nullptr);
1979 : }
1980 :
1981 3391410 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1982 3391420 : if (poBlock == nullptr)
1983 0 : return nullptr;
1984 :
1985 3391420 : poBlock->AddLock();
1986 :
1987 : /* We need to temporarily drop the read-write lock in the following */
1988 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1989 : */
1990 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1991 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1992 : */
1993 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1994 : */
1995 : /* called and attempt at taking the lock on T2 (already taken).
1996 : * Similarly */
1997 : /* for T2 with D1, hence a deadlock situation (#6163) */
1998 : /* But this may open the door to other problems... */
1999 3391420 : if (poDS)
2000 3390690 : poDS->TemporarilyDropReadWriteLock();
2001 : /* allocate data space */
2002 3391430 : CPLErr eErr = poBlock->Internalize();
2003 3391450 : if (poDS)
2004 3390710 : poDS->ReacquireReadWriteLock();
2005 3391440 : if (eErr != CE_None)
2006 : {
2007 0 : poBlock->DropLock();
2008 0 : delete poBlock;
2009 0 : return nullptr;
2010 : }
2011 :
2012 3391440 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2013 : {
2014 0 : poBlock->DropLock();
2015 0 : delete poBlock;
2016 0 : return nullptr;
2017 : }
2018 :
2019 3391440 : if (!bJustInitialize)
2020 : {
2021 2904040 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2022 2904030 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2023 2903670 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2024 2904030 : if (bCallLeaveReadWrite)
2025 129988 : LeaveReadWrite();
2026 2904020 : if (eErr != CE_None)
2027 : {
2028 1160 : poBlock->DropLock();
2029 1160 : FlushBlock(nXBlockOff, nYBlockOff);
2030 1160 : ReportError(CE_Failure, CPLE_AppDefined,
2031 : "IReadBlock failed at X offset %d, Y offset %d%s",
2032 : nXBlockOff, nYBlockOff,
2033 1160 : (nErrorCounter != CPLGetErrorCounter())
2034 1158 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2035 : : "");
2036 1160 : return nullptr;
2037 : }
2038 :
2039 2902860 : nBlockReads++;
2040 2902860 : if (static_cast<GIntBig>(nBlockReads) ==
2041 2902860 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2042 219 : 1 &&
2043 219 : nBand == 1 && poDS != nullptr)
2044 : {
2045 159 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2046 159 : poDS->GetDescription());
2047 : }
2048 : }
2049 : }
2050 :
2051 10348800 : return poBlock;
2052 : }
2053 :
2054 : /************************************************************************/
2055 : /* Fill() */
2056 : /************************************************************************/
2057 :
2058 : /**
2059 : * \brief Fill this band with a constant value.
2060 : *
2061 : * GDAL makes no guarantees
2062 : * about what values pixels in newly created files are set to, so this
2063 : * method can be used to clear a band to a specified "default" value.
2064 : * The fill value is passed in as a double but this will be converted
2065 : * to the underlying type before writing to the file. An optional
2066 : * second argument allows the imaginary component of a complex
2067 : * constant value to be specified.
2068 : *
2069 : * This method is the same as the C function GDALFillRaster().
2070 : *
2071 : * @param dfRealValue Real component of fill value
2072 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2073 : *
2074 : * @return CE_Failure if the write fails, otherwise CE_None
2075 : */
2076 268645 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2077 : {
2078 :
2079 : // General approach is to construct a source block of the file's
2080 : // native type containing the appropriate value and then copy this
2081 : // to each block in the image via the RasterBlock cache. Using
2082 : // the cache means we avoid file I/O if it is not necessary, at the
2083 : // expense of some extra memcpy's (since we write to the
2084 : // RasterBlock cache, which is then at some point written to the
2085 : // underlying file, rather than simply directly to the underlying
2086 : // file.)
2087 :
2088 : // Check we can write to the file.
2089 268645 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2090 : {
2091 6 : return CE_Failure;
2092 : }
2093 :
2094 : // Make sure block parameters are set.
2095 268639 : if (!InitBlockInfo())
2096 0 : return CE_Failure;
2097 :
2098 : // Allocate the source block.
2099 268639 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2100 268639 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2101 268639 : auto blockByteSize = blockSize * elementSize;
2102 : unsigned char *srcBlock =
2103 268639 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2104 268639 : if (srcBlock == nullptr)
2105 : {
2106 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2107 : "GDALRasterBand::Fill(): Out of memory "
2108 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2109 : static_cast<GUIntBig>(blockByteSize));
2110 0 : return CE_Failure;
2111 : }
2112 :
2113 : // Initialize the source block.
2114 268639 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2115 268639 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2116 : elementSize, blockSize);
2117 :
2118 268639 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2119 :
2120 : // Write block to block cache
2121 874182 : for (int j = 0; j < nBlocksPerColumn; ++j)
2122 : {
2123 1505420 : for (int i = 0; i < nBlocksPerRow; ++i)
2124 : {
2125 899876 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2126 899876 : if (destBlock == nullptr)
2127 : {
2128 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2129 : "GDALRasterBand::Fill(): Error "
2130 : "while retrieving cache block.");
2131 0 : VSIFree(srcBlock);
2132 0 : return CE_Failure;
2133 : }
2134 899876 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2135 899876 : destBlock->MarkDirty();
2136 899876 : destBlock->DropLock();
2137 : }
2138 : }
2139 :
2140 268639 : if (bCallLeaveReadWrite)
2141 267628 : LeaveReadWrite();
2142 :
2143 : // Free up the source block
2144 268639 : VSIFree(srcBlock);
2145 :
2146 268639 : return CE_None;
2147 : }
2148 :
2149 : /************************************************************************/
2150 : /* GDALFillRaster() */
2151 : /************************************************************************/
2152 :
2153 : /**
2154 : * \brief Fill this band with a constant value.
2155 : *
2156 : * @see GDALRasterBand::Fill()
2157 : */
2158 268582 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2159 : double dfImaginaryValue)
2160 : {
2161 268582 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2162 :
2163 268582 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2164 268582 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2165 : }
2166 :
2167 : /************************************************************************/
2168 : /* GetAccess() */
2169 : /************************************************************************/
2170 :
2171 : /**
2172 : * \brief Find out if we have update permission for this band.
2173 : *
2174 : * This method is the same as the C function GDALGetRasterAccess().
2175 : *
2176 : * @return Either GA_Update or GA_ReadOnly.
2177 : */
2178 :
2179 2907 : GDALAccess GDALRasterBand::GetAccess()
2180 :
2181 : {
2182 2907 : return eAccess;
2183 : }
2184 :
2185 : /************************************************************************/
2186 : /* GDALGetRasterAccess() */
2187 : /************************************************************************/
2188 :
2189 : /**
2190 : * \brief Find out if we have update permission for this band.
2191 : *
2192 : * @see GDALRasterBand::GetAccess()
2193 : */
2194 :
2195 2258 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2196 :
2197 : {
2198 2258 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2199 :
2200 2258 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2201 2258 : return poBand->GetAccess();
2202 : }
2203 :
2204 : /************************************************************************/
2205 : /* GetCategoryNames() */
2206 : /************************************************************************/
2207 :
2208 : /**
2209 : * \brief Fetch the list of category names for this raster.
2210 : *
2211 : * The return list is a "StringList" in the sense of the CPL functions.
2212 : * That is a NULL terminated array of strings. Raster values without
2213 : * associated names will have an empty string in the returned list. The
2214 : * first entry in the list is for raster values of zero, and so on.
2215 : *
2216 : * The returned stringlist should not be altered or freed by the application.
2217 : * It may change on the next GDAL call, so please copy it if it is needed
2218 : * for any period of time.
2219 : *
2220 : * This method is the same as the C function GDALGetRasterCategoryNames().
2221 : *
2222 : * @return list of names, or NULL if none.
2223 : */
2224 :
2225 294 : char **GDALRasterBand::GetCategoryNames()
2226 :
2227 : {
2228 294 : return nullptr;
2229 : }
2230 :
2231 : /************************************************************************/
2232 : /* GDALGetRasterCategoryNames() */
2233 : /************************************************************************/
2234 :
2235 : /**
2236 : * \brief Fetch the list of category names for this raster.
2237 : *
2238 : * @see GDALRasterBand::GetCategoryNames()
2239 : */
2240 :
2241 191 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2242 :
2243 : {
2244 191 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2245 :
2246 191 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2247 191 : return poBand->GetCategoryNames();
2248 : }
2249 :
2250 : /************************************************************************/
2251 : /* SetCategoryNames() */
2252 : /************************************************************************/
2253 :
2254 : /**
2255 : * \fn GDALRasterBand::SetCategoryNames(char**)
2256 : * \brief Set the category names for this band.
2257 : *
2258 : * See the GetCategoryNames() method for more on the interpretation of
2259 : * category names.
2260 : *
2261 : * This method is the same as the C function GDALSetRasterCategoryNames().
2262 : *
2263 : * @param papszNames the NULL terminated StringList of category names. May
2264 : * be NULL to just clear the existing list.
2265 : *
2266 : * @return CE_None on success of CE_Failure on failure. If unsupported
2267 : * by the driver CE_Failure is returned, but no error message is reported.
2268 : */
2269 :
2270 : /**/
2271 : /**/
2272 :
2273 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2274 : {
2275 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2276 0 : ReportError(CE_Failure, CPLE_NotSupported,
2277 : "SetCategoryNames() not supported for this dataset.");
2278 :
2279 0 : return CE_Failure;
2280 : }
2281 :
2282 : /************************************************************************/
2283 : /* GDALSetCategoryNames() */
2284 : /************************************************************************/
2285 :
2286 : /**
2287 : * \brief Set the category names for this band.
2288 : *
2289 : * @see GDALRasterBand::SetCategoryNames()
2290 : */
2291 :
2292 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2293 : CSLConstList papszNames)
2294 :
2295 : {
2296 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2297 :
2298 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2299 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2300 : }
2301 :
2302 : /************************************************************************/
2303 : /* GetNoDataValue() */
2304 : /************************************************************************/
2305 :
2306 : /**
2307 : * \brief Fetch the no data value for this band.
2308 : *
2309 : * If there is no out of data value, an out of range value will generally
2310 : * be returned. The no data value for a band is generally a special marker
2311 : * value used to mark pixels that are not valid data. Such pixels should
2312 : * generally not be displayed, nor contribute to analysis operations.
2313 : *
2314 : * The no data value returned is 'raw', meaning that it has no offset and
2315 : * scale applied.
2316 : *
2317 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2318 : * lossy if the nodata value cannot exactly been represented by a double.
2319 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2320 : *
2321 : * This method is the same as the C function GDALGetRasterNoDataValue().
2322 : *
2323 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2324 : * is actually associated with this layer. May be NULL (default).
2325 : *
2326 : * @return the nodata value for this band.
2327 : */
2328 :
2329 31573 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2330 :
2331 : {
2332 31573 : if (pbSuccess != nullptr)
2333 31573 : *pbSuccess = FALSE;
2334 :
2335 31573 : return -1e10;
2336 : }
2337 :
2338 : /************************************************************************/
2339 : /* GDALGetRasterNoDataValue() */
2340 : /************************************************************************/
2341 :
2342 : /**
2343 : * \brief Fetch the no data value for this band.
2344 : *
2345 : * @see GDALRasterBand::GetNoDataValue()
2346 : */
2347 :
2348 414251 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2349 : int *pbSuccess)
2350 :
2351 : {
2352 414251 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2353 :
2354 414251 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2355 414251 : return poBand->GetNoDataValue(pbSuccess);
2356 : }
2357 :
2358 : /************************************************************************/
2359 : /* GetNoDataValueAsInt64() */
2360 : /************************************************************************/
2361 :
2362 : /**
2363 : * \brief Fetch the no data value for this band.
2364 : *
2365 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2366 : *
2367 : * If there is no out of data value, an out of range value will generally
2368 : * be returned. The no data value for a band is generally a special marker
2369 : * value used to mark pixels that are not valid data. Such pixels should
2370 : * generally not be displayed, nor contribute to analysis operations.
2371 : *
2372 : * The no data value returned is 'raw', meaning that it has no offset and
2373 : * scale applied.
2374 : *
2375 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2376 : *
2377 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2378 : * is actually associated with this layer. May be NULL (default).
2379 : *
2380 : * @return the nodata value for this band.
2381 : *
2382 : * @since GDAL 3.5
2383 : */
2384 :
2385 4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2386 :
2387 : {
2388 4 : if (pbSuccess != nullptr)
2389 4 : *pbSuccess = FALSE;
2390 :
2391 4 : return std::numeric_limits<int64_t>::min();
2392 : }
2393 :
2394 : /************************************************************************/
2395 : /* GDALGetRasterNoDataValueAsInt64() */
2396 : /************************************************************************/
2397 :
2398 : /**
2399 : * \brief Fetch the no data value for this band.
2400 : *
2401 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2402 : *
2403 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2404 : *
2405 : * @since GDAL 3.5
2406 : */
2407 :
2408 27 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2409 : int *pbSuccess)
2410 :
2411 : {
2412 27 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2413 : std::numeric_limits<int64_t>::min());
2414 :
2415 27 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2416 27 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2417 : }
2418 :
2419 : /************************************************************************/
2420 : /* GetNoDataValueAsUInt64() */
2421 : /************************************************************************/
2422 :
2423 : /**
2424 : * \brief Fetch the no data value for this band.
2425 : *
2426 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2427 : *
2428 : * If there is no out of data value, an out of range value will generally
2429 : * be returned. The no data value for a band is generally a special marker
2430 : * value used to mark pixels that are not valid data. Such pixels should
2431 : * generally not be displayed, nor contribute to analysis operations.
2432 : *
2433 : * The no data value returned is 'raw', meaning that it has no offset and
2434 : * scale applied.
2435 : *
2436 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2437 : *
2438 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2439 : * is actually associated with this layer. May be NULL (default).
2440 : *
2441 : * @return the nodata value for this band.
2442 : *
2443 : * @since GDAL 3.5
2444 : */
2445 :
2446 3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2447 :
2448 : {
2449 3 : if (pbSuccess != nullptr)
2450 3 : *pbSuccess = FALSE;
2451 :
2452 3 : return std::numeric_limits<uint64_t>::max();
2453 : }
2454 :
2455 : /************************************************************************/
2456 : /* GDALGetRasterNoDataValueAsUInt64() */
2457 : /************************************************************************/
2458 :
2459 : /**
2460 : * \brief Fetch the no data value for this band.
2461 : *
2462 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2463 : *
2464 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2465 : *
2466 : * @since GDAL 3.5
2467 : */
2468 :
2469 18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2470 : int *pbSuccess)
2471 :
2472 : {
2473 18 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2474 : std::numeric_limits<uint64_t>::max());
2475 :
2476 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2477 18 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2478 : }
2479 :
2480 : /************************************************************************/
2481 : /* SetNoDataValueAsString() */
2482 : /************************************************************************/
2483 :
2484 : /**
2485 : * \brief Set the no data value for this band.
2486 : *
2487 : * Depending on drivers, changing the no data value may or may not have an
2488 : * effect on the pixel values of a raster that has just been created. It is
2489 : * thus advised to explicitly called Fill() if the intent is to initialize
2490 : * the raster to the nodata value.
2491 : * In any case, changing an existing no data value, when one already exists and
2492 : * the dataset exists or has been initialized, has no effect on the pixel whose
2493 : * value matched the previous nodata value.
2494 : *
2495 : * To clear the nodata value, use DeleteNoDataValue().
2496 : *
2497 : * @param pszNoData the value to set.
2498 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2499 : * If the value cannot be exactly represented on the output data
2500 : * type, *pbCannotBeExactlyRepresented will be set to true.
2501 : *
2502 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2503 : * by the driver, CE_Failure is returned but no error message will have
2504 : * been emitted.
2505 : *
2506 : * @since 3.11
2507 : */
2508 :
2509 : CPLErr
2510 123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2511 : bool *pbCannotBeExactlyRepresented)
2512 : {
2513 123 : if (pbCannotBeExactlyRepresented)
2514 123 : *pbCannotBeExactlyRepresented = false;
2515 123 : if (eDataType == GDT_Int64)
2516 : {
2517 8 : if (strchr(pszNoData, '.') ||
2518 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2519 : {
2520 2 : char *endptr = nullptr;
2521 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2522 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2523 2 : GDALIsValueExactAs<int64_t>(dfVal))
2524 : {
2525 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2526 : }
2527 : }
2528 : else
2529 : {
2530 : try
2531 : {
2532 7 : const auto val = std::stoll(pszNoData);
2533 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2534 : }
2535 2 : catch (const std::exception &)
2536 : {
2537 : }
2538 : }
2539 : }
2540 118 : else if (eDataType == GDT_UInt64)
2541 : {
2542 2 : if (strchr(pszNoData, '.') ||
2543 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2544 : {
2545 0 : char *endptr = nullptr;
2546 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2547 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2548 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2549 : {
2550 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2551 : }
2552 : }
2553 : else
2554 : {
2555 : try
2556 : {
2557 1 : const auto val = std::stoull(pszNoData);
2558 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2559 : }
2560 0 : catch (const std::exception &)
2561 : {
2562 : }
2563 : }
2564 : }
2565 117 : else if (eDataType == GDT_Float32)
2566 : {
2567 10 : char *endptr = nullptr;
2568 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2569 10 : if (endptr == pszNoData + strlen(pszNoData))
2570 : {
2571 10 : return SetNoDataValue(fVal);
2572 : }
2573 : }
2574 : else
2575 : {
2576 107 : char *endptr = nullptr;
2577 107 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2578 214 : if (endptr == pszNoData + strlen(pszNoData) &&
2579 107 : GDALIsValueExactAs(dfVal, eDataType))
2580 : {
2581 106 : return SetNoDataValue(dfVal);
2582 : }
2583 : }
2584 5 : if (pbCannotBeExactlyRepresented)
2585 5 : *pbCannotBeExactlyRepresented = true;
2586 5 : return CE_Failure;
2587 : }
2588 :
2589 : /************************************************************************/
2590 : /* SetNoDataValue() */
2591 : /************************************************************************/
2592 :
2593 : /**
2594 : * \fn GDALRasterBand::SetNoDataValue(double)
2595 : * \brief Set the no data value for this band.
2596 : *
2597 : * Depending on drivers, changing the no data value may or may not have an
2598 : * effect on the pixel values of a raster that has just been created. It is
2599 : * thus advised to explicitly called Fill() if the intent is to initialize
2600 : * the raster to the nodata value.
2601 : * In any case, changing an existing no data value, when one already exists and
2602 : * the dataset exists or has been initialized, has no effect on the pixel whose
2603 : * value matched the previous nodata value.
2604 : *
2605 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2606 : * be represented by a double, use SetNoDataValueAsInt64() or
2607 : * SetNoDataValueAsUInt64() instead.
2608 : *
2609 : * To clear the nodata value, use DeleteNoDataValue().
2610 : *
2611 : * This method is the same as the C function GDALSetRasterNoDataValue().
2612 : *
2613 : * @param dfNoData the value to set.
2614 : *
2615 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2616 : * by the driver, CE_Failure is returned but no error message will have
2617 : * been emitted.
2618 : */
2619 :
2620 : /**/
2621 : /**/
2622 :
2623 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2624 :
2625 : {
2626 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2627 0 : ReportError(CE_Failure, CPLE_NotSupported,
2628 : "SetNoDataValue() not supported for this dataset.");
2629 :
2630 0 : return CE_Failure;
2631 : }
2632 :
2633 : /************************************************************************/
2634 : /* GDALSetRasterNoDataValue() */
2635 : /************************************************************************/
2636 :
2637 : /**
2638 : * \brief Set the no data value for this band.
2639 : *
2640 : * Depending on drivers, changing the no data value may or may not have an
2641 : * effect on the pixel values of a raster that has just been created. It is
2642 : * thus advised to explicitly called Fill() if the intent is to initialize
2643 : * the raster to the nodata value.
2644 : * In any case, changing an existing no data value, when one already exists and
2645 : * the dataset exists or has been initialized, has no effect on the pixel whose
2646 : * value matched the previous nodata value.
2647 : *
2648 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2649 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2650 : * GDALSetRasterNoDataValueAsUInt64() instead.
2651 : *
2652 : * @see GDALRasterBand::SetNoDataValue()
2653 : */
2654 :
2655 850 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2656 : double dfValue)
2657 :
2658 : {
2659 850 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2660 :
2661 850 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2662 850 : return poBand->SetNoDataValue(dfValue);
2663 : }
2664 :
2665 : /************************************************************************/
2666 : /* SetNoDataValueAsInt64() */
2667 : /************************************************************************/
2668 :
2669 : /**
2670 : * \brief Set the no data value for this band.
2671 : *
2672 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2673 : *
2674 : * Depending on drivers, changing the no data value may or may not have an
2675 : * effect on the pixel values of a raster that has just been created. It is
2676 : * thus advised to explicitly called Fill() if the intent is to initialize
2677 : * the raster to the nodata value.
2678 : * In ay case, changing an existing no data value, when one already exists and
2679 : * the dataset exists or has been initialized, has no effect on the pixel whose
2680 : * value matched the previous nodata value.
2681 : *
2682 : * To clear the nodata value, use DeleteNoDataValue().
2683 : *
2684 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2685 : *
2686 : * @param nNoDataValue the value to set.
2687 : *
2688 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2689 : * by the driver, CE_Failure is returned but no error message will have
2690 : * been emitted.
2691 : *
2692 : * @since GDAL 3.5
2693 : */
2694 :
2695 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2696 :
2697 : {
2698 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2699 0 : ReportError(CE_Failure, CPLE_NotSupported,
2700 : "SetNoDataValueAsInt64() not supported for this dataset.");
2701 :
2702 0 : return CE_Failure;
2703 : }
2704 :
2705 : /************************************************************************/
2706 : /* GDALSetRasterNoDataValueAsInt64() */
2707 : /************************************************************************/
2708 :
2709 : /**
2710 : * \brief Set the no data value for this band.
2711 : *
2712 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2713 : *
2714 : * Depending on drivers, changing the no data value may or may not have an
2715 : * effect on the pixel values of a raster that has just been created. It is
2716 : * thus advised to explicitly called Fill() if the intent is to initialize
2717 : * the raster to the nodata value.
2718 : * In ay case, changing an existing no data value, when one already exists and
2719 : * the dataset exists or has been initialized, has no effect on the pixel whose
2720 : * value matched the previous nodata value.
2721 : *
2722 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2723 : *
2724 : * @since GDAL 3.5
2725 : */
2726 :
2727 20 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2728 : int64_t nValue)
2729 :
2730 : {
2731 20 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2732 :
2733 20 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2734 20 : return poBand->SetNoDataValueAsInt64(nValue);
2735 : }
2736 :
2737 : /************************************************************************/
2738 : /* SetNoDataValueAsUInt64() */
2739 : /************************************************************************/
2740 :
2741 : /**
2742 : * \brief Set the no data value for this band.
2743 : *
2744 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2745 : *
2746 : * Depending on drivers, changing the no data value may or may not have an
2747 : * effect on the pixel values of a raster that has just been created. It is
2748 : * thus advised to explicitly called Fill() if the intent is to initialize
2749 : * the raster to the nodata value.
2750 : * In ay case, changing an existing no data value, when one already exists and
2751 : * the dataset exists or has been initialized, has no effect on the pixel whose
2752 : * value matched the previous nodata value.
2753 : *
2754 : * To clear the nodata value, use DeleteNoDataValue().
2755 : *
2756 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2757 : *
2758 : * @param nNoDataValue the value to set.
2759 : *
2760 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2761 : * by the driver, CE_Failure is returned but no error message will have
2762 : * been emitted.
2763 : *
2764 : * @since GDAL 3.5
2765 : */
2766 :
2767 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2768 :
2769 : {
2770 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2771 0 : ReportError(CE_Failure, CPLE_NotSupported,
2772 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2773 :
2774 0 : return CE_Failure;
2775 : }
2776 :
2777 : /************************************************************************/
2778 : /* GDALSetRasterNoDataValueAsUInt64() */
2779 : /************************************************************************/
2780 :
2781 : /**
2782 : * \brief Set the no data value for this band.
2783 : *
2784 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2785 : *
2786 : * Depending on drivers, changing the no data value may or may not have an
2787 : * effect on the pixel values of a raster that has just been created. It is
2788 : * thus advised to explicitly called Fill() if the intent is to initialize
2789 : * the raster to the nodata value.
2790 : * In ay case, changing an existing no data value, when one already exists and
2791 : * the dataset exists or has been initialized, has no effect on the pixel whose
2792 : * value matched the previous nodata value.
2793 : *
2794 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2795 : *
2796 : * @since GDAL 3.5
2797 : */
2798 :
2799 18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2800 : uint64_t nValue)
2801 :
2802 : {
2803 18 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2804 :
2805 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2806 18 : return poBand->SetNoDataValueAsUInt64(nValue);
2807 : }
2808 :
2809 : /************************************************************************/
2810 : /* DeleteNoDataValue() */
2811 : /************************************************************************/
2812 :
2813 : /**
2814 : * \brief Remove the no data value for this band.
2815 : *
2816 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2817 : *
2818 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2819 : * by the driver, CE_Failure is returned but no error message will have
2820 : * been emitted.
2821 : *
2822 : * @since GDAL 2.1
2823 : */
2824 :
2825 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2826 :
2827 : {
2828 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2829 0 : ReportError(CE_Failure, CPLE_NotSupported,
2830 : "DeleteNoDataValue() not supported for this dataset.");
2831 :
2832 0 : return CE_Failure;
2833 : }
2834 :
2835 : /************************************************************************/
2836 : /* GDALDeleteRasterNoDataValue() */
2837 : /************************************************************************/
2838 :
2839 : /**
2840 : * \brief Remove the no data value for this band.
2841 : *
2842 : * @see GDALRasterBand::DeleteNoDataValue()
2843 : *
2844 : * @since GDAL 2.1
2845 : */
2846 :
2847 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2848 :
2849 : {
2850 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2851 :
2852 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2853 53 : return poBand->DeleteNoDataValue();
2854 : }
2855 :
2856 : /************************************************************************/
2857 : /* GetMaximum() */
2858 : /************************************************************************/
2859 :
2860 : /**
2861 : * \brief Fetch the maximum value for this band.
2862 : *
2863 : * For file formats that don't know this intrinsically, the maximum supported
2864 : * value for the data type will generally be returned.
2865 : *
2866 : * This method is the same as the C function GDALGetRasterMaximum().
2867 : *
2868 : * @param pbSuccess pointer to a boolean to use to indicate if the
2869 : * returned value is a tight maximum or not. May be NULL (default).
2870 : *
2871 : * @return the maximum raster value (excluding no data pixels)
2872 : */
2873 :
2874 525 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2875 :
2876 : {
2877 525 : const char *pszValue = nullptr;
2878 :
2879 525 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2880 : {
2881 47 : if (pbSuccess != nullptr)
2882 42 : *pbSuccess = TRUE;
2883 :
2884 47 : return CPLAtofM(pszValue);
2885 : }
2886 :
2887 478 : if (pbSuccess != nullptr)
2888 474 : *pbSuccess = FALSE;
2889 :
2890 478 : switch (eDataType)
2891 : {
2892 327 : case GDT_Byte:
2893 : {
2894 327 : EnablePixelTypeSignedByteWarning(false);
2895 : const char *pszPixelType =
2896 327 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2897 327 : EnablePixelTypeSignedByteWarning(true);
2898 327 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2899 0 : return 127;
2900 :
2901 327 : return 255;
2902 : }
2903 :
2904 1 : case GDT_Int8:
2905 1 : return 127;
2906 :
2907 21 : case GDT_UInt16:
2908 21 : return 65535;
2909 :
2910 24 : case GDT_Int16:
2911 : case GDT_CInt16:
2912 24 : return 32767;
2913 :
2914 39 : case GDT_Int32:
2915 : case GDT_CInt32:
2916 39 : return 2147483647.0;
2917 :
2918 12 : case GDT_UInt32:
2919 12 : return 4294967295.0;
2920 :
2921 1 : case GDT_Int64:
2922 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2923 :
2924 1 : case GDT_UInt64:
2925 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2926 :
2927 0 : case GDT_Float16:
2928 : case GDT_CFloat16:
2929 0 : return 65504.0;
2930 :
2931 30 : case GDT_Float32:
2932 : case GDT_CFloat32:
2933 30 : return 4294967295.0; // Not actually accurate.
2934 :
2935 22 : case GDT_Float64:
2936 : case GDT_CFloat64:
2937 22 : return 4294967295.0; // Not actually accurate.
2938 :
2939 0 : case GDT_Unknown:
2940 : case GDT_TypeCount:
2941 0 : break;
2942 : }
2943 0 : return 4294967295.0; // Not actually accurate.
2944 : }
2945 :
2946 : /************************************************************************/
2947 : /* GDALGetRasterMaximum() */
2948 : /************************************************************************/
2949 :
2950 : /**
2951 : * \brief Fetch the maximum value for this band.
2952 : *
2953 : * @see GDALRasterBand::GetMaximum()
2954 : */
2955 :
2956 289 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2957 :
2958 : {
2959 289 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2960 :
2961 289 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2962 289 : return poBand->GetMaximum(pbSuccess);
2963 : }
2964 :
2965 : /************************************************************************/
2966 : /* GetMinimum() */
2967 : /************************************************************************/
2968 :
2969 : /**
2970 : * \brief Fetch the minimum value for this band.
2971 : *
2972 : * For file formats that don't know this intrinsically, the minimum supported
2973 : * value for the data type will generally be returned.
2974 : *
2975 : * This method is the same as the C function GDALGetRasterMinimum().
2976 : *
2977 : * @param pbSuccess pointer to a boolean to use to indicate if the
2978 : * returned value is a tight minimum or not. May be NULL (default).
2979 : *
2980 : * @return the minimum raster value (excluding no data pixels)
2981 : */
2982 :
2983 533 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2984 :
2985 : {
2986 533 : const char *pszValue = nullptr;
2987 :
2988 533 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2989 : {
2990 52 : if (pbSuccess != nullptr)
2991 47 : *pbSuccess = TRUE;
2992 :
2993 52 : return CPLAtofM(pszValue);
2994 : }
2995 :
2996 481 : if (pbSuccess != nullptr)
2997 477 : *pbSuccess = FALSE;
2998 :
2999 481 : switch (eDataType)
3000 : {
3001 330 : case GDT_Byte:
3002 : {
3003 330 : EnablePixelTypeSignedByteWarning(false);
3004 : const char *pszPixelType =
3005 330 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3006 330 : EnablePixelTypeSignedByteWarning(true);
3007 330 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3008 0 : return -128;
3009 :
3010 330 : return 0;
3011 : }
3012 :
3013 1 : case GDT_Int8:
3014 1 : return -128;
3015 : break;
3016 :
3017 21 : case GDT_UInt16:
3018 21 : return 0;
3019 :
3020 24 : case GDT_Int16:
3021 : case GDT_CInt16:
3022 24 : return -32768;
3023 :
3024 39 : case GDT_Int32:
3025 : case GDT_CInt32:
3026 39 : return -2147483648.0;
3027 :
3028 12 : case GDT_UInt32:
3029 12 : return 0;
3030 :
3031 1 : case GDT_Int64:
3032 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3033 :
3034 1 : case GDT_UInt64:
3035 1 : return 0;
3036 :
3037 0 : case GDT_Float16:
3038 : case GDT_CFloat16:
3039 0 : return -65504.0;
3040 :
3041 30 : case GDT_Float32:
3042 : case GDT_CFloat32:
3043 30 : return -4294967295.0; // Not actually accurate.
3044 :
3045 22 : case GDT_Float64:
3046 : case GDT_CFloat64:
3047 22 : return -4294967295.0; // Not actually accurate.
3048 :
3049 0 : case GDT_Unknown:
3050 : case GDT_TypeCount:
3051 0 : break;
3052 : }
3053 0 : return -4294967295.0; // Not actually accurate.
3054 : }
3055 :
3056 : /************************************************************************/
3057 : /* GDALGetRasterMinimum() */
3058 : /************************************************************************/
3059 :
3060 : /**
3061 : * \brief Fetch the minimum value for this band.
3062 : *
3063 : * @see GDALRasterBand::GetMinimum()
3064 : */
3065 :
3066 299 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3067 :
3068 : {
3069 299 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3070 :
3071 299 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3072 299 : return poBand->GetMinimum(pbSuccess);
3073 : }
3074 :
3075 : /************************************************************************/
3076 : /* GetColorInterpretation() */
3077 : /************************************************************************/
3078 :
3079 : /**
3080 : * \brief How should this band be interpreted as color?
3081 : *
3082 : * GCI_Undefined is returned when the format doesn't know anything
3083 : * about the color interpretation.
3084 : *
3085 : * This method is the same as the C function
3086 : * GDALGetRasterColorInterpretation().
3087 : *
3088 : * @return color interpretation value for band.
3089 : */
3090 :
3091 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3092 :
3093 : {
3094 163 : return GCI_Undefined;
3095 : }
3096 :
3097 : /************************************************************************/
3098 : /* GDALGetRasterColorInterpretation() */
3099 : /************************************************************************/
3100 :
3101 : /**
3102 : * \brief How should this band be interpreted as color?
3103 : *
3104 : * @see GDALRasterBand::GetColorInterpretation()
3105 : */
3106 :
3107 : GDALColorInterp CPL_STDCALL
3108 5456 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3109 :
3110 : {
3111 5456 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3112 :
3113 5456 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3114 5456 : return poBand->GetColorInterpretation();
3115 : }
3116 :
3117 : /************************************************************************/
3118 : /* SetColorInterpretation() */
3119 : /************************************************************************/
3120 :
3121 : /**
3122 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3123 : * \brief Set color interpretation of a band.
3124 : *
3125 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3126 : *
3127 : * @param eColorInterp the new color interpretation to apply to this band.
3128 : *
3129 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3130 : */
3131 :
3132 : /**/
3133 : /**/
3134 :
3135 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3136 :
3137 : {
3138 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3139 3 : ReportError(CE_Failure, CPLE_NotSupported,
3140 : "SetColorInterpretation() not supported for this dataset.");
3141 3 : return CE_Failure;
3142 : }
3143 :
3144 : /************************************************************************/
3145 : /* GDALSetRasterColorInterpretation() */
3146 : /************************************************************************/
3147 :
3148 : /**
3149 : * \brief Set color interpretation of a band.
3150 : *
3151 : * @see GDALRasterBand::SetColorInterpretation()
3152 : */
3153 :
3154 1831 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3155 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3156 :
3157 : {
3158 1831 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3159 :
3160 1831 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3161 1831 : return poBand->SetColorInterpretation(eColorInterp);
3162 : }
3163 :
3164 : /************************************************************************/
3165 : /* GetColorTable() */
3166 : /************************************************************************/
3167 :
3168 : /**
3169 : * \brief Fetch the color table associated with band.
3170 : *
3171 : * If there is no associated color table, the return result is NULL. The
3172 : * returned color table remains owned by the GDALRasterBand, and can't
3173 : * be depended on for long, nor should it ever be modified by the caller.
3174 : *
3175 : * This method is the same as the C function GDALGetRasterColorTable().
3176 : *
3177 : * @return internal color table, or NULL.
3178 : */
3179 :
3180 231 : GDALColorTable *GDALRasterBand::GetColorTable()
3181 :
3182 : {
3183 231 : return nullptr;
3184 : }
3185 :
3186 : /************************************************************************/
3187 : /* GDALGetRasterColorTable() */
3188 : /************************************************************************/
3189 :
3190 : /**
3191 : * \brief Fetch the color table associated with band.
3192 : *
3193 : * @see GDALRasterBand::GetColorTable()
3194 : */
3195 :
3196 1893 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3197 :
3198 : {
3199 1893 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3200 :
3201 1893 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3202 1893 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3203 : }
3204 :
3205 : /************************************************************************/
3206 : /* SetColorTable() */
3207 : /************************************************************************/
3208 :
3209 : /**
3210 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3211 : * \brief Set the raster color table.
3212 : *
3213 : * The driver will make a copy of all desired data in the colortable. It
3214 : * remains owned by the caller after the call.
3215 : *
3216 : * This method is the same as the C function GDALSetRasterColorTable().
3217 : *
3218 : * @param poCT the color table to apply. This may be NULL to clear the color
3219 : * table (where supported).
3220 : *
3221 : * @return CE_None on success, or CE_Failure on failure. If the action is
3222 : * unsupported by the driver, a value of CE_Failure is returned, but no
3223 : * error is issued.
3224 : */
3225 :
3226 : /**/
3227 : /**/
3228 :
3229 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3230 :
3231 : {
3232 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3233 0 : ReportError(CE_Failure, CPLE_NotSupported,
3234 : "SetColorTable() not supported for this dataset.");
3235 0 : return CE_Failure;
3236 : }
3237 :
3238 : /************************************************************************/
3239 : /* GDALSetRasterColorTable() */
3240 : /************************************************************************/
3241 :
3242 : /**
3243 : * \brief Set the raster color table.
3244 : *
3245 : * @see GDALRasterBand::SetColorTable()
3246 : */
3247 :
3248 78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3249 : GDALColorTableH hCT)
3250 :
3251 : {
3252 78 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3253 :
3254 78 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3255 78 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3256 : }
3257 :
3258 : /************************************************************************/
3259 : /* HasArbitraryOverviews() */
3260 : /************************************************************************/
3261 :
3262 : /**
3263 : * \brief Check for arbitrary overviews.
3264 : *
3265 : * This returns TRUE if the underlying datastore can compute arbitrary
3266 : * overviews efficiently, such as is the case with OGDI over a network.
3267 : * Datastores with arbitrary overviews don't generally have any fixed
3268 : * overviews, but the RasterIO() method can be used in downsampling mode
3269 : * to get overview data efficiently.
3270 : *
3271 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3272 : *
3273 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3274 : * FALSE.
3275 : */
3276 :
3277 260 : int GDALRasterBand::HasArbitraryOverviews()
3278 :
3279 : {
3280 260 : return FALSE;
3281 : }
3282 :
3283 : /************************************************************************/
3284 : /* GDALHasArbitraryOverviews() */
3285 : /************************************************************************/
3286 :
3287 : /**
3288 : * \brief Check for arbitrary overviews.
3289 : *
3290 : * @see GDALRasterBand::HasArbitraryOverviews()
3291 : */
3292 :
3293 181 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3294 :
3295 : {
3296 181 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3297 :
3298 181 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3299 181 : return poBand->HasArbitraryOverviews();
3300 : }
3301 :
3302 : /************************************************************************/
3303 : /* GetOverviewCount() */
3304 : /************************************************************************/
3305 :
3306 : /**
3307 : * \brief Return the number of overview layers available.
3308 : *
3309 : * This method is the same as the C function GDALGetOverviewCount().
3310 : *
3311 : * @return overview count, zero if none.
3312 : */
3313 :
3314 1065940 : int GDALRasterBand::GetOverviewCount()
3315 :
3316 : {
3317 1722450 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3318 656515 : poDS->AreOverviewsEnabled())
3319 656515 : return poDS->oOvManager.GetOverviewCount(nBand);
3320 :
3321 409424 : return 0;
3322 : }
3323 :
3324 : /************************************************************************/
3325 : /* GDALGetOverviewCount() */
3326 : /************************************************************************/
3327 :
3328 : /**
3329 : * \brief Return the number of overview layers available.
3330 : *
3331 : * @see GDALRasterBand::GetOverviewCount()
3332 : */
3333 :
3334 3283 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3335 :
3336 : {
3337 3283 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3338 :
3339 3283 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3340 3283 : return poBand->GetOverviewCount();
3341 : }
3342 :
3343 : /************************************************************************/
3344 : /* GetOverview() */
3345 : /************************************************************************/
3346 :
3347 : /**
3348 : * \brief Fetch overview raster band object.
3349 : *
3350 : * This method is the same as the C function GDALGetOverview().
3351 : *
3352 : * @param i overview index between 0 and GetOverviewCount()-1.
3353 : *
3354 : * @return overview GDALRasterBand.
3355 : */
3356 :
3357 844 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3358 :
3359 : {
3360 1633 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3361 789 : poDS->AreOverviewsEnabled())
3362 789 : return poDS->oOvManager.GetOverview(nBand, i);
3363 :
3364 55 : return nullptr;
3365 : }
3366 :
3367 : /************************************************************************/
3368 : /* GDALGetOverview() */
3369 : /************************************************************************/
3370 :
3371 : /**
3372 : * \brief Fetch overview raster band object.
3373 : *
3374 : * @see GDALRasterBand::GetOverview()
3375 : */
3376 :
3377 5654 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3378 :
3379 : {
3380 5654 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3381 :
3382 5654 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3383 5654 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3384 : }
3385 :
3386 : /************************************************************************/
3387 : /* GetRasterSampleOverview() */
3388 : /************************************************************************/
3389 :
3390 : /**
3391 : * \brief Fetch best sampling overview.
3392 : *
3393 : * Returns the most reduced overview of the given band that still satisfies
3394 : * the desired number of samples. This function can be used with zero
3395 : * as the number of desired samples to fetch the most reduced overview.
3396 : * The same band as was passed in will be returned if it has not overviews,
3397 : * or if none of the overviews have enough samples.
3398 : *
3399 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3400 : * and GDALGetRasterSampleOverviewEx().
3401 : *
3402 : * @param nDesiredSamples the returned band will have at least this many
3403 : * pixels.
3404 : *
3405 : * @return optimal overview or the band itself.
3406 : */
3407 :
3408 : GDALRasterBand *
3409 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3410 :
3411 : {
3412 2006 : GDALRasterBand *poBestBand = this;
3413 :
3414 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3415 :
3416 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3417 : {
3418 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3419 :
3420 2017 : if (poOBand == nullptr)
3421 0 : continue;
3422 :
3423 : const double dfOSamples =
3424 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3425 :
3426 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3427 : {
3428 2014 : dfBestSamples = dfOSamples;
3429 2014 : poBestBand = poOBand;
3430 : }
3431 : }
3432 :
3433 2006 : return poBestBand;
3434 : }
3435 :
3436 : /************************************************************************/
3437 : /* GDALGetRasterSampleOverview() */
3438 : /************************************************************************/
3439 :
3440 : /**
3441 : * \brief Fetch best sampling overview.
3442 : *
3443 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3444 : * billion samples.
3445 : *
3446 : * @see GDALRasterBand::GetRasterSampleOverview()
3447 : * @see GDALGetRasterSampleOverviewEx()
3448 : */
3449 :
3450 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3451 : int nDesiredSamples)
3452 :
3453 : {
3454 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3455 :
3456 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3457 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3458 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3459 : }
3460 :
3461 : /************************************************************************/
3462 : /* GDALGetRasterSampleOverviewEx() */
3463 : /************************************************************************/
3464 :
3465 : /**
3466 : * \brief Fetch best sampling overview.
3467 : *
3468 : * @see GDALRasterBand::GetRasterSampleOverview()
3469 : * @since GDAL 2.0
3470 : */
3471 :
3472 : GDALRasterBandH CPL_STDCALL
3473 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3474 :
3475 : {
3476 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3477 :
3478 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3479 2000 : return GDALRasterBand::ToHandle(
3480 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3481 : }
3482 :
3483 : /************************************************************************/
3484 : /* BuildOverviews() */
3485 : /************************************************************************/
3486 :
3487 : /**
3488 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3489 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3490 : *
3491 : * If the operation is unsupported for the indicated dataset, then
3492 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3493 : * CPLE_NotSupported.
3494 : *
3495 : * WARNING: Most formats don't support per-band overview computation, but
3496 : * require that overviews are computed for all bands of a dataset, using
3497 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3498 : * is the HFA driver which supports this method.
3499 : *
3500 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3501 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3502 : * applied.
3503 : * @param nOverviews number of overviews to build.
3504 : * @param panOverviewList the list of overview decimation factors to build.
3505 : * @param pfnProgress a function to call to report progress, or NULL.
3506 : * @param pProgressData application data to pass to the progress function.
3507 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3508 : * key=value pairs, or NULL
3509 : *
3510 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3511 : */
3512 :
3513 : /**/
3514 : /**/
3515 :
3516 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3517 : int /*nOverviews*/,
3518 : const int * /*panOverviewList*/,
3519 : GDALProgressFunc /*pfnProgress*/,
3520 : void * /*pProgressData*/,
3521 : CSLConstList /* papszOptions */)
3522 :
3523 : {
3524 0 : ReportError(CE_Failure, CPLE_NotSupported,
3525 : "BuildOverviews() not supported for this dataset.");
3526 :
3527 0 : return (CE_Failure);
3528 : }
3529 :
3530 : /************************************************************************/
3531 : /* GetOffset() */
3532 : /************************************************************************/
3533 :
3534 : /**
3535 : * \brief Fetch the raster value offset.
3536 : *
3537 : * This value (in combination with the GetScale() value) can be used to
3538 : * transform raw pixel values into the units returned by GetUnitType().
3539 : * For example this might be used to store elevations in GUInt16 bands
3540 : * with a precision of 0.1, and starting from -100.
3541 : *
3542 : * Units value = (raw value * scale) + offset
3543 : *
3544 : * Note that applying scale and offset is of the responsibility of the user,
3545 : * and is not done by methods such as RasterIO() or ReadBlock().
3546 : *
3547 : * For file formats that don't know this intrinsically a value of zero
3548 : * is returned.
3549 : *
3550 : * This method is the same as the C function GDALGetRasterOffset().
3551 : *
3552 : * @param pbSuccess pointer to a boolean to use to indicate if the
3553 : * returned value is meaningful or not. May be NULL (default).
3554 : *
3555 : * @return the raster offset.
3556 : */
3557 :
3558 460 : double GDALRasterBand::GetOffset(int *pbSuccess)
3559 :
3560 : {
3561 460 : if (pbSuccess != nullptr)
3562 351 : *pbSuccess = FALSE;
3563 :
3564 460 : return 0.0;
3565 : }
3566 :
3567 : /************************************************************************/
3568 : /* GDALGetRasterOffset() */
3569 : /************************************************************************/
3570 :
3571 : /**
3572 : * \brief Fetch the raster value offset.
3573 : *
3574 : * @see GDALRasterBand::GetOffset()
3575 : */
3576 :
3577 385 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3578 :
3579 : {
3580 385 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3581 :
3582 385 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3583 385 : return poBand->GetOffset(pbSuccess);
3584 : }
3585 :
3586 : /************************************************************************/
3587 : /* SetOffset() */
3588 : /************************************************************************/
3589 :
3590 : /**
3591 : * \fn GDALRasterBand::SetOffset(double)
3592 : * \brief Set scaling offset.
3593 : *
3594 : * Very few formats implement this method. When not implemented it will
3595 : * issue a CPLE_NotSupported error and return CE_Failure.
3596 : *
3597 : * This method is the same as the C function GDALSetRasterOffset().
3598 : *
3599 : * @param dfNewOffset the new offset.
3600 : *
3601 : * @return CE_None or success or CE_Failure on failure.
3602 : */
3603 :
3604 : /**/
3605 : /**/
3606 :
3607 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3608 : {
3609 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3610 0 : ReportError(CE_Failure, CPLE_NotSupported,
3611 : "SetOffset() not supported on this raster band.");
3612 :
3613 0 : return CE_Failure;
3614 : }
3615 :
3616 : /************************************************************************/
3617 : /* GDALSetRasterOffset() */
3618 : /************************************************************************/
3619 :
3620 : /**
3621 : * \brief Set scaling offset.
3622 : *
3623 : * @see GDALRasterBand::SetOffset()
3624 : */
3625 :
3626 75 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3627 : double dfNewOffset)
3628 :
3629 : {
3630 75 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3631 :
3632 75 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3633 75 : return poBand->SetOffset(dfNewOffset);
3634 : }
3635 :
3636 : /************************************************************************/
3637 : /* GetScale() */
3638 : /************************************************************************/
3639 :
3640 : /**
3641 : * \brief Fetch the raster value scale.
3642 : *
3643 : * This value (in combination with the GetOffset() value) can be used to
3644 : * transform raw pixel values into the units returned by GetUnitType().
3645 : * For example this might be used to store elevations in GUInt16 bands
3646 : * with a precision of 0.1, and starting from -100.
3647 : *
3648 : * Units value = (raw value * scale) + offset
3649 : *
3650 : * Note that applying scale and offset is of the responsibility of the user,
3651 : * and is not done by methods such as RasterIO() or ReadBlock().
3652 : *
3653 : * For file formats that don't know this intrinsically a value of one
3654 : * is returned.
3655 : *
3656 : * This method is the same as the C function GDALGetRasterScale().
3657 : *
3658 : * @param pbSuccess pointer to a boolean to use to indicate if the
3659 : * returned value is meaningful or not. May be NULL (default).
3660 : *
3661 : * @return the raster scale.
3662 : */
3663 :
3664 460 : double GDALRasterBand::GetScale(int *pbSuccess)
3665 :
3666 : {
3667 460 : if (pbSuccess != nullptr)
3668 351 : *pbSuccess = FALSE;
3669 :
3670 460 : return 1.0;
3671 : }
3672 :
3673 : /************************************************************************/
3674 : /* GDALGetRasterScale() */
3675 : /************************************************************************/
3676 :
3677 : /**
3678 : * \brief Fetch the raster value scale.
3679 : *
3680 : * @see GDALRasterBand::GetScale()
3681 : */
3682 :
3683 383 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3684 :
3685 : {
3686 383 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3687 :
3688 383 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3689 383 : return poBand->GetScale(pbSuccess);
3690 : }
3691 :
3692 : /************************************************************************/
3693 : /* SetScale() */
3694 : /************************************************************************/
3695 :
3696 : /**
3697 : * \fn GDALRasterBand::SetScale(double)
3698 : * \brief Set scaling ratio.
3699 : *
3700 : * Very few formats implement this method. When not implemented it will
3701 : * issue a CPLE_NotSupported error and return CE_Failure.
3702 : *
3703 : * This method is the same as the C function GDALSetRasterScale().
3704 : *
3705 : * @param dfNewScale the new scale.
3706 : *
3707 : * @return CE_None or success or CE_Failure on failure.
3708 : */
3709 :
3710 : /**/
3711 : /**/
3712 :
3713 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3714 :
3715 : {
3716 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3717 0 : ReportError(CE_Failure, CPLE_NotSupported,
3718 : "SetScale() not supported on this raster band.");
3719 :
3720 0 : return CE_Failure;
3721 : }
3722 :
3723 : /************************************************************************/
3724 : /* GDALSetRasterScale() */
3725 : /************************************************************************/
3726 :
3727 : /**
3728 : * \brief Set scaling ratio.
3729 : *
3730 : * @see GDALRasterBand::SetScale()
3731 : */
3732 :
3733 76 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3734 :
3735 : {
3736 76 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3737 :
3738 76 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3739 76 : return poBand->SetScale(dfNewOffset);
3740 : }
3741 :
3742 : /************************************************************************/
3743 : /* GetUnitType() */
3744 : /************************************************************************/
3745 :
3746 : /**
3747 : * \brief Return raster unit type.
3748 : *
3749 : * Return a name for the units of this raster's values. For instance, it
3750 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3751 : * units are available, a value of "" will be returned. The returned string
3752 : * should not be modified, nor freed by the calling application.
3753 : *
3754 : * This method is the same as the C function GDALGetRasterUnitType().
3755 : *
3756 : * @return unit name string.
3757 : */
3758 :
3759 183 : const char *GDALRasterBand::GetUnitType()
3760 :
3761 : {
3762 183 : return "";
3763 : }
3764 :
3765 : /************************************************************************/
3766 : /* GDALGetRasterUnitType() */
3767 : /************************************************************************/
3768 :
3769 : /**
3770 : * \brief Return raster unit type.
3771 : *
3772 : * @see GDALRasterBand::GetUnitType()
3773 : */
3774 :
3775 1427 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3776 :
3777 : {
3778 1427 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3779 :
3780 1427 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3781 1427 : return poBand->GetUnitType();
3782 : }
3783 :
3784 : /************************************************************************/
3785 : /* SetUnitType() */
3786 : /************************************************************************/
3787 :
3788 : /**
3789 : * \fn GDALRasterBand::SetUnitType(const char*)
3790 : * \brief Set unit type.
3791 : *
3792 : * Set the unit type for a raster band. Values should be one of
3793 : * "" (the default indicating it is unknown), "m" indicating meters,
3794 : * or "ft" indicating feet, though other nonstandard values are allowed.
3795 : *
3796 : * This method is the same as the C function GDALSetRasterUnitType().
3797 : *
3798 : * @param pszNewValue the new unit type value.
3799 : *
3800 : * @return CE_None on success or CE_Failure if not successful, or
3801 : * unsupported.
3802 : */
3803 :
3804 : /**/
3805 : /**/
3806 :
3807 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3808 :
3809 : {
3810 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3811 0 : ReportError(CE_Failure, CPLE_NotSupported,
3812 : "SetUnitType() not supported on this raster band.");
3813 0 : return CE_Failure;
3814 : }
3815 :
3816 : /************************************************************************/
3817 : /* GDALSetRasterUnitType() */
3818 : /************************************************************************/
3819 :
3820 : /**
3821 : * \brief Set unit type.
3822 : *
3823 : * @see GDALRasterBand::SetUnitType()
3824 : *
3825 : * @since GDAL 1.8.0
3826 : */
3827 :
3828 75 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3829 : const char *pszNewValue)
3830 :
3831 : {
3832 75 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3833 :
3834 75 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3835 75 : return poBand->SetUnitType(pszNewValue);
3836 : }
3837 :
3838 : /************************************************************************/
3839 : /* GetXSize() */
3840 : /************************************************************************/
3841 :
3842 : /**
3843 : * \brief Fetch XSize of raster.
3844 : *
3845 : * This method is the same as the C function GDALGetRasterBandXSize().
3846 : *
3847 : * @return the width in pixels of this band.
3848 : */
3849 :
3850 8445040 : int GDALRasterBand::GetXSize() const
3851 :
3852 : {
3853 8445040 : return nRasterXSize;
3854 : }
3855 :
3856 : /************************************************************************/
3857 : /* GDALGetRasterBandXSize() */
3858 : /************************************************************************/
3859 :
3860 : /**
3861 : * \brief Fetch XSize of raster.
3862 : *
3863 : * @see GDALRasterBand::GetXSize()
3864 : */
3865 :
3866 57595 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3867 :
3868 : {
3869 57595 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3870 :
3871 57595 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3872 57595 : return poBand->GetXSize();
3873 : }
3874 :
3875 : /************************************************************************/
3876 : /* GetYSize() */
3877 : /************************************************************************/
3878 :
3879 : /**
3880 : * \brief Fetch YSize of raster.
3881 : *
3882 : * This method is the same as the C function GDALGetRasterBandYSize().
3883 : *
3884 : * @return the height in pixels of this band.
3885 : */
3886 :
3887 4665280 : int GDALRasterBand::GetYSize() const
3888 :
3889 : {
3890 4665280 : return nRasterYSize;
3891 : }
3892 :
3893 : /************************************************************************/
3894 : /* GDALGetRasterBandYSize() */
3895 : /************************************************************************/
3896 :
3897 : /**
3898 : * \brief Fetch YSize of raster.
3899 : *
3900 : * @see GDALRasterBand::GetYSize()
3901 : */
3902 :
3903 56454 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3904 :
3905 : {
3906 56454 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3907 :
3908 56454 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3909 56454 : return poBand->GetYSize();
3910 : }
3911 :
3912 : /************************************************************************/
3913 : /* GetBand() */
3914 : /************************************************************************/
3915 :
3916 : /**
3917 : * \brief Fetch the band number.
3918 : *
3919 : * This method returns the band that this GDALRasterBand objects represents
3920 : * within its dataset. This method may return a value of 0 to indicate
3921 : * GDALRasterBand objects without an apparently relationship to a dataset,
3922 : * such as GDALRasterBands serving as overviews.
3923 : *
3924 : * This method is the same as the C function GDALGetBandNumber().
3925 : *
3926 : * @return band number (1+) or 0 if the band number isn't known.
3927 : */
3928 :
3929 151775 : int GDALRasterBand::GetBand() const
3930 :
3931 : {
3932 151775 : return nBand;
3933 : }
3934 :
3935 : /************************************************************************/
3936 : /* GDALGetBandNumber() */
3937 : /************************************************************************/
3938 :
3939 : /**
3940 : * \brief Fetch the band number.
3941 : *
3942 : * @see GDALRasterBand::GetBand()
3943 : */
3944 :
3945 202 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3946 :
3947 : {
3948 202 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3949 :
3950 202 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3951 202 : return poBand->GetBand();
3952 : }
3953 :
3954 : /************************************************************************/
3955 : /* GetDataset() */
3956 : /************************************************************************/
3957 :
3958 : /**
3959 : * \brief Fetch the owning dataset handle.
3960 : *
3961 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3962 : * such as overviews or other "freestanding" bands.
3963 : *
3964 : * This method is the same as the C function GDALGetBandDataset().
3965 : *
3966 : * @return the pointer to the GDALDataset to which this band belongs, or
3967 : * NULL if this cannot be determined.
3968 : */
3969 :
3970 5301230 : GDALDataset *GDALRasterBand::GetDataset() const
3971 :
3972 : {
3973 5301230 : return poDS;
3974 : }
3975 :
3976 : /************************************************************************/
3977 : /* GDALGetBandDataset() */
3978 : /************************************************************************/
3979 :
3980 : /**
3981 : * \brief Fetch the owning dataset handle.
3982 : *
3983 : * @see GDALRasterBand::GetDataset()
3984 : */
3985 :
3986 445 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3987 :
3988 : {
3989 445 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3990 :
3991 445 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3992 445 : return GDALDataset::ToHandle(poBand->GetDataset());
3993 : }
3994 :
3995 : /************************************************************************/
3996 : /* ComputeFloat16NoDataValue() */
3997 : /************************************************************************/
3998 :
3999 2231 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4000 : double dfNoDataValue,
4001 : int &bGotNoDataValue,
4002 : GFloat16 &fNoDataValue,
4003 : bool &bGotFloat16NoDataValue)
4004 : {
4005 2231 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4006 : {
4007 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4008 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4009 : {
4010 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4011 0 : bGotFloat16NoDataValue = true;
4012 0 : bGotNoDataValue = false;
4013 : }
4014 : }
4015 2231 : }
4016 :
4017 : /************************************************************************/
4018 : /* ComputeFloatNoDataValue() */
4019 : /************************************************************************/
4020 :
4021 2231 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4022 : double dfNoDataValue,
4023 : int &bGotNoDataValue,
4024 : float &fNoDataValue,
4025 : bool &bGotFloatNoDataValue)
4026 : {
4027 2231 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4028 : {
4029 84 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4030 84 : if (GDALIsValueInRange<float>(dfNoDataValue))
4031 : {
4032 84 : fNoDataValue = static_cast<float>(dfNoDataValue);
4033 84 : bGotFloatNoDataValue = true;
4034 84 : bGotNoDataValue = false;
4035 : }
4036 : }
4037 2231 : }
4038 :
4039 : /************************************************************************/
4040 : /* struct GDALNoDataValues */
4041 : /************************************************************************/
4042 :
4043 : /**
4044 : * \brief No-data-values for all types
4045 : *
4046 : * The functions below pass various no-data-values around. To avoid
4047 : * long argument lists, this struct collects the no-data-values for
4048 : * all types into a single, convenient place.
4049 : **/
4050 :
4051 : struct GDALNoDataValues
4052 : {
4053 : int bGotNoDataValue;
4054 : double dfNoDataValue;
4055 :
4056 : bool bGotInt64NoDataValue;
4057 : int64_t nInt64NoDataValue;
4058 :
4059 : bool bGotUInt64NoDataValue;
4060 : uint64_t nUInt64NoDataValue;
4061 :
4062 : bool bGotFloatNoDataValue;
4063 : float fNoDataValue;
4064 :
4065 : bool bGotFloat16NoDataValue;
4066 : GFloat16 hfNoDataValue;
4067 :
4068 2275 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4069 2275 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4070 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4071 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4072 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4073 2275 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4074 : {
4075 2275 : if (eDataType == GDT_Int64)
4076 : {
4077 28 : int nGot = false;
4078 28 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4079 28 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4080 28 : if (bGotInt64NoDataValue)
4081 : {
4082 3 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4083 3 : bGotNoDataValue =
4084 3 : nInt64NoDataValue <=
4085 6 : std::numeric_limits<int64_t>::max() - 1024 &&
4086 3 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4087 : }
4088 : else
4089 25 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4090 : }
4091 2247 : else if (eDataType == GDT_UInt64)
4092 : {
4093 16 : int nGot = false;
4094 16 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4095 16 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4096 16 : if (bGotUInt64NoDataValue)
4097 : {
4098 3 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4099 3 : bGotNoDataValue =
4100 3 : nUInt64NoDataValue <=
4101 6 : std::numeric_limits<uint64_t>::max() - 2048 &&
4102 3 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4103 : }
4104 : else
4105 13 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4106 : }
4107 : else
4108 : {
4109 2231 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4110 2231 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4111 :
4112 2231 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4113 2231 : fNoDataValue, bGotFloatNoDataValue);
4114 :
4115 2231 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4116 2231 : hfNoDataValue, bGotFloat16NoDataValue);
4117 : }
4118 2275 : }
4119 : };
4120 :
4121 : /************************************************************************/
4122 : /* ARE_REAL_EQUAL() */
4123 : /************************************************************************/
4124 :
4125 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4126 : {
4127 : using std::abs;
4128 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4129 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4130 0 : abs(dfVal1 + dfVal2) * ulp;
4131 : }
4132 :
4133 : /************************************************************************/
4134 : /* GetHistogram() */
4135 : /************************************************************************/
4136 :
4137 : /**
4138 : * \brief Compute raster histogram.
4139 : *
4140 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4141 : *
4142 : * For example to compute a simple 256 entry histogram of eight bit data,
4143 : * the following would be suitable. The unusual bounds are to ensure that
4144 : * bucket boundaries don't fall right on integer values causing possible errors
4145 : * due to rounding after scaling.
4146 : \code{.cpp}
4147 : GUIntBig anHistogram[256];
4148 :
4149 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4150 : GDALDummyProgress, nullptr );
4151 : \endcode
4152 : *
4153 : * Note that setting bApproxOK will generally result in a subsampling of the
4154 : * file, and will utilize overviews if available. It should generally
4155 : * produce a representative histogram for the data that is suitable for use
4156 : * in generating histogram based luts for instance. Generally bApproxOK is
4157 : * much faster than an exactly computed histogram.
4158 : *
4159 : * This method is the same as the C functions GDALGetRasterHistogram() and
4160 : * GDALGetRasterHistogramEx().
4161 : *
4162 : * @param dfMin the lower bound of the histogram.
4163 : * @param dfMax the upper bound of the histogram.
4164 : * @param nBuckets the number of buckets in panHistogram.
4165 : * @param panHistogram array into which the histogram totals are placed.
4166 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4167 : * mapped into panHistogram[0], and values above will be mapped into
4168 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4169 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4170 : * @param pfnProgress function to report progress to completion.
4171 : * @param pProgressData application data to pass to pfnProgress.
4172 : *
4173 : * @return CE_None on success, or CE_Failure if something goes wrong.
4174 : */
4175 :
4176 42 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4177 : GUIntBig *panHistogram,
4178 : int bIncludeOutOfRange, int bApproxOK,
4179 : GDALProgressFunc pfnProgress,
4180 : void *pProgressData)
4181 :
4182 : {
4183 42 : CPLAssert(nullptr != panHistogram);
4184 :
4185 42 : if (pfnProgress == nullptr)
4186 29 : pfnProgress = GDALDummyProgress;
4187 :
4188 : /* -------------------------------------------------------------------- */
4189 : /* If we have overviews, use them for the histogram. */
4190 : /* -------------------------------------------------------------------- */
4191 42 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4192 : {
4193 : // FIXME: should we use the most reduced overview here or use some
4194 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4195 : // does?
4196 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4197 :
4198 0 : if (poBestOverview != this)
4199 : {
4200 0 : return poBestOverview->GetHistogram(
4201 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4202 0 : bApproxOK, pfnProgress, pProgressData);
4203 : }
4204 : }
4205 :
4206 : /* -------------------------------------------------------------------- */
4207 : /* Read actual data and build histogram. */
4208 : /* -------------------------------------------------------------------- */
4209 42 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4210 : {
4211 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4212 0 : return CE_Failure;
4213 : }
4214 :
4215 : // Written this way to deal with NaN
4216 42 : if (!(dfMax > dfMin))
4217 : {
4218 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4219 : "dfMax should be strictly greater than dfMin");
4220 5 : return CE_Failure;
4221 : }
4222 :
4223 : GDALRasterIOExtraArg sExtraArg;
4224 37 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4225 :
4226 37 : const double dfScale = nBuckets / (dfMax - dfMin);
4227 37 : if (dfScale == 0 || !std::isfinite(dfScale))
4228 : {
4229 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4230 : "dfMin and dfMax should be finite values such that "
4231 : "nBuckets / (dfMax - dfMin) is non-zero");
4232 5 : return CE_Failure;
4233 : }
4234 32 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4235 :
4236 32 : GDALNoDataValues sNoDataValues(this, eDataType);
4237 32 : GDALRasterBand *poMaskBand = nullptr;
4238 32 : if (!sNoDataValues.bGotNoDataValue)
4239 : {
4240 31 : const int l_nMaskFlags = GetMaskFlags();
4241 33 : if (l_nMaskFlags != GMF_ALL_VALID &&
4242 2 : GetColorInterpretation() != GCI_AlphaBand)
4243 : {
4244 2 : poMaskBand = GetMaskBand();
4245 : }
4246 : }
4247 :
4248 32 : bool bSignedByte = false;
4249 32 : if (eDataType == GDT_Byte)
4250 : {
4251 23 : EnablePixelTypeSignedByteWarning(false);
4252 : const char *pszPixelType =
4253 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4254 23 : EnablePixelTypeSignedByteWarning(true);
4255 23 : bSignedByte =
4256 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4257 : }
4258 :
4259 32 : if (bApproxOK && HasArbitraryOverviews())
4260 : {
4261 : /* --------------------------------------------------------------------
4262 : */
4263 : /* Figure out how much the image should be reduced to get an */
4264 : /* approximate value. */
4265 : /* --------------------------------------------------------------------
4266 : */
4267 : const double dfReduction =
4268 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4269 : GDALSTAT_APPROX_NUMSAMPLES);
4270 :
4271 0 : int nXReduced = nRasterXSize;
4272 0 : int nYReduced = nRasterYSize;
4273 0 : if (dfReduction > 1.0)
4274 : {
4275 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4276 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4277 :
4278 : // Catch the case of huge resizing ratios here
4279 0 : if (nXReduced == 0)
4280 0 : nXReduced = 1;
4281 0 : if (nYReduced == 0)
4282 0 : nYReduced = 1;
4283 : }
4284 :
4285 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4286 : nXReduced, nYReduced);
4287 0 : if (!pData)
4288 0 : return CE_Failure;
4289 :
4290 : const CPLErr eErr =
4291 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4292 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4293 0 : if (eErr != CE_None)
4294 : {
4295 0 : CPLFree(pData);
4296 0 : return eErr;
4297 : }
4298 :
4299 0 : GByte *pabyMaskData = nullptr;
4300 0 : if (poMaskBand)
4301 : {
4302 : pabyMaskData =
4303 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4304 0 : if (!pabyMaskData)
4305 : {
4306 0 : CPLFree(pData);
4307 0 : return CE_Failure;
4308 : }
4309 :
4310 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4311 : pabyMaskData, nXReduced, nYReduced,
4312 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4313 : {
4314 0 : CPLFree(pData);
4315 0 : CPLFree(pabyMaskData);
4316 0 : return CE_Failure;
4317 : }
4318 : }
4319 :
4320 : // This isn't the fastest way to do this, but is easier for now.
4321 0 : for (int iY = 0; iY < nYReduced; iY++)
4322 : {
4323 0 : for (int iX = 0; iX < nXReduced; iX++)
4324 : {
4325 0 : const int iOffset = iX + iY * nXReduced;
4326 0 : double dfValue = 0.0;
4327 :
4328 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4329 0 : continue;
4330 :
4331 0 : switch (eDataType)
4332 : {
4333 0 : case GDT_Byte:
4334 : {
4335 0 : if (bSignedByte)
4336 0 : dfValue =
4337 0 : static_cast<signed char *>(pData)[iOffset];
4338 : else
4339 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4340 0 : break;
4341 : }
4342 0 : case GDT_Int8:
4343 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4344 0 : break;
4345 0 : case GDT_UInt16:
4346 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4347 0 : break;
4348 0 : case GDT_Int16:
4349 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4350 0 : break;
4351 0 : case GDT_UInt32:
4352 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4353 0 : break;
4354 0 : case GDT_Int32:
4355 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4356 0 : break;
4357 0 : case GDT_UInt64:
4358 0 : dfValue = static_cast<double>(
4359 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4360 0 : break;
4361 0 : case GDT_Int64:
4362 0 : dfValue = static_cast<double>(
4363 0 : static_cast<GInt64 *>(pData)[iOffset]);
4364 0 : break;
4365 0 : case GDT_Float16:
4366 : {
4367 : using namespace std;
4368 0 : const GFloat16 hfValue =
4369 0 : static_cast<GFloat16 *>(pData)[iOffset];
4370 0 : if (isnan(hfValue) ||
4371 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4372 0 : ARE_REAL_EQUAL(hfValue,
4373 : sNoDataValues.hfNoDataValue)))
4374 0 : continue;
4375 0 : dfValue = hfValue;
4376 0 : break;
4377 : }
4378 0 : case GDT_Float32:
4379 : {
4380 0 : const float fValue =
4381 0 : static_cast<float *>(pData)[iOffset];
4382 0 : if (std::isnan(fValue) ||
4383 0 : (sNoDataValues.bGotFloatNoDataValue &&
4384 0 : ARE_REAL_EQUAL(fValue,
4385 : sNoDataValues.fNoDataValue)))
4386 0 : continue;
4387 0 : dfValue = fValue;
4388 0 : break;
4389 : }
4390 0 : case GDT_Float64:
4391 0 : dfValue = static_cast<double *>(pData)[iOffset];
4392 0 : if (std::isnan(dfValue))
4393 0 : continue;
4394 0 : break;
4395 0 : case GDT_CInt16:
4396 : {
4397 0 : const double dfReal =
4398 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4399 0 : const double dfImag =
4400 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4401 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4402 0 : continue;
4403 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4404 : }
4405 0 : break;
4406 0 : case GDT_CInt32:
4407 : {
4408 0 : const double dfReal =
4409 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4410 0 : const double dfImag =
4411 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4412 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4413 0 : continue;
4414 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4415 : }
4416 0 : break;
4417 0 : case GDT_CFloat16:
4418 : {
4419 : const double dfReal =
4420 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4421 : const double dfImag =
4422 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4423 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4424 0 : continue;
4425 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4426 0 : break;
4427 : }
4428 0 : case GDT_CFloat32:
4429 : {
4430 0 : const double dfReal =
4431 0 : static_cast<float *>(pData)[iOffset * 2];
4432 0 : const double dfImag =
4433 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4434 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4435 0 : continue;
4436 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4437 0 : break;
4438 : }
4439 0 : case GDT_CFloat64:
4440 : {
4441 0 : const double dfReal =
4442 0 : static_cast<double *>(pData)[iOffset * 2];
4443 0 : const double dfImag =
4444 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4445 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4446 0 : continue;
4447 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4448 0 : break;
4449 : }
4450 0 : case GDT_Unknown:
4451 : case GDT_TypeCount:
4452 0 : CPLAssert(false);
4453 : }
4454 :
4455 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4456 0 : sNoDataValues.bGotNoDataValue &&
4457 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4458 0 : continue;
4459 :
4460 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4461 : // finite, the result of the multiplication cannot be NaN
4462 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4463 :
4464 0 : if (dfIndex < 0)
4465 : {
4466 0 : if (bIncludeOutOfRange)
4467 0 : panHistogram[0]++;
4468 : }
4469 0 : else if (dfIndex >= nBuckets)
4470 : {
4471 0 : if (bIncludeOutOfRange)
4472 0 : ++panHistogram[nBuckets - 1];
4473 : }
4474 : else
4475 : {
4476 0 : ++panHistogram[static_cast<int>(dfIndex)];
4477 : }
4478 : }
4479 : }
4480 :
4481 0 : CPLFree(pData);
4482 0 : CPLFree(pabyMaskData);
4483 : }
4484 : else // No arbitrary overviews.
4485 : {
4486 32 : if (!InitBlockInfo())
4487 0 : return CE_Failure;
4488 :
4489 : /* --------------------------------------------------------------------
4490 : */
4491 : /* Figure out the ratio of blocks we will read to get an */
4492 : /* approximate value. */
4493 : /* --------------------------------------------------------------------
4494 : */
4495 :
4496 32 : int nSampleRate = 1;
4497 32 : if (bApproxOK)
4498 : {
4499 8 : nSampleRate = static_cast<int>(std::max(
4500 16 : 1.0,
4501 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4502 : // We want to avoid probing only the first column of blocks for
4503 : // a square shaped raster, because it is not unlikely that it may
4504 : // be padding only (#6378).
4505 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4506 1 : nSampleRate += 1;
4507 : }
4508 :
4509 32 : GByte *pabyMaskData = nullptr;
4510 32 : if (poMaskBand)
4511 : {
4512 : pabyMaskData = static_cast<GByte *>(
4513 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4514 2 : if (!pabyMaskData)
4515 : {
4516 0 : return CE_Failure;
4517 : }
4518 : }
4519 :
4520 : /* --------------------------------------------------------------------
4521 : */
4522 : /* Read the blocks, and add to histogram. */
4523 : /* --------------------------------------------------------------------
4524 : */
4525 32 : for (GIntBig iSampleBlock = 0;
4526 154 : iSampleBlock <
4527 154 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4528 122 : iSampleBlock += nSampleRate)
4529 : {
4530 122 : if (!pfnProgress(
4531 122 : static_cast<double>(iSampleBlock) /
4532 122 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4533 : "Compute Histogram", pProgressData))
4534 : {
4535 0 : CPLFree(pabyMaskData);
4536 0 : return CE_Failure;
4537 : }
4538 :
4539 122 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4540 122 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4541 :
4542 122 : int nXCheck = 0, nYCheck = 0;
4543 122 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4544 :
4545 124 : if (poMaskBand &&
4546 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4547 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4548 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4549 2 : 0, nBlockXSize, nullptr) != CE_None)
4550 : {
4551 0 : CPLFree(pabyMaskData);
4552 0 : return CE_Failure;
4553 : }
4554 :
4555 122 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4556 122 : if (poBlock == nullptr)
4557 : {
4558 0 : CPLFree(pabyMaskData);
4559 0 : return CE_Failure;
4560 : }
4561 :
4562 122 : void *pData = poBlock->GetDataRef();
4563 :
4564 : // this is a special case for a common situation.
4565 122 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4566 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4567 83 : nXCheck == nBlockXSize && nBuckets == 256)
4568 : {
4569 83 : const GPtrDiff_t nPixels =
4570 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4571 83 : GByte *pabyData = static_cast<GByte *>(pData);
4572 :
4573 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4574 : {
4575 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4576 0 : continue;
4577 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4578 512 : (pabyData[i] ==
4579 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4580 : {
4581 71798 : panHistogram[pabyData[i]]++;
4582 : }
4583 : }
4584 :
4585 83 : poBlock->DropLock();
4586 83 : continue; // To next sample block.
4587 : }
4588 :
4589 : // This isn't the fastest way to do this, but is easier for now.
4590 257 : for (int iY = 0; iY < nYCheck; iY++)
4591 : {
4592 36389 : for (int iX = 0; iX < nXCheck; iX++)
4593 : {
4594 36171 : const GPtrDiff_t iOffset =
4595 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4596 :
4597 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4598 2 : continue;
4599 :
4600 36169 : double dfValue = 0.0;
4601 :
4602 36169 : switch (eDataType)
4603 : {
4604 19716 : case GDT_Byte:
4605 : {
4606 19716 : if (bSignedByte)
4607 0 : dfValue =
4608 0 : static_cast<signed char *>(pData)[iOffset];
4609 : else
4610 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4611 19716 : break;
4612 : }
4613 1 : case GDT_Int8:
4614 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4615 1 : break;
4616 16384 : case GDT_UInt16:
4617 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4618 16384 : break;
4619 3 : case GDT_Int16:
4620 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4621 3 : break;
4622 0 : case GDT_UInt32:
4623 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4624 0 : break;
4625 60 : case GDT_Int32:
4626 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4627 60 : break;
4628 0 : case GDT_UInt64:
4629 0 : dfValue = static_cast<double>(
4630 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4631 0 : break;
4632 0 : case GDT_Int64:
4633 0 : dfValue = static_cast<double>(
4634 0 : static_cast<GInt64 *>(pData)[iOffset]);
4635 0 : break;
4636 0 : case GDT_Float16:
4637 : {
4638 : using namespace std;
4639 0 : const GFloat16 hfValue =
4640 0 : static_cast<GFloat16 *>(pData)[iOffset];
4641 0 : if (isnan(hfValue) ||
4642 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4643 0 : ARE_REAL_EQUAL(hfValue,
4644 : sNoDataValues.hfNoDataValue)))
4645 0 : continue;
4646 0 : dfValue = hfValue;
4647 0 : break;
4648 : }
4649 3 : case GDT_Float32:
4650 : {
4651 3 : const float fValue =
4652 3 : static_cast<float *>(pData)[iOffset];
4653 6 : if (std::isnan(fValue) ||
4654 6 : (sNoDataValues.bGotFloatNoDataValue &&
4655 3 : ARE_REAL_EQUAL(fValue,
4656 : sNoDataValues.fNoDataValue)))
4657 0 : continue;
4658 3 : dfValue = fValue;
4659 3 : break;
4660 : }
4661 2 : case GDT_Float64:
4662 2 : dfValue = static_cast<double *>(pData)[iOffset];
4663 2 : if (std::isnan(dfValue))
4664 0 : continue;
4665 2 : break;
4666 0 : case GDT_CInt16:
4667 : {
4668 0 : double dfReal =
4669 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4670 0 : double dfImag =
4671 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4672 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4673 0 : break;
4674 : }
4675 0 : case GDT_CInt32:
4676 : {
4677 0 : double dfReal =
4678 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4679 0 : double dfImag =
4680 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4681 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4682 0 : break;
4683 : }
4684 0 : case GDT_CFloat16:
4685 : {
4686 : double dfReal =
4687 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4688 : double dfImag =
4689 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4690 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4691 0 : continue;
4692 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4693 0 : break;
4694 : }
4695 0 : case GDT_CFloat32:
4696 : {
4697 0 : double dfReal =
4698 0 : static_cast<float *>(pData)[iOffset * 2];
4699 0 : double dfImag =
4700 0 : static_cast<float *>(pData)[iOffset * 2 + 1];
4701 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4702 0 : continue;
4703 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4704 0 : break;
4705 : }
4706 0 : case GDT_CFloat64:
4707 : {
4708 0 : double dfReal =
4709 0 : static_cast<double *>(pData)[iOffset * 2];
4710 0 : double dfImag =
4711 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4712 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4713 0 : continue;
4714 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4715 0 : break;
4716 : }
4717 0 : case GDT_Unknown:
4718 : case GDT_TypeCount:
4719 0 : CPLAssert(false);
4720 : CPLFree(pabyMaskData);
4721 : return CE_Failure;
4722 : }
4723 :
4724 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4725 72338 : sNoDataValues.bGotNoDataValue &&
4726 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4727 0 : continue;
4728 :
4729 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4730 : // and finite, the result of the multiplication cannot be
4731 : // NaN
4732 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4733 :
4734 36169 : if (dfIndex < 0)
4735 : {
4736 1 : if (bIncludeOutOfRange)
4737 1 : panHistogram[0]++;
4738 : }
4739 36168 : else if (dfIndex >= nBuckets)
4740 : {
4741 7 : if (bIncludeOutOfRange)
4742 4 : ++panHistogram[nBuckets - 1];
4743 : }
4744 : else
4745 : {
4746 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4747 : }
4748 : }
4749 : }
4750 :
4751 39 : poBlock->DropLock();
4752 : }
4753 :
4754 32 : CPLFree(pabyMaskData);
4755 : }
4756 :
4757 32 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4758 :
4759 32 : return CE_None;
4760 : }
4761 :
4762 : /************************************************************************/
4763 : /* GDALGetRasterHistogram() */
4764 : /************************************************************************/
4765 :
4766 : /**
4767 : * \brief Compute raster histogram.
4768 : *
4769 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4770 : * exceeding 2 billion.
4771 : *
4772 : * @see GDALRasterBand::GetHistogram()
4773 : * @see GDALGetRasterHistogramEx()
4774 : */
4775 :
4776 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4777 : double dfMax, int nBuckets,
4778 : int *panHistogram,
4779 : int bIncludeOutOfRange, int bApproxOK,
4780 : GDALProgressFunc pfnProgress,
4781 : void *pProgressData)
4782 :
4783 : {
4784 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4785 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4786 :
4787 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4788 :
4789 : GUIntBig *panHistogramTemp =
4790 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4791 0 : if (panHistogramTemp == nullptr)
4792 : {
4793 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4794 : "Out of memory in GDALGetRasterHistogram().");
4795 0 : return CE_Failure;
4796 : }
4797 :
4798 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4799 : bIncludeOutOfRange, bApproxOK,
4800 0 : pfnProgress, pProgressData);
4801 :
4802 0 : if (eErr == CE_None)
4803 : {
4804 0 : for (int i = 0; i < nBuckets; i++)
4805 : {
4806 0 : if (panHistogramTemp[i] > INT_MAX)
4807 : {
4808 0 : CPLError(CE_Warning, CPLE_AppDefined,
4809 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4810 : " exceeds maximum 32 bit value",
4811 0 : i, panHistogramTemp[i]);
4812 0 : panHistogram[i] = INT_MAX;
4813 : }
4814 : else
4815 : {
4816 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4817 : }
4818 : }
4819 : }
4820 :
4821 0 : CPLFree(panHistogramTemp);
4822 :
4823 0 : return eErr;
4824 : }
4825 :
4826 : /************************************************************************/
4827 : /* GDALGetRasterHistogramEx() */
4828 : /************************************************************************/
4829 :
4830 : /**
4831 : * \brief Compute raster histogram.
4832 : *
4833 : * @see GDALRasterBand::GetHistogram()
4834 : *
4835 : * @since GDAL 2.0
4836 : */
4837 :
4838 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4839 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4840 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4841 : GDALProgressFunc pfnProgress, void *pProgressData)
4842 :
4843 : {
4844 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4845 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4846 :
4847 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4848 :
4849 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4850 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4851 26 : pProgressData);
4852 : }
4853 :
4854 : /************************************************************************/
4855 : /* GetDefaultHistogram() */
4856 : /************************************************************************/
4857 :
4858 : /**
4859 : * \brief Fetch default raster histogram.
4860 : *
4861 : * The default method in GDALRasterBand will compute a default histogram. This
4862 : * method is overridden by derived classes (such as GDALPamRasterBand,
4863 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4864 : * stored histogram.
4865 : *
4866 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4867 : * GDALGetDefaultHistogramEx().
4868 : *
4869 : * @param pdfMin pointer to double value that will contain the lower bound of
4870 : * the histogram.
4871 : * @param pdfMax pointer to double value that will contain the upper bound of
4872 : * the histogram.
4873 : * @param pnBuckets pointer to int value that will contain the number of buckets
4874 : * in *ppanHistogram.
4875 : * @param ppanHistogram pointer to array into which the histogram totals are
4876 : * placed. To be freed with VSIFree
4877 : * @param bForce TRUE to force the computation. If FALSE and no default
4878 : * histogram is available, the method will return CE_Warning
4879 : * @param pfnProgress function to report progress to completion.
4880 : * @param pProgressData application data to pass to pfnProgress.
4881 : *
4882 : * @return CE_None on success, CE_Failure if something goes wrong, or
4883 : * CE_Warning if no default histogram is available.
4884 : */
4885 :
4886 24 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4887 : int *pnBuckets,
4888 : GUIntBig **ppanHistogram, int bForce,
4889 : GDALProgressFunc pfnProgress,
4890 : void *pProgressData)
4891 :
4892 : {
4893 24 : CPLAssert(nullptr != pnBuckets);
4894 24 : CPLAssert(nullptr != ppanHistogram);
4895 24 : CPLAssert(nullptr != pdfMin);
4896 24 : CPLAssert(nullptr != pdfMax);
4897 :
4898 24 : *pnBuckets = 0;
4899 24 : *ppanHistogram = nullptr;
4900 :
4901 24 : if (!bForce)
4902 5 : return CE_Warning;
4903 :
4904 19 : int nBuckets = 256;
4905 :
4906 19 : bool bSignedByte = false;
4907 19 : if (eDataType == GDT_Byte)
4908 : {
4909 17 : EnablePixelTypeSignedByteWarning(false);
4910 : const char *pszPixelType =
4911 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4912 17 : EnablePixelTypeSignedByteWarning(true);
4913 17 : bSignedByte =
4914 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4915 : }
4916 :
4917 19 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4918 : {
4919 17 : *pdfMin = -0.5;
4920 17 : *pdfMax = 255.5;
4921 : }
4922 2 : else if (GetRasterDataType() == GDT_Int8)
4923 : {
4924 1 : *pdfMin = -128 - 0.5;
4925 1 : *pdfMax = 127 + 0.5;
4926 : }
4927 : else
4928 : {
4929 :
4930 : const CPLErr eErr =
4931 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4932 1 : if (eErr != CE_None)
4933 0 : return eErr;
4934 1 : if (*pdfMin == *pdfMax)
4935 : {
4936 1 : nBuckets = 1;
4937 1 : *pdfMin -= 0.5;
4938 1 : *pdfMax += 0.5;
4939 : }
4940 : else
4941 : {
4942 0 : const double dfHalfBucket =
4943 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4944 0 : *pdfMin -= dfHalfBucket;
4945 0 : *pdfMax += dfHalfBucket;
4946 : }
4947 : }
4948 :
4949 19 : *ppanHistogram =
4950 19 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4951 19 : if (*ppanHistogram == nullptr)
4952 : {
4953 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4954 : "Out of memory in InitBlockInfo().");
4955 0 : return CE_Failure;
4956 : }
4957 :
4958 19 : *pnBuckets = nBuckets;
4959 38 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4960 19 : TRUE, FALSE, pfnProgress, pProgressData);
4961 19 : if (eErr != CE_None)
4962 : {
4963 0 : *pnBuckets = 0;
4964 : }
4965 19 : return eErr;
4966 : }
4967 :
4968 : /************************************************************************/
4969 : /* GDALGetDefaultHistogram() */
4970 : /************************************************************************/
4971 :
4972 : /**
4973 : * \brief Fetch default raster histogram.
4974 : *
4975 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4976 : * exceeding 2 billion.
4977 : *
4978 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4979 : * @see GDALGetRasterHistogramEx()
4980 : */
4981 :
4982 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4983 : double *pdfMin, double *pdfMax,
4984 : int *pnBuckets, int **ppanHistogram,
4985 : int bForce,
4986 : GDALProgressFunc pfnProgress,
4987 : void *pProgressData)
4988 :
4989 : {
4990 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4991 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4992 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4993 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4994 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4995 :
4996 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4997 0 : GUIntBig *panHistogramTemp = nullptr;
4998 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
4999 : &panHistogramTemp, bForce,
5000 0 : pfnProgress, pProgressData);
5001 0 : if (eErr == CE_None)
5002 : {
5003 0 : const int nBuckets = *pnBuckets;
5004 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5005 0 : if (*ppanHistogram == nullptr)
5006 : {
5007 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5008 : "Out of memory in GDALGetDefaultHistogram().");
5009 0 : VSIFree(panHistogramTemp);
5010 0 : return CE_Failure;
5011 : }
5012 :
5013 0 : for (int i = 0; i < nBuckets; ++i)
5014 : {
5015 0 : if (panHistogramTemp[i] > INT_MAX)
5016 : {
5017 0 : CPLError(CE_Warning, CPLE_AppDefined,
5018 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5019 : " exceeds maximum 32 bit value",
5020 0 : i, panHistogramTemp[i]);
5021 0 : (*ppanHistogram)[i] = INT_MAX;
5022 : }
5023 : else
5024 : {
5025 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5026 : }
5027 : }
5028 :
5029 0 : CPLFree(panHistogramTemp);
5030 : }
5031 : else
5032 : {
5033 0 : *ppanHistogram = nullptr;
5034 : }
5035 :
5036 0 : return eErr;
5037 : }
5038 :
5039 : /************************************************************************/
5040 : /* GDALGetDefaultHistogramEx() */
5041 : /************************************************************************/
5042 :
5043 : /**
5044 : * \brief Fetch default raster histogram.
5045 : *
5046 : * @see GDALRasterBand::GetDefaultHistogram()
5047 : *
5048 : * @since GDAL 2.0
5049 : */
5050 :
5051 : CPLErr CPL_STDCALL
5052 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5053 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5054 : GDALProgressFunc pfnProgress, void *pProgressData)
5055 :
5056 : {
5057 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5058 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5059 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5060 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5061 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5062 :
5063 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5064 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5065 30 : bForce, pfnProgress, pProgressData);
5066 : }
5067 :
5068 : /************************************************************************/
5069 : /* AdviseRead() */
5070 : /************************************************************************/
5071 :
5072 : /**
5073 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5074 : * \brief Advise driver of upcoming read requests.
5075 : *
5076 : * Some GDAL drivers operate more efficiently if they know in advance what
5077 : * set of upcoming read requests will be made. The AdviseRead() method allows
5078 : * an application to notify the driver of the region of interest,
5079 : * and at what resolution the region will be read.
5080 : *
5081 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5082 : * accelerate access via some drivers.
5083 : *
5084 : * Depending on call paths, drivers might receive several calls to
5085 : * AdviseRead() with the same parameters.
5086 : *
5087 : * @param nXOff The pixel offset to the top left corner of the region
5088 : * of the band to be accessed. This would be zero to start from the left side.
5089 : *
5090 : * @param nYOff The line offset to the top left corner of the region
5091 : * of the band to be accessed. This would be zero to start from the top.
5092 : *
5093 : * @param nXSize The width of the region of the band to be accessed in pixels.
5094 : *
5095 : * @param nYSize The height of the region of the band to be accessed in lines.
5096 : *
5097 : * @param nBufXSize the width of the buffer image into which the desired region
5098 : * is to be read, or from which it is to be written.
5099 : *
5100 : * @param nBufYSize the height of the buffer image into which the desired
5101 : * region is to be read, or from which it is to be written.
5102 : *
5103 : * @param eBufType the type of the pixel values in the pData data buffer. The
5104 : * pixel values will automatically be translated to/from the GDALRasterBand
5105 : * data type as needed.
5106 : *
5107 : * @param papszOptions a list of name=value strings with special control
5108 : * options. Normally this is NULL.
5109 : *
5110 : * @return CE_Failure if the request is invalid and CE_None if it works or
5111 : * is ignored.
5112 : */
5113 :
5114 : /**/
5115 : /**/
5116 :
5117 113437 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5118 : int /*nYSize*/, int /*nBufXSize*/,
5119 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5120 : char ** /*papszOptions*/)
5121 : {
5122 113437 : return CE_None;
5123 : }
5124 :
5125 : /************************************************************************/
5126 : /* GDALRasterAdviseRead() */
5127 : /************************************************************************/
5128 :
5129 : /**
5130 : * \brief Advise driver of upcoming read requests.
5131 : *
5132 : * @see GDALRasterBand::AdviseRead()
5133 : */
5134 :
5135 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5136 : int nYOff, int nXSize, int nYSize,
5137 : int nBufXSize, int nBufYSize,
5138 : GDALDataType eDT,
5139 : CSLConstList papszOptions)
5140 :
5141 : {
5142 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5143 :
5144 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5145 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5146 : nBufYSize, eDT,
5147 2 : const_cast<char **>(papszOptions));
5148 : }
5149 :
5150 : /************************************************************************/
5151 : /* GetStatistics() */
5152 : /************************************************************************/
5153 :
5154 : /**
5155 : * \brief Fetch image statistics.
5156 : *
5157 : * Returns the minimum, maximum, mean and standard deviation of all
5158 : * pixel values in this band. If approximate statistics are sufficient,
5159 : * the bApproxOK flag can be set to true in which case overviews, or a
5160 : * subset of image tiles may be used in computing the statistics.
5161 : *
5162 : * If bForce is FALSE results will only be returned if it can be done
5163 : * quickly (i.e. without scanning the image, typically by using pre-existing
5164 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5165 : * returned efficiently, the method will return CE_Warning but no warning will
5166 : * be issued. This is a non-standard use of the CE_Warning return value
5167 : * to indicate "nothing done".
5168 : *
5169 : * If bForce is TRUE, and results are quickly available without scanning the
5170 : * image, they will be used. If bForce is TRUE and results are not quickly
5171 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5172 : * which will scan the image.
5173 : *
5174 : * To always force recomputation of statistics, use ComputeStatistics() instead
5175 : * of this method.
5176 : *
5177 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5178 : * will generally cache statistics in the .pam file allowing fast fetch
5179 : * after the first request.
5180 : *
5181 : * This method is the same as the C function GDALGetRasterStatistics().
5182 : *
5183 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5184 : * or a subset of all tiles.
5185 : *
5186 : * @param bForce If FALSE statistics will only be returned if it can
5187 : * be done without rescanning the image. If TRUE, statistics computation will
5188 : * be forced if pre-existing values are not quickly available.
5189 : *
5190 : * @param pdfMin Location into which to load image minimum (may be NULL).
5191 : *
5192 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5193 : *
5194 : * @param pdfMean Location into which to load image mean (may be NULL).
5195 : *
5196 : * @param pdfStdDev Location into which to load image standard deviation
5197 : * (may be NULL).
5198 : *
5199 : * @return CE_None on success, CE_Warning if no values returned,
5200 : * CE_Failure if an error occurs.
5201 : */
5202 :
5203 628 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5204 : double *pdfMax, double *pdfMean,
5205 : double *pdfStdDev)
5206 :
5207 : {
5208 : /* -------------------------------------------------------------------- */
5209 : /* Do we already have metadata items for the requested values? */
5210 : /* -------------------------------------------------------------------- */
5211 1256 : if ((pdfMin == nullptr ||
5212 628 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5213 203 : (pdfMax == nullptr ||
5214 203 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5215 1459 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5216 203 : (pdfStdDev == nullptr ||
5217 203 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5218 : {
5219 203 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5220 : {
5221 196 : if (pdfMin != nullptr)
5222 196 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5223 196 : if (pdfMax != nullptr)
5224 196 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5225 196 : if (pdfMean != nullptr)
5226 196 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5227 196 : if (pdfStdDev != nullptr)
5228 196 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5229 :
5230 196 : return CE_None;
5231 : }
5232 : }
5233 :
5234 : /* -------------------------------------------------------------------- */
5235 : /* Does the driver already know the min/max? */
5236 : /* -------------------------------------------------------------------- */
5237 432 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5238 : {
5239 1 : int bSuccessMin = FALSE;
5240 1 : int bSuccessMax = FALSE;
5241 :
5242 1 : const double dfMin = GetMinimum(&bSuccessMin);
5243 1 : const double dfMax = GetMaximum(&bSuccessMax);
5244 :
5245 1 : if (bSuccessMin && bSuccessMax)
5246 : {
5247 0 : if (pdfMin != nullptr)
5248 0 : *pdfMin = dfMin;
5249 0 : if (pdfMax != nullptr)
5250 0 : *pdfMax = dfMax;
5251 0 : return CE_None;
5252 : }
5253 : }
5254 :
5255 : /* -------------------------------------------------------------------- */
5256 : /* Either return without results, or force computation. */
5257 : /* -------------------------------------------------------------------- */
5258 432 : if (!bForce)
5259 176 : return CE_Warning;
5260 : else
5261 256 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5262 256 : GDALDummyProgress, nullptr);
5263 : }
5264 :
5265 : /************************************************************************/
5266 : /* GDALGetRasterStatistics() */
5267 : /************************************************************************/
5268 :
5269 : /**
5270 : * \brief Fetch image statistics.
5271 : *
5272 : * @see GDALRasterBand::GetStatistics()
5273 : */
5274 :
5275 276 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5276 : int bForce, double *pdfMin,
5277 : double *pdfMax, double *pdfMean,
5278 : double *pdfStdDev)
5279 :
5280 : {
5281 276 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5282 :
5283 276 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5284 276 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5285 276 : pdfStdDev);
5286 : }
5287 :
5288 : /************************************************************************/
5289 : /* GDALUInt128 */
5290 : /************************************************************************/
5291 :
5292 : #ifdef HAVE_UINT128_T
5293 : class GDALUInt128
5294 : {
5295 : __uint128_t val;
5296 :
5297 642 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5298 : {
5299 642 : }
5300 :
5301 : public:
5302 428 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5303 : {
5304 : // Evaluates to just a single mul on x86_64
5305 428 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5306 : }
5307 :
5308 214 : GDALUInt128 operator-(const GDALUInt128 &other) const
5309 : {
5310 214 : return GDALUInt128(val - other.val);
5311 : }
5312 :
5313 205 : operator double() const
5314 : {
5315 205 : return static_cast<double>(val);
5316 : }
5317 : };
5318 : #else
5319 :
5320 : #if defined(_MSC_VER) && defined(_M_X64)
5321 : #include <intrin.h>
5322 : #endif
5323 :
5324 : class GDALUInt128
5325 : {
5326 : GUIntBig low, high;
5327 :
5328 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5329 : {
5330 : }
5331 :
5332 : public:
5333 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5334 : {
5335 : #if defined(_MSC_VER) && defined(_M_X64)
5336 : GUIntBig highRes;
5337 : GUIntBig lowRes = _umul128(first, second, &highRes);
5338 : return GDALUInt128(lowRes, highRes);
5339 : #else
5340 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5341 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5342 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5343 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5344 : GUIntBig highRes = 0;
5345 : const GUIntBig firstLowSecondHigh =
5346 : static_cast<GUIntBig>(firstLow) * secondHigh;
5347 : const GUIntBig firstHighSecondLow =
5348 : static_cast<GUIntBig>(firstHigh) * secondLow;
5349 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5350 : if (middleTerm < firstLowSecondHigh) // check for overflow
5351 : highRes += static_cast<GUIntBig>(1) << 32;
5352 : const GUIntBig firstLowSecondLow =
5353 : static_cast<GUIntBig>(firstLow) * secondLow;
5354 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5355 : if (lowRes < firstLowSecondLow) // check for overflow
5356 : highRes++;
5357 : highRes +=
5358 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5359 : return GDALUInt128(lowRes, highRes);
5360 : #endif
5361 : }
5362 :
5363 : GDALUInt128 operator-(const GDALUInt128 &other) const
5364 : {
5365 : GUIntBig highRes = high - other.high;
5366 : GUIntBig lowRes = low - other.low;
5367 : if (lowRes > low) // check for underflow
5368 : --highRes;
5369 : return GDALUInt128(lowRes, highRes);
5370 : }
5371 :
5372 : operator double() const
5373 : {
5374 : const double twoPow64 = 18446744073709551616.0;
5375 : return high * twoPow64 + low;
5376 : }
5377 : };
5378 : #endif
5379 :
5380 : /************************************************************************/
5381 : /* ComputeStatisticsInternal() */
5382 : /************************************************************************/
5383 :
5384 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5385 : // not needed.
5386 : #define static_cast_for_coverity_scan static_cast
5387 :
5388 : // The rationale for below optimizations is detailed in statistics.txt
5389 :
5390 : // Use with T = GByte or GUInt16 only !
5391 : template <class T, bool COMPUTE_OTHER_STATS>
5392 : struct ComputeStatisticsInternalGeneric
5393 : {
5394 208 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5395 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5396 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5397 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5398 : {
5399 : static_assert(std::is_same<T, GByte>::value ||
5400 : std::is_same<T, GUInt16>::value,
5401 : "bad type for T");
5402 208 : if (bHasNoData)
5403 : {
5404 : // General case
5405 386 : for (int iY = 0; iY < nYCheck; iY++)
5406 : {
5407 81751 : for (int iX = 0; iX < nXCheck; iX++)
5408 : {
5409 81468 : const GPtrDiff_t iOffset =
5410 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5411 81468 : const GUInt32 nValue = pData[iOffset];
5412 81468 : if (nValue == nNoDataValue)
5413 175 : continue;
5414 81293 : if (nValue < nMin)
5415 26 : nMin = nValue;
5416 81293 : if (nValue > nMax)
5417 57 : nMax = nValue;
5418 : if constexpr (COMPUTE_OTHER_STATS)
5419 : {
5420 79657 : nValidCount++;
5421 79657 : nSum += nValue;
5422 79657 : nSumSquare +=
5423 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5424 79657 : nValue;
5425 : }
5426 : }
5427 : }
5428 : if constexpr (COMPUTE_OTHER_STATS)
5429 : {
5430 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5431 : }
5432 : }
5433 115 : else if (nMin == std::numeric_limits<T>::lowest() &&
5434 10 : nMax == std::numeric_limits<T>::max())
5435 : {
5436 : if constexpr (COMPUTE_OTHER_STATS)
5437 : {
5438 : // Optimization when there is no nodata and we know we have already
5439 : // reached the min and max
5440 208 : for (int iY = 0; iY < nYCheck; iY++)
5441 : {
5442 : int iX;
5443 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5444 : {
5445 800 : const GPtrDiff_t iOffset =
5446 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5447 800 : const GUIntBig nValue = pData[iOffset];
5448 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5449 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5450 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5451 800 : nSum += nValue;
5452 800 : nSumSquare += nValue * nValue;
5453 800 : nSum += nValue2;
5454 800 : nSumSquare += nValue2 * nValue2;
5455 800 : nSum += nValue3;
5456 800 : nSumSquare += nValue3 * nValue3;
5457 800 : nSum += nValue4;
5458 800 : nSumSquare += nValue4 * nValue4;
5459 : }
5460 207 : for (; iX < nXCheck; ++iX)
5461 : {
5462 5 : const GPtrDiff_t iOffset =
5463 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5464 5 : const GUIntBig nValue = pData[iOffset];
5465 5 : nSum += nValue;
5466 5 : nSumSquare += nValue * nValue;
5467 : }
5468 : }
5469 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5470 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5471 : }
5472 : }
5473 : else
5474 : {
5475 3434 : for (int iY = 0; iY < nYCheck; iY++)
5476 : {
5477 : int iX;
5478 643297 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5479 : {
5480 639962 : const GPtrDiff_t iOffset =
5481 639962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5482 639962 : const GUInt32 nValue = pData[iOffset];
5483 639962 : const GUInt32 nValue2 = pData[iOffset + 1];
5484 639962 : if (nValue < nValue2)
5485 : {
5486 2320 : if (nValue < nMin)
5487 48 : nMin = nValue;
5488 2320 : if (nValue2 > nMax)
5489 116 : nMax = nValue2;
5490 : }
5491 : else
5492 : {
5493 637642 : if (nValue2 < nMin)
5494 66 : nMin = nValue2;
5495 637642 : if (nValue > nMax)
5496 215 : nMax = nValue;
5497 : }
5498 : if constexpr (COMPUTE_OTHER_STATS)
5499 : {
5500 632911 : nSum += nValue;
5501 632911 : nSumSquare +=
5502 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5503 632911 : nValue;
5504 632911 : nSum += nValue2;
5505 632911 : nSumSquare +=
5506 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5507 632911 : nValue2;
5508 : }
5509 : }
5510 3335 : if (iX < nXCheck)
5511 : {
5512 18 : const GPtrDiff_t iOffset =
5513 18 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5514 18 : const GUInt32 nValue = pData[iOffset];
5515 18 : if (nValue < nMin)
5516 13 : nMin = nValue;
5517 18 : if (nValue > nMax)
5518 14 : nMax = nValue;
5519 : if (COMPUTE_OTHER_STATS)
5520 : {
5521 9 : nSum += nValue;
5522 9 : nSumSquare +=
5523 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5524 9 : nValue;
5525 : }
5526 : }
5527 : }
5528 : if constexpr (COMPUTE_OTHER_STATS)
5529 : {
5530 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5531 44 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5532 : }
5533 : }
5534 208 : }
5535 : };
5536 :
5537 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5538 : // using 64bit accumulators in internal loops. This also slightly helps in
5539 : // 64bit mode.
5540 : template <bool COMPUTE_OTHER_STATS>
5541 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5542 : {
5543 13697 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5544 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5545 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5546 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5547 : {
5548 13697 : int nOuterLoops = nXCheck / 65536;
5549 13697 : if (nXCheck % 65536)
5550 13697 : nOuterLoops++;
5551 :
5552 13697 : if (bHasNoData)
5553 : {
5554 : // General case
5555 23475 : for (int iY = 0; iY < nYCheck; iY++)
5556 : {
5557 12901 : int iX = 0;
5558 25802 : for (int k = 0; k < nOuterLoops; k++)
5559 : {
5560 12901 : int iMax = iX + 65536;
5561 12901 : if (iMax > nXCheck)
5562 12901 : iMax = nXCheck;
5563 12901 : GUInt32 nSum32bit = 0;
5564 12901 : GUInt32 nSumSquare32bit = 0;
5565 12901 : GUInt32 nValidCount32bit = 0;
5566 12901 : GUInt32 nSampleCount32bit = 0;
5567 20707205 : for (; iX < iMax; iX++)
5568 : {
5569 20694353 : const GPtrDiff_t iOffset =
5570 20694353 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5571 20694353 : const GUInt32 nValue = pData[iOffset];
5572 :
5573 20694353 : nSampleCount32bit++;
5574 20694353 : if (nValue == nNoDataValue)
5575 20353480 : continue;
5576 340818 : if (nValue < nMin)
5577 357 : nMin = nValue;
5578 340818 : if (nValue > nMax)
5579 813 : nMax = nValue;
5580 : if constexpr (COMPUTE_OTHER_STATS)
5581 : {
5582 17073 : nValidCount32bit++;
5583 17073 : nSum32bit += nValue;
5584 17073 : nSumSquare32bit += nValue * nValue;
5585 : }
5586 : }
5587 : if constexpr (COMPUTE_OTHER_STATS)
5588 : {
5589 652 : nSampleCount += nSampleCount32bit;
5590 652 : nValidCount += nValidCount32bit;
5591 652 : nSum += nSum32bit;
5592 652 : nSumSquare += nSumSquare32bit;
5593 : }
5594 : }
5595 : }
5596 : }
5597 3123 : else if (nMin == 0 && nMax == 255)
5598 : {
5599 : if constexpr (COMPUTE_OTHER_STATS)
5600 : {
5601 : // Optimization when there is no nodata and we know we have already
5602 : // reached the min and max
5603 2644 : for (int iY = 0; iY < nYCheck; iY++)
5604 : {
5605 2617 : int iX = 0;
5606 5234 : for (int k = 0; k < nOuterLoops; k++)
5607 : {
5608 2617 : int iMax = iX + 65536;
5609 2617 : if (iMax > nXCheck)
5610 2617 : iMax = nXCheck;
5611 2617 : GUInt32 nSum32bit = 0;
5612 2617 : GUInt32 nSumSquare32bit = 0;
5613 176297 : for (; iX + 3 < iMax; iX += 4)
5614 : {
5615 173680 : const GPtrDiff_t iOffset =
5616 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5617 173680 : const GUInt32 nValue = pData[iOffset];
5618 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5619 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5620 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5621 173680 : nSum32bit += nValue;
5622 173680 : nSumSquare32bit += nValue * nValue;
5623 173680 : nSum32bit += nValue2;
5624 173680 : nSumSquare32bit += nValue2 * nValue2;
5625 173680 : nSum32bit += nValue3;
5626 173680 : nSumSquare32bit += nValue3 * nValue3;
5627 173680 : nSum32bit += nValue4;
5628 173680 : nSumSquare32bit += nValue4 * nValue4;
5629 : }
5630 2617 : nSum += nSum32bit;
5631 2617 : nSumSquare += nSumSquare32bit;
5632 : }
5633 2620 : for (; iX < nXCheck; ++iX)
5634 : {
5635 3 : const GPtrDiff_t iOffset =
5636 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5637 3 : const GUIntBig nValue = pData[iOffset];
5638 3 : nSum += nValue;
5639 3 : nSumSquare += nValue * nValue;
5640 : }
5641 : }
5642 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5643 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5644 27 : }
5645 : }
5646 : else
5647 : {
5648 7883 : for (int iY = 0; iY < nYCheck; iY++)
5649 : {
5650 4787 : int iX = 0;
5651 9574 : for (int k = 0; k < nOuterLoops; k++)
5652 : {
5653 4787 : int iMax = iX + 65536;
5654 4787 : if (iMax > nXCheck)
5655 4787 : iMax = nXCheck;
5656 4787 : GUInt32 nSum32bit = 0;
5657 4787 : GUInt32 nSumSquare32bit = 0;
5658 159415 : for (; iX + 1 < iMax; iX += 2)
5659 : {
5660 154628 : const GPtrDiff_t iOffset =
5661 154628 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5662 154628 : const GUInt32 nValue = pData[iOffset];
5663 154628 : const GUInt32 nValue2 = pData[iOffset + 1];
5664 154628 : if (nValue < nValue2)
5665 : {
5666 8047 : if (nValue < nMin)
5667 230 : nMin = nValue;
5668 8047 : if (nValue2 > nMax)
5669 219 : nMax = nValue2;
5670 : }
5671 : else
5672 : {
5673 146581 : if (nValue2 < nMin)
5674 359 : nMin = nValue2;
5675 146581 : if (nValue > nMax)
5676 828 : nMax = nValue;
5677 : }
5678 : if constexpr (COMPUTE_OTHER_STATS)
5679 : {
5680 132491 : nSum32bit += nValue;
5681 132491 : nSumSquare32bit += nValue * nValue;
5682 132491 : nSum32bit += nValue2;
5683 132491 : nSumSquare32bit += nValue2 * nValue2;
5684 : }
5685 : }
5686 : if constexpr (COMPUTE_OTHER_STATS)
5687 : {
5688 1610 : nSum += nSum32bit;
5689 1610 : nSumSquare += nSumSquare32bit;
5690 : }
5691 : }
5692 4787 : if (iX < nXCheck)
5693 : {
5694 1515 : const GPtrDiff_t iOffset =
5695 1515 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5696 1515 : const GUInt32 nValue = pData[iOffset];
5697 1515 : if (nValue < nMin)
5698 108 : nMin = nValue;
5699 1515 : if (nValue > nMax)
5700 95 : nMax = nValue;
5701 : if constexpr (COMPUTE_OTHER_STATS)
5702 : {
5703 313 : nSum += nValue;
5704 313 : nSumSquare +=
5705 313 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5706 313 : nValue;
5707 : }
5708 : }
5709 : }
5710 : if constexpr (COMPUTE_OTHER_STATS)
5711 : {
5712 909 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5713 909 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5714 : }
5715 : }
5716 13697 : }
5717 : };
5718 :
5719 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5720 : {
5721 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5722 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5723 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5724 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5725 : {
5726 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5727 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5728 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5729 : }
5730 : };
5731 :
5732 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5733 : (defined(__GNUC__) || defined(_MSC_VER))
5734 :
5735 : #include "gdal_avx2_emulation.hpp"
5736 :
5737 : #define ZERO256 GDALmm256_setzero_si256()
5738 :
5739 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5740 : static void
5741 21335 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5742 : // assumed to be aligned on 256 bits
5743 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5744 : GUIntBig &nSum, GUIntBig &nSumSquare,
5745 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5746 : {
5747 : // 32-byte alignment may not be enforced by linker, so do it at hand
5748 : GByte
5749 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5750 21335 : GByte *paby32ByteAligned =
5751 : aby32ByteUnaligned +
5752 21335 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5753 21335 : GByte *pabyMin = paby32ByteAligned;
5754 21335 : GByte *pabyMax = paby32ByteAligned + 32;
5755 21335 : GUInt32 *panSum =
5756 : COMPUTE_OTHER_STATS
5757 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5758 : : nullptr;
5759 21335 : GUInt32 *panSumSquare =
5760 : COMPUTE_OTHER_STATS
5761 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5762 : : nullptr;
5763 :
5764 21335 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5765 :
5766 21335 : GPtrDiff_t i = 0;
5767 : // Make sure that sumSquare can fit on uint32
5768 : // * 8 since we can hold 8 sums per vector register
5769 21335 : const int nMaxIterationsPerInnerLoop =
5770 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5771 21335 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5772 21335 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5773 21335 : nOuterLoops++;
5774 :
5775 : GDALm256i ymm_min =
5776 21335 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5777 21335 : GDALm256i ymm_max = ymm_min;
5778 21335 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5779 :
5780 42670 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5781 : {
5782 21335 : const auto iMax =
5783 21335 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5784 :
5785 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5786 21335 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5787 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5788 21335 : ZERO256; // holds 8 uint32 sums
5789 717110 : for (; i + 31 < iMax; i += 32)
5790 : {
5791 695775 : const GDALm256i ymm = GDALmm256_load_si256(
5792 695775 : reinterpret_cast<const GDALm256i *>(pData + i));
5793 : if (COMPUTE_MIN)
5794 : {
5795 237938 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5796 : }
5797 : if (COMPUTE_MAX)
5798 : {
5799 604834 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5800 : }
5801 :
5802 : if constexpr (COMPUTE_OTHER_STATS)
5803 : {
5804 : // Extract even-8bit values
5805 : const GDALm256i ymm_even =
5806 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5807 : // Compute square of those 16 values as 32 bit result
5808 : // and add adjacent pairs
5809 : const GDALm256i ymm_even_square =
5810 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5811 : // Add to the sumsquare accumulator
5812 : ymm_sumsquare =
5813 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5814 :
5815 : // Extract odd-8bit values
5816 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5817 : const GDALm256i ymm_odd_square =
5818 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5819 : ymm_sumsquare =
5820 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5821 :
5822 : // Now compute the sums
5823 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5824 : GDALmm256_sad_epu8(ymm, ZERO256));
5825 : }
5826 : }
5827 :
5828 : if constexpr (COMPUTE_OTHER_STATS)
5829 : {
5830 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5831 : ymm_sum);
5832 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5833 : ymm_sumsquare);
5834 :
5835 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5836 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5837 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5838 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5839 : panSumSquare[7];
5840 : }
5841 : }
5842 :
5843 : if constexpr (COMPUTE_MIN)
5844 : {
5845 8461 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5846 : }
5847 : if constexpr (COMPUTE_MAX)
5848 : {
5849 17338 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5850 : }
5851 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5852 : {
5853 589644 : for (int j = 0; j < 32; j++)
5854 : {
5855 : if constexpr (COMPUTE_MIN)
5856 : {
5857 270752 : if (pabyMin[j] < nMin)
5858 1263 : nMin = pabyMin[j];
5859 : }
5860 : if constexpr (COMPUTE_MAX)
5861 : {
5862 554816 : if (pabyMax[j] > nMax)
5863 1814 : nMax = pabyMax[j];
5864 : }
5865 : }
5866 : }
5867 :
5868 234401 : for (; i < nBlockPixels; i++)
5869 : {
5870 213066 : const GUInt32 nValue = pData[i];
5871 : if constexpr (COMPUTE_MIN)
5872 : {
5873 88390 : if (nValue < nMin)
5874 1 : nMin = nValue;
5875 : }
5876 : if constexpr (COMPUTE_MAX)
5877 : {
5878 210291 : if (nValue > nMax)
5879 1149 : nMax = nValue;
5880 : }
5881 : if constexpr (COMPUTE_OTHER_STATS)
5882 : {
5883 77195 : nSum += nValue;
5884 77195 : nSumSquare +=
5885 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5886 : }
5887 : }
5888 :
5889 : if constexpr (COMPUTE_OTHER_STATS)
5890 : {
5891 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5892 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5893 : }
5894 21335 : }
5895 :
5896 : // SSE2/AVX2 optimization for GByte case
5897 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5898 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5899 : // there are strictly equivalent to 2 parallel SSE2 streams.
5900 : template <bool COMPUTE_OTHER_STATS>
5901 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5902 : {
5903 30168 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5904 : // assumed to be aligned on 256 bits
5905 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5906 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5907 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5908 : GUIntBig &nValidCount)
5909 : {
5910 30168 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5911 30168 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5912 11574 : nMin <= nMax)
5913 : {
5914 : // 32-byte alignment may not be enforced by linker, so do it at hand
5915 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5916 1459 : GByte *paby32ByteAligned =
5917 : aby32ByteUnaligned +
5918 1459 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5919 1459 : GByte *pabyMin = paby32ByteAligned;
5920 1459 : GByte *pabyMax = paby32ByteAligned + 32;
5921 1459 : GUInt32 *panSum =
5922 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5923 1459 : GUInt32 *panSumSquare =
5924 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5925 :
5926 1459 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5927 :
5928 1459 : GPtrDiff_t i = 0;
5929 : // Make sure that sumSquare can fit on uint32
5930 : // * 8 since we can hold 8 sums per vector register
5931 1459 : const int nMaxIterationsPerInnerLoop =
5932 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5933 1459 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5934 1459 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5935 1459 : nOuterLoops++;
5936 :
5937 : const GDALm256i ymm_nodata =
5938 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5939 : // any non noData value in [min,max] would do.
5940 : const GDALm256i ymm_neutral =
5941 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5942 1459 : GDALm256i ymm_min = ymm_neutral;
5943 1459 : GDALm256i ymm_max = ymm_neutral;
5944 : [[maybe_unused]] const auto ymm_mask_8bits =
5945 1459 : GDALmm256_set1_epi16(0xFF);
5946 :
5947 1459 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5948 1459 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5949 1459 : const bool bComputeMinMax =
5950 1459 : nMin > nMinThreshold || nMax < nMaxThreshold;
5951 :
5952 2918 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5953 : {
5954 1459 : const auto iMax =
5955 1459 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5956 :
5957 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5958 1459 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5959 : // holds 8 uint32 sums
5960 1459 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5961 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5962 1459 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5963 1459 : const auto iInit = i;
5964 14435 : for (; i + 31 < iMax; i += 32)
5965 : {
5966 12976 : const GDALm256i ymm = GDALmm256_load_si256(
5967 12976 : reinterpret_cast<const GDALm256i *>(pData + i));
5968 :
5969 : // Check which values are nodata
5970 : const GDALm256i ymm_eq_nodata =
5971 12976 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5972 : if constexpr (COMPUTE_OTHER_STATS)
5973 : {
5974 : // Count how many values are nodata (due to cmpeq
5975 : // putting 255 when condition is met, this will actually
5976 : // be 255 times the number of nodata value, spread in 4
5977 : // 64 bits words). We can use add_epi32 as the counter
5978 : // will not overflow uint32
5979 4634 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5980 : ymm_count_nodata_mul_255,
5981 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5982 : }
5983 : // Replace all nodata values by zero for the purpose of sum
5984 : // and sumquare.
5985 : const GDALm256i ymm_nodata_by_zero =
5986 12976 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5987 12976 : if (bComputeMinMax)
5988 : {
5989 : // Replace all nodata values by a neutral value for the
5990 : // purpose of min and max.
5991 : const GDALm256i ymm_nodata_by_neutral =
5992 8591 : GDALmm256_or_si256(
5993 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5994 : ymm_nodata_by_zero);
5995 :
5996 : ymm_min =
5997 8591 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5998 : ymm_max =
5999 8591 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6000 : }
6001 :
6002 : if constexpr (COMPUTE_OTHER_STATS)
6003 : {
6004 : // Extract even-8bit values
6005 4634 : const GDALm256i ymm_even = GDALmm256_and_si256(
6006 : ymm_nodata_by_zero, ymm_mask_8bits);
6007 : // Compute square of those 16 values as 32 bit result
6008 : // and add adjacent pairs
6009 : const GDALm256i ymm_even_square =
6010 4634 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6011 : // Add to the sumsquare accumulator
6012 : ymm_sumsquare =
6013 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6014 :
6015 : // Extract odd-8bit values
6016 : const GDALm256i ymm_odd =
6017 4634 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6018 : const GDALm256i ymm_odd_square =
6019 4634 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6020 : ymm_sumsquare =
6021 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6022 :
6023 : // Now compute the sums
6024 4634 : ymm_sum = GDALmm256_add_epi32(
6025 : ymm_sum,
6026 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6027 : }
6028 : }
6029 :
6030 : if constexpr (COMPUTE_OTHER_STATS)
6031 : {
6032 153 : GUInt32 *panCoutNoDataMul255 = panSum;
6033 153 : GDALmm256_store_si256(
6034 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6035 : ymm_count_nodata_mul_255);
6036 :
6037 153 : nSampleCount += (i - iInit);
6038 :
6039 153 : nValidCount +=
6040 153 : (i - iInit) -
6041 153 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6042 153 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6043 : 255;
6044 :
6045 153 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6046 : ymm_sum);
6047 153 : GDALmm256_store_si256(
6048 : reinterpret_cast<GDALm256i *>(panSumSquare),
6049 : ymm_sumsquare);
6050 153 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6051 153 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6052 153 : panSumSquare[1] + panSumSquare[2] +
6053 153 : panSumSquare[3] + panSumSquare[4] +
6054 153 : panSumSquare[5] + panSumSquare[6] +
6055 : panSumSquare[7];
6056 : }
6057 : }
6058 :
6059 1459 : if (bComputeMinMax)
6060 : {
6061 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6062 : ymm_min);
6063 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6064 : ymm_max);
6065 47124 : for (int j = 0; j < 32; j++)
6066 : {
6067 45696 : if (pabyMin[j] < nMin)
6068 40 : nMin = pabyMin[j];
6069 45696 : if (pabyMax[j] > nMax)
6070 159 : nMax = pabyMax[j];
6071 : }
6072 : }
6073 :
6074 : if constexpr (COMPUTE_OTHER_STATS)
6075 : {
6076 153 : nSampleCount += nBlockPixels - i;
6077 : }
6078 33905 : for (; i < nBlockPixels; i++)
6079 : {
6080 32446 : const GUInt32 nValue = pData[i];
6081 32446 : if (nValue == nNoDataValue)
6082 24923 : continue;
6083 7523 : if (nValue < nMin)
6084 1 : nMin = nValue;
6085 7523 : if (nValue > nMax)
6086 13 : nMax = nValue;
6087 : if constexpr (COMPUTE_OTHER_STATS)
6088 : {
6089 3590 : nValidCount++;
6090 3590 : nSum += nValue;
6091 3590 : nSumSquare +=
6092 3590 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6093 3590 : nValue;
6094 : }
6095 1459 : }
6096 : }
6097 28709 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6098 : {
6099 14979 : if (nMin > 0)
6100 : {
6101 2105 : if (nMax < 255)
6102 : {
6103 : ComputeStatisticsByteNoNodata<true, true,
6104 1575 : COMPUTE_OTHER_STATS>(
6105 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6106 : nSampleCount, nValidCount);
6107 : }
6108 : else
6109 : {
6110 : ComputeStatisticsByteNoNodata<true, false,
6111 530 : COMPUTE_OTHER_STATS>(
6112 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6113 : nSampleCount, nValidCount);
6114 : }
6115 : }
6116 : else
6117 : {
6118 12874 : if (nMax < 255)
6119 : {
6120 : ComputeStatisticsByteNoNodata<false, true,
6121 9407 : COMPUTE_OTHER_STATS>(
6122 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6123 : nSampleCount, nValidCount);
6124 : }
6125 : else
6126 : {
6127 : ComputeStatisticsByteNoNodata<false, false,
6128 3467 : COMPUTE_OTHER_STATS>(
6129 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6130 : nSampleCount, nValidCount);
6131 : }
6132 : }
6133 : }
6134 12475 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6135 33 : (nBlockXSize % 32) == 0)
6136 : {
6137 6389 : for (int iY = 0; iY < nYCheck; iY++)
6138 : {
6139 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6140 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6141 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6142 33 : }
6143 : }
6144 : else
6145 : {
6146 13697 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6147 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6148 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6149 : }
6150 30168 : }
6151 : };
6152 :
6153 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6154 400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6155 : GUIntBig i)
6156 : {
6157 400 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6158 400 : }
6159 :
6160 : // AVX2/SSE2 optimization for GUInt16 case
6161 : template <bool COMPUTE_OTHER_STATS>
6162 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6163 : {
6164 1882 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6165 : // assumed to be aligned on 128 bits
6166 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6167 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6168 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6169 : GUIntBig &nValidCount)
6170 : {
6171 1882 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6172 1882 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6173 : {
6174 1674 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6175 :
6176 1674 : GPtrDiff_t i = 0;
6177 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6178 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6179 : // Furthermore the shift is also needed to use madd_epi16
6180 1674 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6181 1674 : GDALm256i ymm_min = GDALmm256_load_si256(
6182 1674 : reinterpret_cast<const GDALm256i *>(pData + i));
6183 1674 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6184 1674 : GDALm256i ymm_max = ymm_min;
6185 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6186 1674 : ZERO256; // holds 4 uint64 sums
6187 :
6188 : // Make sure that sum can fit on uint32
6189 : // * 8 since we can hold 8 sums per vector register
6190 1674 : const int nMaxIterationsPerInnerLoop =
6191 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6192 1674 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6193 1674 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6194 1674 : nOuterLoops++;
6195 :
6196 1674 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6197 : [[maybe_unused]] const auto ymm_mask_16bits =
6198 1674 : GDALmm256_set1_epi32(0xFFFF);
6199 : [[maybe_unused]] const auto ymm_mask_32bits =
6200 1674 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6201 :
6202 1674 : GUIntBig nSumThis = 0;
6203 3372 : for (int k = 0; k < nOuterLoops; k++)
6204 : {
6205 1698 : const auto iMax =
6206 1698 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6207 :
6208 : [[maybe_unused]] GDALm256i ymm_sum =
6209 1698 : ZERO256; // holds 8 uint32 sums
6210 964126 : for (; i + 15 < iMax; i += 16)
6211 : {
6212 962428 : const GDALm256i ymm = GDALmm256_load_si256(
6213 962428 : reinterpret_cast<const GDALm256i *>(pData + i));
6214 : const GDALm256i ymm_shifted =
6215 962428 : GDALmm256_add_epi16(ymm, ymm_m32768);
6216 962428 : if (bComputeMinMax)
6217 : {
6218 953409 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6219 953409 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6220 : }
6221 :
6222 : if constexpr (COMPUTE_OTHER_STATS)
6223 : {
6224 : // Note: the int32 range can overflow for (0-32768)^2 +
6225 : // (0-32768)^2 = 0x80000000, but as we know the result
6226 : // is positive, this is OK as we interpret is a uint32.
6227 : const GDALm256i ymm_square =
6228 95410 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6229 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6230 : ymm_sumsquare,
6231 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6232 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6233 : ymm_sumsquare,
6234 : GDALmm256_srli_epi64(ymm_square, 32));
6235 :
6236 : // Now compute the sums
6237 95410 : ymm_sum = GDALmm256_add_epi32(
6238 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6239 95410 : ymm_sum = GDALmm256_add_epi32(
6240 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6241 : }
6242 : }
6243 :
6244 : if constexpr (COMPUTE_OTHER_STATS)
6245 : {
6246 : GUInt32 anSum[8];
6247 400 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6248 : ymm_sum);
6249 400 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6250 400 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6251 400 : anSum[6] + anSum[7];
6252 : }
6253 : }
6254 :
6255 1674 : if (bComputeMinMax)
6256 : {
6257 : GUInt16 anMin[16];
6258 : GUInt16 anMax[16];
6259 :
6260 : // Unshift the result
6261 1633 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6262 1633 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6263 1633 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6264 : ymm_min);
6265 1633 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6266 : ymm_max);
6267 27761 : for (int j = 0; j < 16; j++)
6268 : {
6269 26128 : if (anMin[j] < nMin)
6270 342 : nMin = anMin[j];
6271 26128 : if (anMax[j] > nMax)
6272 482 : nMax = anMax[j];
6273 : }
6274 : }
6275 :
6276 : if constexpr (COMPUTE_OTHER_STATS)
6277 : {
6278 : GUIntBig anSumSquare[4];
6279 400 : GDALmm256_storeu_si256(
6280 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6281 400 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6282 : anSumSquare[3];
6283 :
6284 : // Unshift the sum of squares
6285 400 : UnshiftSumSquare(nSumSquare, nSumThis,
6286 : static_cast<GUIntBig>(i));
6287 :
6288 400 : nSum += nSumThis;
6289 :
6290 722 : for (; i < nBlockPixels; i++)
6291 : {
6292 322 : const GUInt32 nValue = pData[i];
6293 322 : if (nValue < nMin)
6294 1 : nMin = nValue;
6295 322 : if (nValue > nMax)
6296 1 : nMax = nValue;
6297 322 : nSum += nValue;
6298 322 : nSumSquare +=
6299 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6300 322 : nValue;
6301 : }
6302 :
6303 400 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6304 400 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6305 1674 : }
6306 : }
6307 : else
6308 : {
6309 208 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6310 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6311 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6312 : }
6313 1882 : }
6314 : };
6315 :
6316 : #endif
6317 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6318 : // defined(_MSC_VER))
6319 :
6320 : /************************************************************************/
6321 : /* GetPixelValue() */
6322 : /************************************************************************/
6323 :
6324 23815700 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6325 : const void *pData, GPtrDiff_t iOffset,
6326 : const GDALNoDataValues &sNoDataValues,
6327 : bool &bValid)
6328 : {
6329 23815700 : bValid = true;
6330 23815700 : double dfValue = 0;
6331 23815700 : switch (eDataType)
6332 : {
6333 1413690 : case GDT_Byte:
6334 : {
6335 1413690 : if (bSignedByte)
6336 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6337 : else
6338 1413500 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6339 1413690 : break;
6340 : }
6341 10409 : case GDT_Int8:
6342 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6343 10409 : break;
6344 200608 : case GDT_UInt16:
6345 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6346 200608 : break;
6347 60193 : case GDT_Int16:
6348 60193 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6349 60193 : break;
6350 27600 : case GDT_UInt32:
6351 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6352 27600 : break;
6353 455610 : case GDT_Int32:
6354 455610 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6355 455610 : break;
6356 2604 : case GDT_UInt64:
6357 2604 : dfValue = static_cast<double>(
6358 2604 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6359 2604 : break;
6360 7404 : case GDT_Int64:
6361 7404 : dfValue = static_cast<double>(
6362 7404 : static_cast<const std::int64_t *>(pData)[iOffset]);
6363 7404 : break;
6364 0 : case GDT_Float16:
6365 : {
6366 : using namespace std;
6367 0 : const GFloat16 hfValue =
6368 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6369 0 : if (isnan(hfValue) ||
6370 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6371 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6372 : {
6373 0 : bValid = false;
6374 0 : return 0.0;
6375 : }
6376 0 : dfValue = hfValue;
6377 0 : return dfValue;
6378 : }
6379 17931500 : case GDT_Float32:
6380 : {
6381 17931500 : const float fValue = static_cast<const float *>(pData)[iOffset];
6382 35836200 : if (std::isnan(fValue) ||
6383 31039800 : (sNoDataValues.bGotFloatNoDataValue &&
6384 13135100 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6385 : {
6386 26881 : bValid = false;
6387 26881 : return 0.0;
6388 : }
6389 17904700 : dfValue = fValue;
6390 17904700 : return dfValue;
6391 : }
6392 3688930 : case GDT_Float64:
6393 3688930 : dfValue = static_cast<const double *>(pData)[iOffset];
6394 3688930 : if (std::isnan(dfValue))
6395 : {
6396 52 : bValid = false;
6397 52 : return 0.0;
6398 : }
6399 3688880 : break;
6400 2692 : case GDT_CInt16:
6401 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6402 2692 : break;
6403 2692 : case GDT_CInt32:
6404 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6405 2692 : break;
6406 0 : case GDT_CFloat16:
6407 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6408 0 : if (std::isnan(dfValue))
6409 : {
6410 0 : bValid = false;
6411 0 : return 0.0;
6412 : }
6413 0 : break;
6414 5812 : case GDT_CFloat32:
6415 5812 : dfValue = static_cast<const float *>(pData)[iOffset * 2];
6416 5812 : if (std::isnan(dfValue))
6417 : {
6418 0 : bValid = false;
6419 0 : return 0.0;
6420 : }
6421 5812 : break;
6422 5892 : case GDT_CFloat64:
6423 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6424 5892 : if (std::isnan(dfValue))
6425 : {
6426 0 : bValid = false;
6427 0 : return 0.0;
6428 : }
6429 5892 : break;
6430 0 : case GDT_Unknown:
6431 : case GDT_TypeCount:
6432 0 : CPLAssert(false);
6433 : break;
6434 : }
6435 :
6436 9624280 : if (sNoDataValues.bGotNoDataValue &&
6437 3740190 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6438 : {
6439 3346220 : bValid = false;
6440 3346220 : return 0.0;
6441 : }
6442 2537860 : return dfValue;
6443 : }
6444 :
6445 : /************************************************************************/
6446 : /* SetValidPercent() */
6447 : /************************************************************************/
6448 :
6449 : //! @cond Doxygen_Suppress
6450 : /**
6451 : * \brief Set percentage of valid (not nodata) pixels.
6452 : *
6453 : * Stores the percentage of valid pixels in the metadata item
6454 : * STATISTICS_VALID_PERCENT
6455 : *
6456 : * @param nSampleCount Number of sampled pixels.
6457 : *
6458 : * @param nValidCount Number of valid pixels.
6459 : */
6460 :
6461 495 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6462 : GUIntBig nValidCount)
6463 : {
6464 495 : if (nValidCount == 0)
6465 : {
6466 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6467 : }
6468 483 : else if (nValidCount == nSampleCount)
6469 : {
6470 436 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6471 : }
6472 : else /* nValidCount < nSampleCount */
6473 : {
6474 47 : char szValue[128] = {0};
6475 :
6476 : /* percentage is only an indicator: limit precision */
6477 47 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6478 47 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6479 :
6480 47 : if (EQUAL(szValue, "100"))
6481 : {
6482 : /* don't set 100 percent valid
6483 : * because some of the sampled pixels were nodata */
6484 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6485 : }
6486 : else
6487 : {
6488 47 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6489 : }
6490 : }
6491 495 : }
6492 :
6493 : //! @endcond
6494 :
6495 : /************************************************************************/
6496 : /* ComputeStatistics() */
6497 : /************************************************************************/
6498 :
6499 : /**
6500 : * \brief Compute image statistics.
6501 : *
6502 : * Returns the minimum, maximum, mean and standard deviation of all
6503 : * pixel values in this band. If approximate statistics are sufficient,
6504 : * the bApproxOK flag can be set to true in which case overviews, or a
6505 : * subset of image tiles may be used in computing the statistics.
6506 : *
6507 : * Once computed, the statistics will generally be "set" back on the
6508 : * raster band using SetStatistics().
6509 : *
6510 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6511 : *
6512 : * This method is the same as the C function GDALComputeRasterStatistics().
6513 : *
6514 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6515 : * or a subset of all tiles.
6516 : *
6517 : * @param pdfMin Location into which to load image minimum (may be NULL).
6518 : *
6519 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6520 : *
6521 : * @param pdfMean Location into which to load image mean (may be NULL).
6522 : *
6523 : * @param pdfStdDev Location into which to load image standard deviation
6524 : * (may be NULL).
6525 : *
6526 : * @param pfnProgress a function to call to report progress, or NULL.
6527 : *
6528 : * @param pProgressData application data to pass to the progress function.
6529 : *
6530 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6531 : * is terminated by the user.
6532 : */
6533 :
6534 473 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6535 : double *pdfMax, double *pdfMean,
6536 : double *pdfStdDev,
6537 : GDALProgressFunc pfnProgress,
6538 : void *pProgressData)
6539 :
6540 : {
6541 473 : if (pfnProgress == nullptr)
6542 171 : pfnProgress = GDALDummyProgress;
6543 :
6544 : /* -------------------------------------------------------------------- */
6545 : /* If we have overview bands, use them for statistics. */
6546 : /* -------------------------------------------------------------------- */
6547 473 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6548 : {
6549 : GDALRasterBand *poBand =
6550 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6551 :
6552 3 : if (poBand != this)
6553 : {
6554 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6555 : pdfMean, pdfStdDev,
6556 3 : pfnProgress, pProgressData);
6557 3 : if (eErr == CE_None)
6558 : {
6559 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6560 : {
6561 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6562 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6563 : }
6564 :
6565 : /* transfer metadata from overview band to this */
6566 : const char *pszPercentValid =
6567 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6568 :
6569 3 : if (pszPercentValid != nullptr)
6570 : {
6571 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6572 3 : pszPercentValid);
6573 : }
6574 : }
6575 3 : return eErr;
6576 : }
6577 : }
6578 :
6579 470 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6580 : {
6581 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6582 0 : return CE_Failure;
6583 : }
6584 :
6585 : /* -------------------------------------------------------------------- */
6586 : /* Read actual data and compute statistics. */
6587 : /* -------------------------------------------------------------------- */
6588 : // Using Welford algorithm:
6589 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6590 : // to compute standard deviation in a more numerically robust way than
6591 : // the difference of the sum of square values with the square of the sum.
6592 : // dfMean and dfM2 are updated at each sample.
6593 : // dfM2 is the sum of square of differences to the current mean.
6594 470 : double dfMin = std::numeric_limits<double>::infinity();
6595 470 : double dfMax = -std::numeric_limits<double>::infinity();
6596 470 : double dfMean = 0.0;
6597 470 : double dfM2 = 0.0;
6598 :
6599 : GDALRasterIOExtraArg sExtraArg;
6600 470 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6601 :
6602 470 : GDALNoDataValues sNoDataValues(this, eDataType);
6603 470 : GDALRasterBand *poMaskBand = nullptr;
6604 470 : if (!sNoDataValues.bGotNoDataValue)
6605 : {
6606 443 : const int l_nMaskFlags = GetMaskFlags();
6607 488 : if (l_nMaskFlags != GMF_ALL_VALID &&
6608 45 : GetColorInterpretation() != GCI_AlphaBand)
6609 : {
6610 45 : poMaskBand = GetMaskBand();
6611 : }
6612 : }
6613 :
6614 470 : bool bSignedByte = false;
6615 470 : if (eDataType == GDT_Byte)
6616 : {
6617 203 : EnablePixelTypeSignedByteWarning(false);
6618 : const char *pszPixelType =
6619 203 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6620 203 : EnablePixelTypeSignedByteWarning(true);
6621 203 : bSignedByte =
6622 203 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6623 : }
6624 :
6625 470 : GUIntBig nSampleCount = 0;
6626 470 : GUIntBig nValidCount = 0;
6627 :
6628 470 : if (bApproxOK && HasArbitraryOverviews())
6629 : {
6630 : /* --------------------------------------------------------------------
6631 : */
6632 : /* Figure out how much the image should be reduced to get an */
6633 : /* approximate value. */
6634 : /* --------------------------------------------------------------------
6635 : */
6636 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6637 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6638 :
6639 0 : int nXReduced = nRasterXSize;
6640 0 : int nYReduced = nRasterYSize;
6641 0 : if (dfReduction > 1.0)
6642 : {
6643 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6644 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6645 :
6646 : // Catch the case of huge resizing ratios here
6647 0 : if (nXReduced == 0)
6648 0 : nXReduced = 1;
6649 0 : if (nYReduced == 0)
6650 0 : nYReduced = 1;
6651 : }
6652 :
6653 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6654 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6655 :
6656 : const CPLErr eErr =
6657 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6658 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6659 0 : if (eErr != CE_None)
6660 : {
6661 0 : CPLFree(pData);
6662 0 : return eErr;
6663 : }
6664 :
6665 0 : GByte *pabyMaskData = nullptr;
6666 0 : if (poMaskBand)
6667 : {
6668 : pabyMaskData =
6669 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6670 0 : if (!pabyMaskData)
6671 : {
6672 0 : CPLFree(pData);
6673 0 : return CE_Failure;
6674 : }
6675 :
6676 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6677 : pabyMaskData, nXReduced, nYReduced,
6678 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6679 : {
6680 0 : CPLFree(pData);
6681 0 : CPLFree(pabyMaskData);
6682 0 : return CE_Failure;
6683 : }
6684 : }
6685 :
6686 : /* this isn't the fastest way to do this, but is easier for now */
6687 0 : for (int iY = 0; iY < nYReduced; iY++)
6688 : {
6689 0 : for (int iX = 0; iX < nXReduced; iX++)
6690 : {
6691 0 : const int iOffset = iX + iY * nXReduced;
6692 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6693 0 : continue;
6694 :
6695 0 : bool bValid = true;
6696 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6697 0 : iOffset, sNoDataValues, bValid);
6698 0 : if (!bValid)
6699 0 : continue;
6700 :
6701 0 : dfMin = std::min(dfMin, dfValue);
6702 0 : dfMax = std::max(dfMax, dfValue);
6703 :
6704 0 : nValidCount++;
6705 0 : if (dfMin == dfMax)
6706 : {
6707 0 : if (nValidCount == 1)
6708 0 : dfMean = dfMin;
6709 : }
6710 : else
6711 : {
6712 0 : const double dfDelta = dfValue - dfMean;
6713 0 : dfMean += dfDelta / nValidCount;
6714 0 : dfM2 += dfDelta * (dfValue - dfMean);
6715 : }
6716 : }
6717 : }
6718 :
6719 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6720 :
6721 0 : CPLFree(pData);
6722 0 : CPLFree(pabyMaskData);
6723 : }
6724 :
6725 : else // No arbitrary overviews.
6726 : {
6727 470 : if (!InitBlockInfo())
6728 0 : return CE_Failure;
6729 :
6730 : /* --------------------------------------------------------------------
6731 : */
6732 : /* Figure out the ratio of blocks we will read to get an */
6733 : /* approximate value. */
6734 : /* --------------------------------------------------------------------
6735 : */
6736 470 : int nSampleRate = 1;
6737 470 : if (bApproxOK)
6738 : {
6739 43 : nSampleRate = static_cast<int>(std::max(
6740 86 : 1.0,
6741 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6742 : // We want to avoid probing only the first column of blocks for
6743 : // a square shaped raster, because it is not unlikely that it may
6744 : // be padding only (#6378)
6745 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6746 1 : nSampleRate += 1;
6747 : }
6748 470 : if (nSampleRate == 1)
6749 436 : bApproxOK = false;
6750 :
6751 : // Particular case for GDT_Byte that only use integral types for all
6752 : // intermediate computations. Only possible if the number of pixels
6753 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6754 : // can fit on a uint64. Should be 99.99999% of cases.
6755 : // For GUInt16, this limits to raster of 4 giga pixels
6756 470 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6757 185 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6758 185 : nSampleRate <
6759 185 : GUINTBIG_MAX / (255U * 255U) /
6760 185 : (static_cast<GUInt64>(nBlockXSize) *
6761 185 : static_cast<GUInt64>(nBlockYSize))) ||
6762 285 : (eDataType == GDT_UInt16 &&
6763 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6764 29 : nSampleRate <
6765 29 : GUINTBIG_MAX / (65535U * 65535U) /
6766 29 : (static_cast<GUInt64>(nBlockXSize) *
6767 29 : static_cast<GUInt64>(nBlockYSize))))
6768 : {
6769 214 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6770 214 : GUInt32 nMin = nMaxValueType;
6771 214 : GUInt32 nMax = 0;
6772 214 : GUIntBig nSum = 0;
6773 214 : GUIntBig nSumSquare = 0;
6774 : // If no valid nodata, map to invalid value (256 for Byte)
6775 214 : const GUInt32 nNoDataValue =
6776 237 : (sNoDataValues.bGotNoDataValue &&
6777 23 : sNoDataValues.dfNoDataValue >= 0 &&
6778 23 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6779 23 : fabs(sNoDataValues.dfNoDataValue -
6780 23 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6781 : 1e-10)) < 1e-10)
6782 237 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6783 : : nMaxValueType + 1;
6784 :
6785 214 : for (GIntBig iSampleBlock = 0;
6786 12741 : iSampleBlock <
6787 12741 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6788 12527 : iSampleBlock += nSampleRate)
6789 : {
6790 12527 : const int iYBlock =
6791 12527 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6792 12527 : const int iXBlock =
6793 12527 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6794 :
6795 : GDALRasterBlock *const poBlock =
6796 12527 : GetLockedBlockRef(iXBlock, iYBlock);
6797 12527 : if (poBlock == nullptr)
6798 0 : return CE_Failure;
6799 :
6800 12527 : void *const pData = poBlock->GetDataRef();
6801 :
6802 12527 : int nXCheck = 0, nYCheck = 0;
6803 12527 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6804 :
6805 12527 : if (eDataType == GDT_Byte)
6806 : {
6807 : ComputeStatisticsInternal<
6808 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6809 12057 : f(nXCheck, nBlockXSize, nYCheck,
6810 : static_cast<const GByte *>(pData),
6811 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6812 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6813 : }
6814 : else
6815 : {
6816 : ComputeStatisticsInternal<
6817 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6818 470 : f(nXCheck, nBlockXSize, nYCheck,
6819 : static_cast<const GUInt16 *>(pData),
6820 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6821 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6822 : }
6823 :
6824 12527 : poBlock->DropLock();
6825 :
6826 12527 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6827 12527 : (static_cast<double>(nBlocksPerRow) *
6828 12527 : nBlocksPerColumn),
6829 : "Compute Statistics", pProgressData))
6830 : {
6831 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6832 : "User terminated");
6833 0 : return CE_Failure;
6834 : }
6835 : }
6836 :
6837 214 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6838 : {
6839 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6840 0 : return CE_Failure;
6841 : }
6842 :
6843 : /* --------------------------------------------------------------------
6844 : */
6845 : /* Save computed information. */
6846 : /* --------------------------------------------------------------------
6847 : */
6848 214 : if (nValidCount)
6849 205 : dfMean = static_cast<double>(nSum) / nValidCount;
6850 :
6851 : // To avoid potential precision issues when doing the difference,
6852 : // we need to do that computation on 128 bit rather than casting
6853 : // to double
6854 : const GDALUInt128 nTmpForStdDev(
6855 214 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6856 428 : GDALUInt128::Mul(nSum, nSum));
6857 : const double dfStdDev =
6858 214 : nValidCount > 0
6859 214 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6860 214 : : 0.0;
6861 :
6862 214 : if (nValidCount > 0)
6863 : {
6864 205 : if (bApproxOK)
6865 : {
6866 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6867 : }
6868 181 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6869 : {
6870 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6871 : }
6872 205 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6873 : }
6874 :
6875 214 : SetValidPercent(nSampleCount, nValidCount);
6876 :
6877 : /* --------------------------------------------------------------------
6878 : */
6879 : /* Record results. */
6880 : /* --------------------------------------------------------------------
6881 : */
6882 214 : if (pdfMin != nullptr)
6883 211 : *pdfMin = nValidCount ? nMin : 0;
6884 214 : if (pdfMax != nullptr)
6885 211 : *pdfMax = nValidCount ? nMax : 0;
6886 :
6887 214 : if (pdfMean != nullptr)
6888 207 : *pdfMean = dfMean;
6889 :
6890 214 : if (pdfStdDev != nullptr)
6891 207 : *pdfStdDev = dfStdDev;
6892 :
6893 214 : if (nValidCount > 0)
6894 205 : return CE_None;
6895 :
6896 9 : ReportError(CE_Failure, CPLE_AppDefined,
6897 : "Failed to compute statistics, no valid pixels found "
6898 : "in sampling.");
6899 9 : return CE_Failure;
6900 : }
6901 :
6902 256 : GByte *pabyMaskData = nullptr;
6903 256 : if (poMaskBand)
6904 : {
6905 : pabyMaskData = static_cast<GByte *>(
6906 45 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6907 45 : if (!pabyMaskData)
6908 : {
6909 0 : return CE_Failure;
6910 : }
6911 : }
6912 :
6913 256 : for (GIntBig iSampleBlock = 0;
6914 5891 : iSampleBlock <
6915 5891 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6916 5635 : iSampleBlock += nSampleRate)
6917 : {
6918 5635 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6919 5635 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6920 :
6921 5635 : int nXCheck = 0, nYCheck = 0;
6922 5635 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6923 :
6924 6220 : if (poMaskBand &&
6925 585 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6926 585 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6927 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6928 585 : 0, nBlockXSize, nullptr) != CE_None)
6929 : {
6930 0 : CPLFree(pabyMaskData);
6931 0 : return CE_Failure;
6932 : }
6933 :
6934 : GDALRasterBlock *const poBlock =
6935 5635 : GetLockedBlockRef(iXBlock, iYBlock);
6936 5635 : if (poBlock == nullptr)
6937 : {
6938 0 : CPLFree(pabyMaskData);
6939 0 : return CE_Failure;
6940 : }
6941 :
6942 5635 : void *const pData = poBlock->GetDataRef();
6943 :
6944 : // This isn't the fastest way to do this, but is easier for now.
6945 13494 : for (int iY = 0; iY < nYCheck; iY++)
6946 : {
6947 4891200 : for (int iX = 0; iX < nXCheck; iX++)
6948 : {
6949 4883340 : const GPtrDiff_t iOffset =
6950 4883340 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6951 4883340 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6952 111829 : continue;
6953 :
6954 4779080 : bool bValid = true;
6955 : double dfValue =
6956 4779080 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6957 4779080 : sNoDataValues, bValid);
6958 :
6959 4779080 : if (!bValid)
6960 7574 : continue;
6961 :
6962 4771510 : dfMin = std::min(dfMin, dfValue);
6963 4771510 : dfMax = std::max(dfMax, dfValue);
6964 :
6965 4771510 : nValidCount++;
6966 4771510 : if (dfMin == dfMax)
6967 : {
6968 2173320 : if (nValidCount == 1)
6969 255 : dfMean = dfMin;
6970 : }
6971 : else
6972 : {
6973 2598180 : const double dfDelta = dfValue - dfMean;
6974 2598180 : dfMean += dfDelta / nValidCount;
6975 2598180 : dfM2 += dfDelta * (dfValue - dfMean);
6976 : }
6977 : }
6978 : }
6979 :
6980 5635 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6981 :
6982 5635 : poBlock->DropLock();
6983 :
6984 5635 : if (!pfnProgress(
6985 5635 : static_cast<double>(iSampleBlock) /
6986 5635 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6987 : "Compute Statistics", pProgressData))
6988 : {
6989 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6990 0 : CPLFree(pabyMaskData);
6991 0 : return CE_Failure;
6992 : }
6993 : }
6994 :
6995 256 : CPLFree(pabyMaskData);
6996 : }
6997 :
6998 256 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6999 : {
7000 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7001 0 : return CE_Failure;
7002 : }
7003 :
7004 : /* -------------------------------------------------------------------- */
7005 : /* Save computed information. */
7006 : /* -------------------------------------------------------------------- */
7007 256 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7008 :
7009 256 : if (nValidCount > 0)
7010 : {
7011 255 : if (bApproxOK)
7012 : {
7013 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7014 : }
7015 247 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7016 : {
7017 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7018 : }
7019 255 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7020 : }
7021 : else
7022 : {
7023 1 : dfMin = 0.0;
7024 1 : dfMax = 0.0;
7025 : }
7026 :
7027 256 : SetValidPercent(nSampleCount, nValidCount);
7028 :
7029 : /* -------------------------------------------------------------------- */
7030 : /* Record results. */
7031 : /* -------------------------------------------------------------------- */
7032 256 : if (pdfMin != nullptr)
7033 253 : *pdfMin = dfMin;
7034 256 : if (pdfMax != nullptr)
7035 253 : *pdfMax = dfMax;
7036 :
7037 256 : if (pdfMean != nullptr)
7038 250 : *pdfMean = dfMean;
7039 :
7040 256 : if (pdfStdDev != nullptr)
7041 250 : *pdfStdDev = dfStdDev;
7042 :
7043 256 : if (nValidCount > 0)
7044 255 : return CE_None;
7045 :
7046 1 : ReportError(
7047 : CE_Failure, CPLE_AppDefined,
7048 : "Failed to compute statistics, no valid pixels found in sampling.");
7049 1 : return CE_Failure;
7050 : }
7051 :
7052 : /************************************************************************/
7053 : /* GDALComputeRasterStatistics() */
7054 : /************************************************************************/
7055 :
7056 : /**
7057 : * \brief Compute image statistics.
7058 : *
7059 : * @see GDALRasterBand::ComputeStatistics()
7060 : */
7061 :
7062 157 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7063 : int bApproxOK, double *pdfMin,
7064 : double *pdfMax, double *pdfMean,
7065 : double *pdfStdDev,
7066 : GDALProgressFunc pfnProgress,
7067 : void *pProgressData)
7068 :
7069 : {
7070 157 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7071 :
7072 157 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7073 :
7074 157 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7075 157 : pdfStdDev, pfnProgress, pProgressData);
7076 : }
7077 :
7078 : /************************************************************************/
7079 : /* SetStatistics() */
7080 : /************************************************************************/
7081 :
7082 : /**
7083 : * \brief Set statistics on band.
7084 : *
7085 : * This method can be used to store min/max/mean/standard deviation
7086 : * statistics on a raster band.
7087 : *
7088 : * The default implementation stores them as metadata, and will only work
7089 : * on formats that can save arbitrary metadata. This method cannot detect
7090 : * whether metadata will be properly saved and so may return CE_None even
7091 : * if the statistics will never be saved.
7092 : *
7093 : * This method is the same as the C function GDALSetRasterStatistics().
7094 : *
7095 : * @param dfMin minimum pixel value.
7096 : *
7097 : * @param dfMax maximum pixel value.
7098 : *
7099 : * @param dfMean mean (average) of all pixel values.
7100 : *
7101 : * @param dfStdDev Standard deviation of all pixel values.
7102 : *
7103 : * @return CE_None on success or CE_Failure on failure.
7104 : */
7105 :
7106 493 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7107 : double dfStdDev)
7108 :
7109 : {
7110 493 : char szValue[128] = {0};
7111 :
7112 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7113 493 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7114 :
7115 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7116 493 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7117 :
7118 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7119 493 : SetMetadataItem("STATISTICS_MEAN", szValue);
7120 :
7121 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7122 493 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7123 :
7124 493 : return CE_None;
7125 : }
7126 :
7127 : /************************************************************************/
7128 : /* GDALSetRasterStatistics() */
7129 : /************************************************************************/
7130 :
7131 : /**
7132 : * \brief Set statistics on band.
7133 : *
7134 : * @see GDALRasterBand::SetStatistics()
7135 : */
7136 :
7137 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7138 : double dfMax, double dfMean,
7139 : double dfStdDev)
7140 :
7141 : {
7142 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7143 :
7144 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7145 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7146 : }
7147 :
7148 : /************************************************************************/
7149 : /* ComputeRasterMinMax() */
7150 : /************************************************************************/
7151 :
7152 : template <class T, bool HAS_NODATA>
7153 120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7154 : T *pMax)
7155 : {
7156 120175 : T min0 = *pMin;
7157 120175 : T max0 = *pMax;
7158 120175 : T min1 = *pMin;
7159 120175 : T max1 = *pMax;
7160 : size_t i;
7161 214453 : for (i = 0; i + 1 < nElts; i += 2)
7162 : {
7163 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7164 : {
7165 94278 : min0 = std::min(min0, buffer[i]);
7166 94278 : max0 = std::max(max0, buffer[i]);
7167 : }
7168 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7169 : {
7170 94278 : min1 = std::min(min1, buffer[i + 1]);
7171 94278 : max1 = std::max(max1, buffer[i + 1]);
7172 : }
7173 : }
7174 120175 : T min = std::min(min0, min1);
7175 120175 : T max = std::max(max0, max1);
7176 120175 : if (i < nElts)
7177 : {
7178 118460 : if (!HAS_NODATA || buffer[i] != nodataValue)
7179 : {
7180 118480 : min = std::min(min, buffer[i]);
7181 118480 : max = std::max(max, buffer[i]);
7182 : }
7183 : }
7184 120175 : *pMin = min;
7185 120175 : *pMax = max;
7186 120175 : }
7187 :
7188 : template <GDALDataType eDataType, bool bSignedByte>
7189 : static void
7190 12191 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7191 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7192 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7193 : {
7194 12191 : double dfLocalMin = dfMin;
7195 12191 : double dfLocalMax = dfMax;
7196 :
7197 42531 : for (int iY = 0; iY < nYCheck; iY++)
7198 : {
7199 19161629 : for (int iX = 0; iX < nXCheck; iX++)
7200 : {
7201 19131303 : const GPtrDiff_t iOffset =
7202 19131303 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7203 19131303 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7204 3460312 : continue;
7205 19036560 : bool bValid = true;
7206 19036560 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7207 : iOffset, sNoDataValues, bValid);
7208 19036560 : if (!bValid)
7209 3365580 : continue;
7210 :
7211 15670953 : dfLocalMin = std::min(dfLocalMin, dfValue);
7212 15670953 : dfLocalMax = std::max(dfLocalMax, dfValue);
7213 : }
7214 : }
7215 :
7216 12191 : dfMin = dfLocalMin;
7217 12191 : dfMax = dfLocalMax;
7218 12191 : }
7219 :
7220 12191 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7221 : bool bSignedByte, int nXCheck, int nYCheck,
7222 : int nBlockXSize,
7223 : const GDALNoDataValues &sNoDataValues,
7224 : const GByte *pabyMaskData, double &dfMin,
7225 : double &dfMax)
7226 : {
7227 12191 : switch (eDataType)
7228 : {
7229 0 : case GDT_Unknown:
7230 0 : CPLAssert(false);
7231 : break;
7232 672 : case GDT_Byte:
7233 672 : if (bSignedByte)
7234 : {
7235 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7236 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7237 : pabyMaskData, dfMin, dfMax);
7238 : }
7239 : else
7240 : {
7241 669 : ComputeMinMaxGeneric<GDT_Byte, false>(
7242 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7243 : pabyMaskData, dfMin, dfMax);
7244 : }
7245 672 : break;
7246 106 : case GDT_Int8:
7247 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7248 : nBlockXSize, sNoDataValues,
7249 : pabyMaskData, dfMin, dfMax);
7250 106 : break;
7251 968 : case GDT_UInt16:
7252 968 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7253 : nBlockXSize, sNoDataValues,
7254 : pabyMaskData, dfMin, dfMax);
7255 968 : break;
7256 1 : case GDT_Int16:
7257 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7258 : nBlockXSize, sNoDataValues,
7259 : pabyMaskData, dfMin, dfMax);
7260 1 : break;
7261 201 : case GDT_UInt32:
7262 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7263 : nBlockXSize, sNoDataValues,
7264 : pabyMaskData, dfMin, dfMax);
7265 201 : break;
7266 1048 : case GDT_Int32:
7267 1048 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7268 : nBlockXSize, sNoDataValues,
7269 : pabyMaskData, dfMin, dfMax);
7270 1048 : break;
7271 17 : case GDT_UInt64:
7272 17 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7273 : nBlockXSize, sNoDataValues,
7274 : pabyMaskData, dfMin, dfMax);
7275 17 : break;
7276 29 : case GDT_Int64:
7277 29 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7278 : nBlockXSize, sNoDataValues,
7279 : pabyMaskData, dfMin, dfMax);
7280 29 : break;
7281 0 : case GDT_Float16:
7282 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7283 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7284 : pabyMaskData, dfMin, dfMax);
7285 0 : break;
7286 5552 : case GDT_Float32:
7287 5552 : ComputeMinMaxGeneric<GDT_Float32, false>(
7288 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7289 : pabyMaskData, dfMin, dfMax);
7290 5552 : break;
7291 3487 : case GDT_Float64:
7292 3487 : ComputeMinMaxGeneric<GDT_Float64, false>(
7293 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7294 : pabyMaskData, dfMin, dfMax);
7295 3487 : break;
7296 9 : case GDT_CInt16:
7297 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7298 : nBlockXSize, sNoDataValues,
7299 : pabyMaskData, dfMin, dfMax);
7300 9 : break;
7301 9 : case GDT_CInt32:
7302 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7303 : nBlockXSize, sNoDataValues,
7304 : pabyMaskData, dfMin, dfMax);
7305 9 : break;
7306 0 : case GDT_CFloat16:
7307 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7308 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7309 : pabyMaskData, dfMin, dfMax);
7310 0 : break;
7311 75 : case GDT_CFloat32:
7312 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7313 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7314 : pabyMaskData, dfMin, dfMax);
7315 75 : break;
7316 17 : case GDT_CFloat64:
7317 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7318 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7319 : pabyMaskData, dfMin, dfMax);
7320 17 : break;
7321 0 : case GDT_TypeCount:
7322 0 : CPLAssert(false);
7323 : break;
7324 : }
7325 12191 : }
7326 :
7327 775 : static bool ComputeMinMaxGenericIterBlocks(
7328 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7329 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7330 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7331 : double &dfMin, double &dfMax)
7332 :
7333 : {
7334 775 : GByte *pabyMaskData = nullptr;
7335 : int nBlockXSize, nBlockYSize;
7336 775 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7337 :
7338 775 : if (poMaskBand)
7339 : {
7340 : pabyMaskData =
7341 109 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7342 109 : if (!pabyMaskData)
7343 : {
7344 0 : return false;
7345 : }
7346 : }
7347 :
7348 12966 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7349 12191 : iSampleBlock += nSampleRate)
7350 : {
7351 12191 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7352 12191 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7353 :
7354 12191 : int nXCheck = 0, nYCheck = 0;
7355 12191 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7356 :
7357 18691 : if (poMaskBand &&
7358 6500 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7359 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7360 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7361 : nBlockXSize, nullptr) != CE_None)
7362 : {
7363 0 : CPLFree(pabyMaskData);
7364 0 : return false;
7365 : }
7366 :
7367 12191 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7368 12191 : if (poBlock == nullptr)
7369 : {
7370 0 : CPLFree(pabyMaskData);
7371 0 : return false;
7372 : }
7373 :
7374 12191 : void *const pData = poBlock->GetDataRef();
7375 :
7376 12191 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7377 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7378 : dfMax);
7379 :
7380 12191 : poBlock->DropLock();
7381 : }
7382 :
7383 775 : CPLFree(pabyMaskData);
7384 775 : return true;
7385 : }
7386 :
7387 : /**
7388 : * \brief Compute the min/max values for a band.
7389 : *
7390 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7391 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7392 : * get an approximate min/max. If the band has a nodata value it will
7393 : * be excluded from the minimum and maximum.
7394 : *
7395 : * If bApprox is FALSE, then all pixels will be read and used to compute
7396 : * an exact range.
7397 : *
7398 : * This method is the same as the C function GDALComputeRasterMinMax().
7399 : *
7400 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7401 : * FALSE.
7402 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7403 : * maximum (adfMinMax[1]) are returned.
7404 : *
7405 : * @return CE_None on success or CE_Failure on failure.
7406 : */
7407 :
7408 1766 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7409 : {
7410 : /* -------------------------------------------------------------------- */
7411 : /* Does the driver already know the min/max? */
7412 : /* -------------------------------------------------------------------- */
7413 1766 : if (bApproxOK)
7414 : {
7415 23 : int bSuccessMin = FALSE;
7416 23 : int bSuccessMax = FALSE;
7417 :
7418 23 : double dfMin = GetMinimum(&bSuccessMin);
7419 23 : double dfMax = GetMaximum(&bSuccessMax);
7420 :
7421 23 : if (bSuccessMin && bSuccessMax)
7422 : {
7423 1 : adfMinMax[0] = dfMin;
7424 1 : adfMinMax[1] = dfMax;
7425 1 : return CE_None;
7426 : }
7427 : }
7428 :
7429 : /* -------------------------------------------------------------------- */
7430 : /* If we have overview bands, use them for min/max. */
7431 : /* -------------------------------------------------------------------- */
7432 : // cppcheck-suppress knownConditionTrueFalse
7433 1765 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7434 : {
7435 : GDALRasterBand *poBand =
7436 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7437 :
7438 0 : if (poBand != this)
7439 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7440 : }
7441 :
7442 : /* -------------------------------------------------------------------- */
7443 : /* Read actual data and compute minimum and maximum. */
7444 : /* -------------------------------------------------------------------- */
7445 1765 : GDALNoDataValues sNoDataValues(this, eDataType);
7446 1765 : GDALRasterBand *poMaskBand = nullptr;
7447 1765 : if (!sNoDataValues.bGotNoDataValue)
7448 : {
7449 1516 : const int l_nMaskFlags = GetMaskFlags();
7450 1625 : if (l_nMaskFlags != GMF_ALL_VALID &&
7451 109 : GetColorInterpretation() != GCI_AlphaBand)
7452 : {
7453 109 : poMaskBand = GetMaskBand();
7454 : }
7455 : }
7456 :
7457 1765 : bool bSignedByte = false;
7458 1765 : if (eDataType == GDT_Byte)
7459 : {
7460 779 : EnablePixelTypeSignedByteWarning(false);
7461 : const char *pszPixelType =
7462 779 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7463 779 : EnablePixelTypeSignedByteWarning(true);
7464 779 : bSignedByte =
7465 779 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7466 : }
7467 :
7468 : GDALRasterIOExtraArg sExtraArg;
7469 1765 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7470 :
7471 3530 : GUInt32 nMin = (eDataType == GDT_Byte)
7472 1765 : ? 255
7473 : : 65535; // used for GByte & GUInt16 cases
7474 1765 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7475 1765 : GInt16 nMinInt16 =
7476 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7477 1765 : GInt16 nMaxInt16 =
7478 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7479 1765 : double dfMin =
7480 : std::numeric_limits<double>::infinity(); // used for generic code path
7481 1765 : double dfMax =
7482 : -std::numeric_limits<double>::infinity(); // used for generic code path
7483 1765 : const bool bUseOptimizedPath =
7484 2673 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7485 908 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7486 :
7487 : const auto ComputeMinMaxForBlock =
7488 20911 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7489 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7490 242393 : int nYCheck)
7491 : {
7492 20911 : if (eDataType == GDT_Byte && !bSignedByte)
7493 : {
7494 : const bool bHasNoData =
7495 11561 : sNoDataValues.bGotNoDataValue &&
7496 29672 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7497 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7498 11561 : sNoDataValues.dfNoDataValue;
7499 18111 : const GUInt32 nNoDataValue =
7500 18111 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7501 : : 0;
7502 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7503 : ComputeStatisticsInternal<GByte,
7504 : /* COMPUTE_OTHER_STATS = */ false>::
7505 18111 : f(nXCheck, nBufferWidth, nYCheck,
7506 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7507 18111 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7508 : }
7509 2800 : else if (eDataType == GDT_UInt16)
7510 : {
7511 : const bool bHasNoData =
7512 83 : sNoDataValues.bGotNoDataValue &&
7513 1495 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7514 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7515 83 : sNoDataValues.dfNoDataValue;
7516 1412 : const GUInt32 nNoDataValue =
7517 1412 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7518 : : 0;
7519 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7520 : ComputeStatisticsInternal<GUInt16,
7521 : /* COMPUTE_OTHER_STATS = */ false>::
7522 1412 : f(nXCheck, nBufferWidth, nYCheck,
7523 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7524 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7525 : }
7526 1388 : else if (eDataType == GDT_Int16)
7527 : {
7528 : const bool bHasNoData =
7529 1214 : sNoDataValues.bGotNoDataValue &&
7530 2602 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7531 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7532 1214 : sNoDataValues.dfNoDataValue;
7533 1388 : if (bHasNoData)
7534 : {
7535 1214 : const int16_t nNoDataValue =
7536 1214 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7537 120117 : for (int iY = 0; iY < nYCheck; iY++)
7538 : {
7539 118903 : ComputeMinMax<int16_t, true>(
7540 118903 : static_cast<const int16_t *>(pData) +
7541 118903 : static_cast<size_t>(iY) * nBufferWidth,
7542 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7543 : }
7544 : }
7545 : else
7546 : {
7547 1446 : for (int iY = 0; iY < nYCheck; iY++)
7548 : {
7549 1272 : ComputeMinMax<int16_t, false>(
7550 1272 : static_cast<const int16_t *>(pData) +
7551 1272 : static_cast<size_t>(iY) * nBufferWidth,
7552 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7553 : }
7554 : }
7555 : }
7556 20911 : };
7557 :
7558 1765 : if (bApproxOK && HasArbitraryOverviews())
7559 : {
7560 : /* --------------------------------------------------------------------
7561 : */
7562 : /* Figure out how much the image should be reduced to get an */
7563 : /* approximate value. */
7564 : /* --------------------------------------------------------------------
7565 : */
7566 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7567 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7568 :
7569 0 : int nXReduced = nRasterXSize;
7570 0 : int nYReduced = nRasterYSize;
7571 0 : if (dfReduction > 1.0)
7572 : {
7573 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7574 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7575 :
7576 : // Catch the case of huge resizing ratios here
7577 0 : if (nXReduced == 0)
7578 0 : nXReduced = 1;
7579 0 : if (nYReduced == 0)
7580 0 : nYReduced = 1;
7581 : }
7582 :
7583 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7584 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7585 :
7586 : const CPLErr eErr =
7587 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7588 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7589 0 : if (eErr != CE_None)
7590 : {
7591 0 : CPLFree(pData);
7592 0 : return eErr;
7593 : }
7594 :
7595 0 : GByte *pabyMaskData = nullptr;
7596 0 : if (poMaskBand)
7597 : {
7598 : pabyMaskData =
7599 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7600 0 : if (!pabyMaskData)
7601 : {
7602 0 : CPLFree(pData);
7603 0 : return CE_Failure;
7604 : }
7605 :
7606 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7607 : pabyMaskData, nXReduced, nYReduced,
7608 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7609 : {
7610 0 : CPLFree(pData);
7611 0 : CPLFree(pabyMaskData);
7612 0 : return CE_Failure;
7613 : }
7614 : }
7615 :
7616 0 : if (bUseOptimizedPath)
7617 : {
7618 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7619 : }
7620 : else
7621 : {
7622 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7623 : nYReduced, nXReduced, sNoDataValues,
7624 : pabyMaskData, dfMin, dfMax);
7625 : }
7626 :
7627 0 : CPLFree(pData);
7628 0 : CPLFree(pabyMaskData);
7629 : }
7630 :
7631 : else // No arbitrary overviews
7632 : {
7633 1765 : if (!InitBlockInfo())
7634 0 : return CE_Failure;
7635 :
7636 : /* --------------------------------------------------------------------
7637 : */
7638 : /* Figure out the ratio of blocks we will read to get an */
7639 : /* approximate value. */
7640 : /* --------------------------------------------------------------------
7641 : */
7642 1765 : int nSampleRate = 1;
7643 :
7644 1765 : if (bApproxOK)
7645 : {
7646 22 : nSampleRate = static_cast<int>(std::max(
7647 44 : 1.0,
7648 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7649 : // We want to avoid probing only the first column of blocks for
7650 : // a square shaped raster, because it is not unlikely that it may
7651 : // be padding only (#6378).
7652 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7653 0 : nSampleRate += 1;
7654 : }
7655 :
7656 1765 : if (bUseOptimizedPath)
7657 : {
7658 990 : for (GIntBig iSampleBlock = 0;
7659 21823 : iSampleBlock <
7660 21823 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7661 20833 : iSampleBlock += nSampleRate)
7662 : {
7663 20912 : const int iYBlock =
7664 20912 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7665 20912 : const int iXBlock =
7666 20912 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7667 :
7668 20912 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7669 20912 : if (poBlock == nullptr)
7670 1 : return CE_Failure;
7671 :
7672 20911 : void *const pData = poBlock->GetDataRef();
7673 :
7674 20911 : int nXCheck = 0, nYCheck = 0;
7675 20911 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7676 :
7677 20911 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7678 :
7679 20911 : poBlock->DropLock();
7680 :
7681 20911 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7682 4110 : nMax == 255)
7683 78 : break;
7684 : }
7685 : }
7686 : else
7687 : {
7688 775 : const GIntBig nTotalBlocks =
7689 775 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7690 775 : if (!ComputeMinMaxGenericIterBlocks(
7691 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7692 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7693 : {
7694 0 : return CE_Failure;
7695 : }
7696 : }
7697 : }
7698 :
7699 1764 : if (bUseOptimizedPath)
7700 : {
7701 989 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7702 : {
7703 887 : dfMin = nMin;
7704 887 : dfMax = nMax;
7705 : }
7706 102 : else if (eDataType == GDT_Int16)
7707 : {
7708 102 : dfMin = nMinInt16;
7709 102 : dfMax = nMaxInt16;
7710 : }
7711 : }
7712 :
7713 1764 : if (dfMin > dfMax)
7714 : {
7715 9 : adfMinMax[0] = 0;
7716 9 : adfMinMax[1] = 0;
7717 9 : ReportError(
7718 : CE_Failure, CPLE_AppDefined,
7719 : "Failed to compute min/max, no valid pixels found in sampling.");
7720 9 : return CE_Failure;
7721 : }
7722 :
7723 1755 : adfMinMax[0] = dfMin;
7724 1755 : adfMinMax[1] = dfMax;
7725 :
7726 1755 : return CE_None;
7727 : }
7728 :
7729 : /************************************************************************/
7730 : /* GDALComputeRasterMinMax() */
7731 : /************************************************************************/
7732 :
7733 : /**
7734 : * \brief Compute the min/max values for a band.
7735 : *
7736 : * @see GDALRasterBand::ComputeRasterMinMax()
7737 : *
7738 : * @note Prior to GDAL 3.6, this function returned void
7739 : */
7740 :
7741 1615 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7742 : double adfMinMax[2])
7743 :
7744 : {
7745 1615 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7746 :
7747 1615 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7748 1615 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7749 : }
7750 :
7751 : /************************************************************************/
7752 : /* ComputeRasterMinMaxLocation() */
7753 : /************************************************************************/
7754 :
7755 : /**
7756 : * \brief Compute the min/max values for a band, and their location.
7757 : *
7758 : * Pixels whose value matches the nodata value or are masked by the mask
7759 : * band are ignored.
7760 : *
7761 : * If the minimum or maximum value is hit in several locations, it is not
7762 : * specified which one will be returned.
7763 : *
7764 : * @param[out] pdfMin Pointer to the minimum value.
7765 : * @param[out] pdfMax Pointer to the maximum value.
7766 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7767 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7768 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7769 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7770 : *
7771 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7772 : * CE_Failure in case of error.
7773 : *
7774 : * @since GDAL 3.11
7775 : */
7776 :
7777 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7778 : double *pdfMax, int *pnMinX,
7779 : int *pnMinY, int *pnMaxX,
7780 : int *pnMaxY)
7781 : {
7782 8 : int nMinX = -1;
7783 8 : int nMinY = -1;
7784 8 : int nMaxX = -1;
7785 8 : int nMaxY = -1;
7786 8 : double dfMin = std::numeric_limits<double>::infinity();
7787 8 : double dfMax = -std::numeric_limits<double>::infinity();
7788 8 : if (pdfMin)
7789 5 : *pdfMin = dfMin;
7790 8 : if (pdfMax)
7791 5 : *pdfMax = dfMax;
7792 8 : if (pnMinX)
7793 6 : *pnMinX = nMinX;
7794 8 : if (pnMinY)
7795 6 : *pnMinY = nMinY;
7796 8 : if (pnMaxX)
7797 6 : *pnMaxX = nMaxX;
7798 8 : if (pnMaxY)
7799 6 : *pnMaxY = nMaxY;
7800 :
7801 8 : if (GDALDataTypeIsComplex(eDataType))
7802 : {
7803 0 : CPLError(CE_Failure, CPLE_NotSupported,
7804 : "Complex data type not supported");
7805 0 : return CE_Failure;
7806 : }
7807 :
7808 8 : if (!InitBlockInfo())
7809 0 : return CE_Failure;
7810 :
7811 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7812 8 : GDALRasterBand *poMaskBand = nullptr;
7813 8 : if (!sNoDataValues.bGotNoDataValue)
7814 : {
7815 8 : const int l_nMaskFlags = GetMaskFlags();
7816 9 : if (l_nMaskFlags != GMF_ALL_VALID &&
7817 1 : GetColorInterpretation() != GCI_AlphaBand)
7818 : {
7819 1 : poMaskBand = GetMaskBand();
7820 : }
7821 : }
7822 :
7823 8 : bool bSignedByte = false;
7824 8 : if (eDataType == GDT_Byte)
7825 : {
7826 7 : EnablePixelTypeSignedByteWarning(false);
7827 : const char *pszPixelType =
7828 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7829 7 : EnablePixelTypeSignedByteWarning(true);
7830 7 : bSignedByte =
7831 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7832 : }
7833 :
7834 8 : GByte *pabyMaskData = nullptr;
7835 8 : if (poMaskBand)
7836 : {
7837 : pabyMaskData =
7838 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7839 1 : if (!pabyMaskData)
7840 : {
7841 0 : return CE_Failure;
7842 : }
7843 : }
7844 :
7845 8 : const GIntBig nTotalBlocks =
7846 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7847 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7848 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7849 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7850 : {
7851 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7852 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7853 :
7854 11 : int nXCheck = 0, nYCheck = 0;
7855 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7856 :
7857 13 : if (poMaskBand &&
7858 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7859 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7860 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7861 2 : nBlockXSize, nullptr) != CE_None)
7862 : {
7863 0 : CPLFree(pabyMaskData);
7864 0 : return CE_Failure;
7865 : }
7866 :
7867 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7868 11 : if (poBlock == nullptr)
7869 : {
7870 0 : CPLFree(pabyMaskData);
7871 0 : return CE_Failure;
7872 : }
7873 :
7874 11 : void *const pData = poBlock->GetDataRef();
7875 :
7876 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7877 : {
7878 4 : for (int iY = 0; iY < nYCheck; ++iY)
7879 : {
7880 6 : for (int iX = 0; iX < nXCheck; ++iX)
7881 : {
7882 4 : const GPtrDiff_t iOffset =
7883 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7884 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7885 2 : continue;
7886 2 : bool bValid = true;
7887 : double dfValue =
7888 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7889 : sNoDataValues, bValid);
7890 2 : if (!bValid)
7891 0 : continue;
7892 2 : if (dfValue < dfMin)
7893 : {
7894 2 : dfMin = dfValue;
7895 2 : nMinX = iXBlock * nBlockXSize + iX;
7896 2 : nMinY = iYBlock * nBlockYSize + iY;
7897 : }
7898 2 : if (dfValue > dfMax)
7899 : {
7900 1 : dfMax = dfValue;
7901 1 : nMaxX = iXBlock * nBlockXSize + iX;
7902 1 : nMaxY = iYBlock * nBlockYSize + iY;
7903 : }
7904 : }
7905 2 : }
7906 : }
7907 : else
7908 : {
7909 9 : size_t pos_min = 0;
7910 9 : size_t pos_max = 0;
7911 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7912 9 : if (bNeedsMin && bNeedsMax)
7913 : {
7914 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7915 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7916 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7917 10 : sNoDataValues.dfNoDataValue);
7918 : }
7919 4 : else if (bNeedsMin)
7920 : {
7921 1 : pos_min = gdal::min_element(
7922 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7923 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7924 : sNoDataValues.dfNoDataValue);
7925 : }
7926 3 : else if (bNeedsMax)
7927 : {
7928 2 : pos_max = gdal::max_element(
7929 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7930 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7931 : sNoDataValues.dfNoDataValue);
7932 : }
7933 :
7934 9 : if (bNeedsMin)
7935 : {
7936 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7937 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7938 6 : bool bValid = true;
7939 : const double dfMinValueBlock =
7940 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7941 : sNoDataValues, bValid);
7942 6 : if (bValid && dfMinValueBlock < dfMin)
7943 : {
7944 5 : dfMin = dfMinValueBlock;
7945 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7946 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7947 : }
7948 : }
7949 :
7950 9 : if (bNeedsMax)
7951 : {
7952 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7953 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7954 7 : bool bValid = true;
7955 : const double dfMaxValueBlock =
7956 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7957 : sNoDataValues, bValid);
7958 7 : if (bValid && dfMaxValueBlock > dfMax)
7959 : {
7960 5 : dfMax = dfMaxValueBlock;
7961 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7962 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7963 : }
7964 : }
7965 : }
7966 :
7967 11 : poBlock->DropLock();
7968 :
7969 11 : if (eDataType == GDT_Byte)
7970 : {
7971 10 : if (bNeedsMin && dfMin == 0)
7972 : {
7973 1 : bNeedsMin = false;
7974 : }
7975 10 : if (bNeedsMax && dfMax == 255)
7976 : {
7977 4 : bNeedsMax = false;
7978 : }
7979 10 : if (!bNeedsMin && !bNeedsMax)
7980 : {
7981 3 : break;
7982 : }
7983 : }
7984 : }
7985 :
7986 8 : CPLFree(pabyMaskData);
7987 :
7988 8 : if (pdfMin)
7989 5 : *pdfMin = dfMin;
7990 8 : if (pdfMax)
7991 5 : *pdfMax = dfMax;
7992 8 : if (pnMinX)
7993 6 : *pnMinX = nMinX;
7994 8 : if (pnMinY)
7995 6 : *pnMinY = nMinY;
7996 8 : if (pnMaxX)
7997 6 : *pnMaxX = nMaxX;
7998 8 : if (pnMaxY)
7999 6 : *pnMaxY = nMaxY;
8000 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8001 8 : : CE_None;
8002 : }
8003 :
8004 : /************************************************************************/
8005 : /* GDALComputeRasterMinMaxLocation() */
8006 : /************************************************************************/
8007 :
8008 : /**
8009 : * \brief Compute the min/max values for a band, and their location.
8010 : *
8011 : * @see GDALRasterBand::ComputeRasterMinMax()
8012 : * @since GDAL 3.11
8013 : */
8014 :
8015 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8016 : double *pdfMax, int *pnMinX, int *pnMinY,
8017 : int *pnMaxX, int *pnMaxY)
8018 :
8019 : {
8020 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8021 :
8022 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8023 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8024 6 : pnMaxX, pnMaxY);
8025 : }
8026 :
8027 : /************************************************************************/
8028 : /* SetDefaultHistogram() */
8029 : /************************************************************************/
8030 :
8031 : /* FIXME : add proper documentation */
8032 : /**
8033 : * \brief Set default histogram.
8034 : *
8035 : * This method is the same as the C function GDALSetDefaultHistogram() and
8036 : * GDALSetDefaultHistogramEx()
8037 : */
8038 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8039 : double /* dfMax */,
8040 : int /* nBuckets */,
8041 : GUIntBig * /* panHistogram */)
8042 :
8043 : {
8044 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8045 0 : ReportError(CE_Failure, CPLE_NotSupported,
8046 : "SetDefaultHistogram() not implemented for this format.");
8047 :
8048 0 : return CE_Failure;
8049 : }
8050 :
8051 : /************************************************************************/
8052 : /* GDALSetDefaultHistogram() */
8053 : /************************************************************************/
8054 :
8055 : /**
8056 : * \brief Set default histogram.
8057 : *
8058 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8059 : * 2 billion.
8060 : *
8061 : * @see GDALRasterBand::SetDefaultHistogram()
8062 : * @see GDALSetRasterHistogramEx()
8063 : */
8064 :
8065 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8066 : double dfMax, int nBuckets,
8067 : int *panHistogram)
8068 :
8069 : {
8070 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8071 :
8072 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8073 :
8074 : GUIntBig *panHistogramTemp =
8075 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8076 0 : if (panHistogramTemp == nullptr)
8077 : {
8078 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8079 : "Out of memory in GDALSetDefaultHistogram().");
8080 0 : return CE_Failure;
8081 : }
8082 :
8083 0 : for (int i = 0; i < nBuckets; ++i)
8084 : {
8085 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8086 : }
8087 :
8088 : const CPLErr eErr =
8089 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8090 :
8091 0 : CPLFree(panHistogramTemp);
8092 :
8093 0 : return eErr;
8094 : }
8095 :
8096 : /************************************************************************/
8097 : /* GDALSetDefaultHistogramEx() */
8098 : /************************************************************************/
8099 :
8100 : /**
8101 : * \brief Set default histogram.
8102 : *
8103 : * @see GDALRasterBand::SetDefaultHistogram()
8104 : *
8105 : * @since GDAL 2.0
8106 : */
8107 :
8108 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8109 : double dfMin, double dfMax,
8110 : int nBuckets,
8111 : GUIntBig *panHistogram)
8112 :
8113 : {
8114 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8115 :
8116 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8117 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8118 : }
8119 :
8120 : /************************************************************************/
8121 : /* GetDefaultRAT() */
8122 : /************************************************************************/
8123 :
8124 : /**
8125 : * \brief Fetch default Raster Attribute Table.
8126 : *
8127 : * A RAT will be returned if there is a default one associated with the
8128 : * band, otherwise NULL is returned. The returned RAT is owned by the
8129 : * band and should not be deleted by the application.
8130 : *
8131 : * This method is the same as the C function GDALGetDefaultRAT().
8132 : *
8133 : * @return NULL, or a pointer to an internal RAT owned by the band.
8134 : */
8135 :
8136 173 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8137 :
8138 : {
8139 173 : return nullptr;
8140 : }
8141 :
8142 : /************************************************************************/
8143 : /* GDALGetDefaultRAT() */
8144 : /************************************************************************/
8145 :
8146 : /**
8147 : * \brief Fetch default Raster Attribute Table.
8148 : *
8149 : * @see GDALRasterBand::GetDefaultRAT()
8150 : */
8151 :
8152 1074 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8153 :
8154 : {
8155 1074 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8156 :
8157 1074 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8158 1074 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8159 : }
8160 :
8161 : /************************************************************************/
8162 : /* SetDefaultRAT() */
8163 : /************************************************************************/
8164 :
8165 : /**
8166 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8167 : * \brief Set default Raster Attribute Table.
8168 : *
8169 : * Associates a default RAT with the band. If not implemented for the
8170 : * format a CPLE_NotSupported error will be issued. If successful a copy
8171 : * of the RAT is made, the original remains owned by the caller.
8172 : *
8173 : * This method is the same as the C function GDALSetDefaultRAT().
8174 : *
8175 : * @param poRAT the RAT to assign to the band.
8176 : *
8177 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8178 : * failing.
8179 : */
8180 :
8181 : /**/
8182 : /**/
8183 :
8184 : CPLErr
8185 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8186 : {
8187 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8188 : {
8189 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8190 0 : ReportError(CE_Failure, CPLE_NotSupported,
8191 : "SetDefaultRAT() not implemented for this format.");
8192 0 : CPLPopErrorHandler();
8193 : }
8194 0 : return CE_Failure;
8195 : }
8196 :
8197 : /************************************************************************/
8198 : /* GDALSetDefaultRAT() */
8199 : /************************************************************************/
8200 :
8201 : /**
8202 : * \brief Set default Raster Attribute Table.
8203 : *
8204 : * @see GDALRasterBand::GDALSetDefaultRAT()
8205 : */
8206 :
8207 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8208 : GDALRasterAttributeTableH hRAT)
8209 :
8210 : {
8211 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8212 :
8213 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8214 :
8215 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8216 : }
8217 :
8218 : /************************************************************************/
8219 : /* GetMaskBand() */
8220 : /************************************************************************/
8221 :
8222 : /**
8223 : * \brief Return the mask band associated with the band.
8224 : *
8225 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8226 : * that returns one of four default implementations :
8227 : * <ul>
8228 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8229 : * </li>
8230 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8231 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8232 : * GMF_NODATA | GMF_PER_DATASET.
8233 : * </li>
8234 : * <li>If the band has a nodata value set, an instance of the new
8235 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8236 : * GMF_NODATA.
8237 : * </li>
8238 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8239 : * to apply to this band (specific rules yet to be determined) and that is of
8240 : * type GDT_Byte then that alpha band will be returned, and the flags
8241 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8242 : * </li>
8243 : * <li>If neither of the above apply, an instance of the new
8244 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8245 : * pixels. The null flags will return GMF_ALL_VALID.
8246 : * </li>
8247 : * </ul>
8248 : *
8249 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8250 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8251 : *
8252 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8253 : * dataset, with the same name as the main dataset and suffixed with .msk,
8254 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8255 : * main dataset.
8256 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8257 : * level, where xx matches the band number of a band of the main dataset. The
8258 : * value of those items is a combination of the flags GMF_ALL_VALID,
8259 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8260 : * a band, then the other rules explained above will be used to generate a
8261 : * on-the-fly mask band.
8262 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8263 : *
8264 : * This method is the same as the C function GDALGetMaskBand().
8265 : *
8266 : * @return a valid mask band.
8267 : *
8268 : * @since GDAL 1.5.0
8269 : *
8270 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8271 : *
8272 : */
8273 804952 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8274 :
8275 : {
8276 386085 : const auto HasNoData = [this]()
8277 : {
8278 128363 : int bHaveNoDataRaw = FALSE;
8279 128363 : bool bHaveNoData = false;
8280 128363 : if (eDataType == GDT_Int64)
8281 : {
8282 66 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8283 66 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8284 : }
8285 128297 : else if (eDataType == GDT_UInt64)
8286 : {
8287 48 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8288 48 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8289 : }
8290 : else
8291 : {
8292 128249 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8293 128255 : if (bHaveNoDataRaw &&
8294 128255 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8295 : {
8296 1021 : bHaveNoData = true;
8297 : }
8298 : }
8299 128370 : return bHaveNoData;
8300 804952 : };
8301 :
8302 804952 : if (poMask != nullptr)
8303 : {
8304 700788 : if (poMask.IsOwned())
8305 : {
8306 333520 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8307 : {
8308 33353 : if (HasNoData())
8309 : {
8310 9 : InvalidateMaskBand();
8311 : }
8312 : }
8313 300467 : else if (auto poNoDataMaskBand =
8314 300226 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8315 : {
8316 388 : int bHaveNoDataRaw = FALSE;
8317 388 : bool bIsSame = false;
8318 388 : if (eDataType == GDT_Int64)
8319 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8320 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8321 10 : bHaveNoDataRaw;
8322 371 : else if (eDataType == GDT_UInt64)
8323 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8324 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8325 10 : bHaveNoDataRaw;
8326 : else
8327 : {
8328 : const double dfNoDataValue =
8329 354 : GetNoDataValue(&bHaveNoDataRaw);
8330 354 : if (bHaveNoDataRaw)
8331 : {
8332 351 : bIsSame =
8333 351 : std::isnan(dfNoDataValue)
8334 351 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8335 316 : : poNoDataMaskBand->m_dfNoDataValue ==
8336 : dfNoDataValue;
8337 : }
8338 : }
8339 388 : if (!bIsSame)
8340 23 : InvalidateMaskBand();
8341 : }
8342 : }
8343 :
8344 704261 : if (poMask)
8345 706955 : return poMask.get();
8346 : }
8347 :
8348 : /* -------------------------------------------------------------------- */
8349 : /* Check for a mask in a .msk file. */
8350 : /* -------------------------------------------------------------------- */
8351 95130 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8352 : {
8353 46 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
8354 46 : if (poMask != nullptr)
8355 : {
8356 44 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8357 44 : return poMask.get();
8358 : }
8359 : }
8360 :
8361 : /* -------------------------------------------------------------------- */
8362 : /* Check for NODATA_VALUES metadata. */
8363 : /* -------------------------------------------------------------------- */
8364 95084 : if (poDS != nullptr)
8365 : {
8366 : const char *pszGDALNoDataValues =
8367 95071 : poDS->GetMetadataItem("NODATA_VALUES");
8368 95071 : if (pszGDALNoDataValues != nullptr)
8369 : {
8370 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8371 : pszGDALNoDataValues, " ", FALSE, FALSE);
8372 :
8373 : // Make sure we have as many values as bands.
8374 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8375 68 : poDS->GetRasterCount() != 0)
8376 : {
8377 : // Make sure that all bands have the same data type
8378 : // This is clearly not a fundamental condition, just a
8379 : // condition to make implementation easier.
8380 68 : GDALDataType eDT = GDT_Unknown;
8381 68 : int i = 0; // Used after for.
8382 270 : for (; i < poDS->GetRasterCount(); ++i)
8383 : {
8384 202 : if (i == 0)
8385 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8386 134 : else if (eDT !=
8387 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8388 : {
8389 0 : break;
8390 : }
8391 : }
8392 68 : if (i == poDS->GetRasterCount())
8393 : {
8394 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8395 : try
8396 : {
8397 68 : poMask.reset(
8398 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
8399 : }
8400 0 : catch (const std::bad_alloc &)
8401 : {
8402 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8403 0 : poMask.reset();
8404 : }
8405 68 : CSLDestroy(papszGDALNoDataValues);
8406 68 : return poMask.get();
8407 : }
8408 : else
8409 : {
8410 0 : ReportError(CE_Warning, CPLE_AppDefined,
8411 : "All bands should have the same type in "
8412 : "order the NODATA_VALUES metadata item "
8413 : "to be used as a mask.");
8414 : }
8415 : }
8416 : else
8417 : {
8418 0 : ReportError(
8419 : CE_Warning, CPLE_AppDefined,
8420 : "NODATA_VALUES metadata item doesn't have the same number "
8421 : "of values as the number of bands. "
8422 : "Ignoring it for mask.");
8423 : }
8424 :
8425 0 : CSLDestroy(papszGDALNoDataValues);
8426 : }
8427 : }
8428 :
8429 : /* -------------------------------------------------------------------- */
8430 : /* Check for nodata case. */
8431 : /* -------------------------------------------------------------------- */
8432 95016 : if (HasNoData())
8433 : {
8434 1047 : nMaskFlags = GMF_NODATA;
8435 : try
8436 : {
8437 1047 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
8438 : }
8439 0 : catch (const std::bad_alloc &)
8440 : {
8441 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8442 0 : poMask.reset();
8443 : }
8444 1047 : return poMask.get();
8445 : }
8446 :
8447 : /* -------------------------------------------------------------------- */
8448 : /* Check for alpha case. */
8449 : /* -------------------------------------------------------------------- */
8450 93955 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8451 188511 : this == poDS->GetRasterBand(1) &&
8452 587 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8453 : {
8454 223 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8455 : {
8456 179 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8457 179 : poMask.resetNotOwned(poDS->GetRasterBand(2));
8458 179 : return poMask.get();
8459 : }
8460 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8461 : {
8462 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8463 : try
8464 : {
8465 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8466 46 : poDS->GetRasterBand(2)));
8467 : }
8468 0 : catch (const std::bad_alloc &)
8469 : {
8470 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8471 0 : poMask.reset();
8472 : }
8473 23 : return poMask.get();
8474 : }
8475 : }
8476 :
8477 93752 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8478 3001 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8479 188238 : this == poDS->GetRasterBand(3)) &&
8480 2337 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8481 : {
8482 1459 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8483 : {
8484 1408 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8485 1408 : poMask.resetNotOwned(poDS->GetRasterBand(4));
8486 1408 : return poMask.get();
8487 : }
8488 51 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8489 : {
8490 38 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8491 : try
8492 : {
8493 38 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8494 76 : poDS->GetRasterBand(4)));
8495 : }
8496 0 : catch (const std::bad_alloc &)
8497 : {
8498 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8499 0 : poMask.reset();
8500 : }
8501 38 : return poMask.get();
8502 : }
8503 : }
8504 :
8505 : /* -------------------------------------------------------------------- */
8506 : /* Fallback to all valid case. */
8507 : /* -------------------------------------------------------------------- */
8508 92320 : nMaskFlags = GMF_ALL_VALID;
8509 : try
8510 : {
8511 92320 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
8512 : }
8513 0 : catch (const std::bad_alloc &)
8514 : {
8515 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8516 0 : poMask.reset();
8517 : }
8518 :
8519 92320 : return poMask.get();
8520 : }
8521 :
8522 : /************************************************************************/
8523 : /* GDALGetMaskBand() */
8524 : /************************************************************************/
8525 :
8526 : /**
8527 : * \brief Return the mask band associated with the band.
8528 : *
8529 : * @see GDALRasterBand::GetMaskBand()
8530 : */
8531 :
8532 11042 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8533 :
8534 : {
8535 11042 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8536 :
8537 11042 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8538 11042 : return poBand->GetMaskBand();
8539 : }
8540 :
8541 : /************************************************************************/
8542 : /* GetMaskFlags() */
8543 : /************************************************************************/
8544 :
8545 : /**
8546 : * \brief Return the status flags of the mask band associated with the band.
8547 : *
8548 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8549 : * the following available definitions that may be extended in the future:
8550 : * <ul>
8551 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8552 : * 255. When used this will normally be the only flag set.
8553 : * </li>
8554 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8555 : * dataset.
8556 : * </li>
8557 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8558 : * and may have values other than 0 and 255.
8559 : * </li>
8560 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8561 : * nodata values. (mutually exclusive of GMF_ALPHA)
8562 : * </li>
8563 : * </ul>
8564 : *
8565 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8566 : * that returns one of four default implementations:
8567 : * <ul>
8568 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8569 : * </li>
8570 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8571 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8572 : * GMF_NODATA | GMF_PER_DATASET.
8573 : * </li>
8574 : * <li>If the band has a nodata value set, an instance of the new
8575 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8576 : * GMF_NODATA.
8577 : * </li>
8578 : * <li>If there is no nodata value, but the dataset has an alpha band that
8579 : * seems to apply to this band (specific rules yet to be determined) and that is
8580 : * of type GDT_Byte then that alpha band will be returned, and the flags
8581 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8582 : * </li>
8583 : * <li>If neither of the above apply, an instance of the new
8584 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8585 : * pixels. The null flags will return GMF_ALL_VALID.
8586 : * </li>
8587 : * </ul>
8588 : *
8589 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8590 : * dataset, with the same name as the main dataset and suffixed with .msk,
8591 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8592 : * main dataset.
8593 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8594 : * level, where xx matches the band number of a band of the main dataset. The
8595 : * value of those items is a combination of the flags GMF_ALL_VALID,
8596 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8597 : * a band, then the other rules explained above will be used to generate a
8598 : * on-the-fly mask band.
8599 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8600 : *
8601 : * This method is the same as the C function GDALGetMaskFlags().
8602 : *
8603 : * @since GDAL 1.5.0
8604 : *
8605 : * @return a valid mask band.
8606 : *
8607 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8608 : *
8609 : */
8610 150267 : int GDALRasterBand::GetMaskFlags()
8611 :
8612 : {
8613 : // If we don't have a band yet, force this now so that the masks value
8614 : // will be initialized.
8615 :
8616 150267 : if (poMask == nullptr)
8617 93832 : GetMaskBand();
8618 :
8619 150264 : return nMaskFlags;
8620 : }
8621 :
8622 : /************************************************************************/
8623 : /* GDALGetMaskFlags() */
8624 : /************************************************************************/
8625 :
8626 : /**
8627 : * \brief Return the status flags of the mask band associated with the band.
8628 : *
8629 : * @see GDALRasterBand::GetMaskFlags()
8630 : */
8631 :
8632 6963 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8633 :
8634 : {
8635 6963 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8636 :
8637 6963 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8638 6963 : return poBand->GetMaskFlags();
8639 : }
8640 :
8641 : /************************************************************************/
8642 : /* InvalidateMaskBand() */
8643 : /************************************************************************/
8644 :
8645 : //! @cond Doxygen_Suppress
8646 1911520 : void GDALRasterBand::InvalidateMaskBand()
8647 : {
8648 1911520 : poMask.reset();
8649 1911520 : nMaskFlags = 0;
8650 1911520 : }
8651 :
8652 : //! @endcond
8653 :
8654 : /************************************************************************/
8655 : /* CreateMaskBand() */
8656 : /************************************************************************/
8657 :
8658 : /**
8659 : * \brief Adds a mask band to the current band
8660 : *
8661 : * The default implementation of the CreateMaskBand() method is implemented
8662 : * based on similar rules to the .ovr handling implemented using the
8663 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8664 : * be created with the same basename as the original file, and it will have
8665 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8666 : * The mask images will be deflate compressed tiled images with the same
8667 : * block size as the original image if possible.
8668 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8669 : * level, where xx matches the band number of a band of the main dataset. The
8670 : * value of those items will be the one of the nFlagsIn parameter.
8671 : *
8672 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8673 : * it might be invalidated by CreateMaskBand(). So you have to call
8674 : * GetMaskBand() again.
8675 : *
8676 : * This method is the same as the C function GDALCreateMaskBand().
8677 : *
8678 : * @since GDAL 1.5.0
8679 : *
8680 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8681 : *
8682 : * @return CE_None on success or CE_Failure on an error.
8683 : *
8684 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8685 : * @see GDALDataset::CreateMaskBand()
8686 : *
8687 : */
8688 :
8689 9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8690 :
8691 : {
8692 9 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8693 : {
8694 9 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8695 9 : if (eErr != CE_None)
8696 1 : return eErr;
8697 :
8698 8 : InvalidateMaskBand();
8699 :
8700 8 : return CE_None;
8701 : }
8702 :
8703 0 : ReportError(CE_Failure, CPLE_NotSupported,
8704 : "CreateMaskBand() not supported for this band.");
8705 :
8706 0 : return CE_Failure;
8707 : }
8708 :
8709 : /************************************************************************/
8710 : /* GDALCreateMaskBand() */
8711 : /************************************************************************/
8712 :
8713 : /**
8714 : * \brief Adds a mask band to the current band
8715 : *
8716 : * @see GDALRasterBand::CreateMaskBand()
8717 : */
8718 :
8719 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8720 :
8721 : {
8722 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8723 :
8724 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8725 33 : return poBand->CreateMaskBand(nFlags);
8726 : }
8727 :
8728 : /************************************************************************/
8729 : /* IsMaskBand() */
8730 : /************************************************************************/
8731 :
8732 : /**
8733 : * \brief Returns whether a band is a mask band.
8734 : *
8735 : * Mask band must be understood in the broad term: it can be a per-dataset
8736 : * mask band, an alpha band, or an implicit mask band.
8737 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8738 : *
8739 : * This method is the same as the C function GDALIsMaskBand().
8740 : *
8741 : * @return true if the band is a mask band.
8742 : *
8743 : * @see GDALDataset::CreateMaskBand()
8744 : *
8745 : * @since GDAL 3.5.0
8746 : *
8747 : */
8748 :
8749 439 : bool GDALRasterBand::IsMaskBand() const
8750 : {
8751 : // The GeoTIFF driver, among others, override this method to
8752 : // also handle external .msk bands.
8753 439 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8754 439 : GCI_AlphaBand;
8755 : }
8756 :
8757 : /************************************************************************/
8758 : /* GDALIsMaskBand() */
8759 : /************************************************************************/
8760 :
8761 : /**
8762 : * \brief Returns whether a band is a mask band.
8763 : *
8764 : * Mask band must be understood in the broad term: it can be a per-dataset
8765 : * mask band, an alpha band, or an implicit mask band.
8766 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8767 : *
8768 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8769 : *
8770 : * @return true if the band is a mask band.
8771 : *
8772 : * @see GDALRasterBand::IsMaskBand()
8773 : *
8774 : * @since GDAL 3.5.0
8775 : *
8776 : */
8777 :
8778 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8779 :
8780 : {
8781 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8782 :
8783 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8784 37 : return poBand->IsMaskBand();
8785 : }
8786 :
8787 : /************************************************************************/
8788 : /* GetMaskValueRange() */
8789 : /************************************************************************/
8790 :
8791 : /**
8792 : * \brief Returns the range of values that a mask band can take.
8793 : *
8794 : * @return the range of values that a mask band can take.
8795 : *
8796 : * @since GDAL 3.5.0
8797 : *
8798 : */
8799 :
8800 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8801 : {
8802 0 : return GMVR_UNKNOWN;
8803 : }
8804 :
8805 : /************************************************************************/
8806 : /* GetIndexColorTranslationTo() */
8807 : /************************************************************************/
8808 :
8809 : /**
8810 : * \brief Compute translation table for color tables.
8811 : *
8812 : * When the raster band has a palette index, it may be useful to compute
8813 : * the "translation" of this palette to the palette of another band.
8814 : * The translation tries to do exact matching first, and then approximate
8815 : * matching if no exact matching is possible.
8816 : * This method returns a table such that table[i] = j where i is an index
8817 : * of the 'this' rasterband and j the corresponding index for the reference
8818 : * rasterband.
8819 : *
8820 : * This method is thought as internal to GDAL and is used for drivers
8821 : * like RPFTOC.
8822 : *
8823 : * The implementation only supports 1-byte palette rasterbands.
8824 : *
8825 : * @param poReferenceBand the raster band
8826 : * @param pTranslationTable an already allocated translation table (at least 256
8827 : * bytes), or NULL to let the method allocate it
8828 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8829 : * is approximate. May be NULL.
8830 : *
8831 : * @return a translation table if the two bands are palette index and that they
8832 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8833 : * NULL was passed for pTranslationTable.
8834 : */
8835 :
8836 : unsigned char *
8837 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8838 : unsigned char *pTranslationTable,
8839 : int *pApproximateMatching)
8840 : {
8841 4 : if (poReferenceBand == nullptr)
8842 0 : return nullptr;
8843 :
8844 : // cppcheck-suppress knownConditionTrueFalse
8845 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8846 : // cppcheck-suppress knownConditionTrueFalse
8847 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8848 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8849 4 : GetRasterDataType() == GDT_Byte)
8850 : {
8851 4 : const GDALColorTable *srcColorTable = GetColorTable();
8852 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8853 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8854 : {
8855 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8856 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8857 :
8858 4 : int bHasNoDataValueSrc = FALSE;
8859 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8860 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8861 4 : dfNoDataValueSrc <= 255 &&
8862 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8863 0 : bHasNoDataValueSrc = FALSE;
8864 4 : const int noDataValueSrc =
8865 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8866 :
8867 4 : int bHasNoDataValueRef = FALSE;
8868 : const double dfNoDataValueRef =
8869 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8870 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8871 3 : dfNoDataValueRef <= 255 &&
8872 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8873 1 : bHasNoDataValueRef = FALSE;
8874 4 : const int noDataValueRef =
8875 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8876 :
8877 4 : bool samePalette = false;
8878 :
8879 4 : if (pApproximateMatching)
8880 3 : *pApproximateMatching = FALSE;
8881 :
8882 4 : if (nEntries == nRefEntries &&
8883 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8884 3 : (bHasNoDataValueSrc == FALSE ||
8885 : noDataValueSrc == noDataValueRef))
8886 : {
8887 3 : samePalette = true;
8888 654 : for (int i = 0; i < nEntries; ++i)
8889 : {
8890 651 : if (noDataValueSrc == i)
8891 3 : continue;
8892 : const GDALColorEntry *entry =
8893 648 : srcColorTable->GetColorEntry(i);
8894 : const GDALColorEntry *entryRef =
8895 648 : destColorTable->GetColorEntry(i);
8896 648 : if (entry->c1 != entryRef->c1 ||
8897 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8898 : {
8899 0 : samePalette = false;
8900 : }
8901 : }
8902 : }
8903 :
8904 4 : if (!samePalette)
8905 : {
8906 1 : if (pTranslationTable == nullptr)
8907 : {
8908 : pTranslationTable = static_cast<unsigned char *>(
8909 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8910 1 : if (pTranslationTable == nullptr)
8911 1 : return nullptr;
8912 : }
8913 :
8914 : // Trying to remap the product palette on the subdataset
8915 : // palette.
8916 5 : for (int i = 0; i < nEntries; ++i)
8917 : {
8918 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8919 : noDataValueSrc == i)
8920 0 : continue;
8921 : const GDALColorEntry *entry =
8922 4 : srcColorTable->GetColorEntry(i);
8923 4 : bool bMatchFound = false;
8924 13 : for (int j = 0; j < nRefEntries; ++j)
8925 : {
8926 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8927 0 : continue;
8928 : const GDALColorEntry *entryRef =
8929 10 : destColorTable->GetColorEntry(j);
8930 10 : if (entry->c1 == entryRef->c1 &&
8931 2 : entry->c2 == entryRef->c2 &&
8932 2 : entry->c3 == entryRef->c3)
8933 : {
8934 1 : pTranslationTable[i] =
8935 : static_cast<unsigned char>(j);
8936 1 : bMatchFound = true;
8937 1 : break;
8938 : }
8939 : }
8940 4 : if (!bMatchFound)
8941 : {
8942 : // No exact match. Looking for closest color now.
8943 3 : int best_j = 0;
8944 3 : int best_distance = 0;
8945 3 : if (pApproximateMatching)
8946 0 : *pApproximateMatching = TRUE;
8947 12 : for (int j = 0; j < nRefEntries; ++j)
8948 : {
8949 : const GDALColorEntry *entryRef =
8950 9 : destColorTable->GetColorEntry(j);
8951 9 : int distance = (entry->c1 - entryRef->c1) *
8952 9 : (entry->c1 - entryRef->c1) +
8953 9 : (entry->c2 - entryRef->c2) *
8954 9 : (entry->c2 - entryRef->c2) +
8955 9 : (entry->c3 - entryRef->c3) *
8956 9 : (entry->c3 - entryRef->c3);
8957 9 : if (j == 0 || distance < best_distance)
8958 : {
8959 7 : best_j = j;
8960 7 : best_distance = distance;
8961 : }
8962 : }
8963 3 : pTranslationTable[i] =
8964 : static_cast<unsigned char>(best_j);
8965 : }
8966 : }
8967 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8968 0 : pTranslationTable[noDataValueSrc] =
8969 : static_cast<unsigned char>(noDataValueRef);
8970 :
8971 1 : return pTranslationTable;
8972 : }
8973 : }
8974 : }
8975 3 : return nullptr;
8976 : }
8977 :
8978 : /************************************************************************/
8979 : /* SetFlushBlockErr() */
8980 : /************************************************************************/
8981 :
8982 : /**
8983 : * \brief Store that an error occurred while writing a dirty block.
8984 : *
8985 : * This function stores the fact that an error occurred while writing a dirty
8986 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8987 : * flushed when the block cache get full, it is not convenient/possible to
8988 : * report that a dirty block could not be written correctly. This function
8989 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8990 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8991 : * places where the user can easily match the error with the relevant dataset.
8992 : */
8993 :
8994 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8995 : {
8996 0 : eFlushBlockErr = eErr;
8997 0 : }
8998 :
8999 : /************************************************************************/
9000 : /* IncDirtyBlocks() */
9001 : /************************************************************************/
9002 :
9003 : /**
9004 : * \brief Increment/decrement the number of dirty blocks
9005 : */
9006 :
9007 800501 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9008 : {
9009 800501 : if (poBandBlockCache)
9010 800500 : poBandBlockCache->IncDirtyBlocks(nInc);
9011 800503 : }
9012 :
9013 : /************************************************************************/
9014 : /* ReportError() */
9015 : /************************************************************************/
9016 :
9017 : #ifndef DOXYGEN_XML
9018 : /**
9019 : * \brief Emits an error related to a raster band.
9020 : *
9021 : * This function is a wrapper for regular CPLError(). The only difference
9022 : * with CPLError() is that it prepends the error message with the dataset
9023 : * name and the band number.
9024 : *
9025 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9026 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9027 : * @param fmt a printf() style format string. Any additional arguments
9028 : * will be treated as arguments to fill in this format in a manner
9029 : * similar to printf().
9030 : *
9031 : * @since GDAL 1.9.0
9032 : */
9033 :
9034 2469 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9035 : const char *fmt, ...) const
9036 : {
9037 : va_list args;
9038 :
9039 2469 : va_start(args, fmt);
9040 :
9041 2469 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9042 2469 : pszDSName = CPLGetFilename(pszDSName);
9043 2469 : if (pszDSName[0] != '\0')
9044 : {
9045 2402 : CPLError(eErrClass, err_no, "%s",
9046 4804 : CPLString()
9047 2402 : .Printf("%s, band %d: ", pszDSName, GetBand())
9048 4804 : .append(CPLString().vPrintf(fmt, args))
9049 : .c_str());
9050 : }
9051 : else
9052 : {
9053 67 : CPLErrorV(eErrClass, err_no, fmt, args);
9054 : }
9055 :
9056 2469 : va_end(args);
9057 2469 : }
9058 : #endif
9059 :
9060 : /************************************************************************/
9061 : /* GetVirtualMemAuto() */
9062 : /************************************************************************/
9063 :
9064 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9065 : *
9066 : * Only supported on Linux and Unix systems with mmap() for now.
9067 : *
9068 : * This method allows creating a virtual memory object for a GDALRasterBand,
9069 : * that exposes the whole image data as a virtual array.
9070 : *
9071 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9072 : * specialized implementation, such as for raw files, may also directly use
9073 : * mechanisms of the operating system to create a view of the underlying file
9074 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9075 : *
9076 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9077 : * offer a specialized implementation with direct file mapping, provided that
9078 : * some requirements are met :
9079 : * - for all drivers, the dataset must be backed by a "real" file in the file
9080 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9081 : * must match the native ordering of the CPU.
9082 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9083 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9084 : * the file in sequential order, and be equally spaced (which is generally the
9085 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9086 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9087 : *
9088 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9089 : * CPLVirtualMemFree() must be called before the raster band object is
9090 : * destroyed.
9091 : *
9092 : * If p is such a pointer and base_type the type matching
9093 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9094 : * accessed with
9095 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9096 : *
9097 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9098 : *
9099 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9100 : * read/write the band.
9101 : *
9102 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9103 : * one pixel value in the buffer to the start of the next pixel value within a
9104 : * scanline.
9105 : *
9106 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9107 : * one scanline in the buffer to the start of the next.
9108 : *
9109 : * @param papszOptions NULL terminated list of options.
9110 : * If a specialized implementation exists, defining
9111 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9112 : * used. On the contrary, starting with GDAL 2.2, defining
9113 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9114 : * being used (thus only allowing efficient implementations to be used). When
9115 : * requiring or falling back to the default implementation, the following
9116 : * options are available : CACHE_SIZE (in bytes, defaults to
9117 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9118 : * to FALSE)
9119 : *
9120 : * @return a virtual memory object that must be unreferenced by
9121 : * CPLVirtualMemFree(), or NULL in case of failure.
9122 : *
9123 : * @since GDAL 1.11
9124 : */
9125 :
9126 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9127 : int *pnPixelSpace,
9128 : GIntBig *pnLineSpace,
9129 : char **papszOptions)
9130 : {
9131 9 : const char *pszImpl = CSLFetchNameValueDef(
9132 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9133 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9134 8 : EQUAL(pszImpl, "FALSE"))
9135 : {
9136 1 : return nullptr;
9137 : }
9138 :
9139 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9140 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9141 8 : if (pnPixelSpace)
9142 8 : *pnPixelSpace = nPixelSpace;
9143 8 : if (pnLineSpace)
9144 8 : *pnLineSpace = nLineSpace;
9145 : const size_t nCacheSize =
9146 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9147 : const size_t nPageSizeHint =
9148 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9149 8 : const bool bSingleThreadUsage = CPLTestBool(
9150 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9151 8 : return GDALRasterBandGetVirtualMem(
9152 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9153 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9154 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9155 8 : papszOptions);
9156 : }
9157 :
9158 : /************************************************************************/
9159 : /* GDALGetVirtualMemAuto() */
9160 : /************************************************************************/
9161 :
9162 : /**
9163 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9164 : *
9165 : * @see GDALRasterBand::GetVirtualMemAuto()
9166 : */
9167 :
9168 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9169 : int *pnPixelSpace, GIntBig *pnLineSpace,
9170 : CSLConstList papszOptions)
9171 : {
9172 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9173 :
9174 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9175 :
9176 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9177 31 : const_cast<char **>(papszOptions));
9178 : }
9179 :
9180 : /************************************************************************/
9181 : /* GDALGetDataCoverageStatus() */
9182 : /************************************************************************/
9183 :
9184 : /**
9185 : * \brief Get the coverage status of a sub-window of the raster.
9186 : *
9187 : * Returns whether a sub-window of the raster contains only data, only empty
9188 : * blocks or a mix of both. This function can be used to determine quickly
9189 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9190 : * be sparse.
9191 : *
9192 : * Empty blocks are blocks that are generally not physically present in the
9193 : * file, and when read through GDAL, contain only pixels whose value is the
9194 : * nodata value when it is set, or whose value is 0 when the nodata value is
9195 : * not set.
9196 : *
9197 : * The query is done in an efficient way without reading the actual pixel
9198 : * values. If not possible, or not implemented at all by the driver,
9199 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9200 : * be returned.
9201 : *
9202 : * The values that can be returned by the function are the following,
9203 : * potentially combined with the binary or operator :
9204 : * <ul>
9205 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9206 : * GetDataCoverageStatus(). This flag should be returned together with
9207 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9208 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9209 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9210 : * the queried window. This is typically identified by the concept of missing
9211 : * block in formats that supports it.
9212 : * </li>
9213 : * </ul>
9214 : *
9215 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9216 : * should be interpreted more as hint of potential presence of data. For example
9217 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9218 : * nodata value), instead of using the missing block mechanism,
9219 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9220 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9221 : *
9222 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9223 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9224 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9225 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9226 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9227 : * the function will exit, so that you can potentially refine the requested area
9228 : * to find which particular region(s) have missing blocks.
9229 : *
9230 : * @see GDALRasterBand::GetDataCoverageStatus()
9231 : *
9232 : * @param hBand raster band
9233 : *
9234 : * @param nXOff The pixel offset to the top left corner of the region
9235 : * of the band to be queried. This would be zero to start from the left side.
9236 : *
9237 : * @param nYOff The line offset to the top left corner of the region
9238 : * of the band to be queried. This would be zero to start from the top.
9239 : *
9240 : * @param nXSize The width of the region of the band to be queried in pixels.
9241 : *
9242 : * @param nYSize The height of the region of the band to be queried in lines.
9243 : *
9244 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9245 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9246 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9247 : * as the computation of the coverage matches the mask, the computation will be
9248 : * stopped. *pdfDataPct will not be valid in that case.
9249 : *
9250 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9251 : * to the (approximate) percentage in [0,100] of pixels in the queried
9252 : * sub-window that have valid values. The implementation might not always be
9253 : * able to compute it, in which case it will be set to a negative value.
9254 : *
9255 : * @return a binary-or'ed combination of possible values
9256 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9257 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9258 : *
9259 : * @note Added in GDAL 2.2
9260 : */
9261 :
9262 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9263 : int nYOff, int nXSize, int nYSize,
9264 : int nMaskFlagStop, double *pdfDataPct)
9265 : {
9266 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9267 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9268 :
9269 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9270 :
9271 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9272 26 : nMaskFlagStop, pdfDataPct);
9273 : }
9274 :
9275 : /************************************************************************/
9276 : /* GetDataCoverageStatus() */
9277 : /************************************************************************/
9278 :
9279 : /**
9280 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9281 : * int nYOff,
9282 : * int nXSize,
9283 : * int nYSize,
9284 : * int nMaskFlagStop,
9285 : * double* pdfDataPct)
9286 : * \brief Get the coverage status of a sub-window of the raster.
9287 : *
9288 : * Returns whether a sub-window of the raster contains only data, only empty
9289 : * blocks or a mix of both. This function can be used to determine quickly
9290 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9291 : * be sparse.
9292 : *
9293 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9294 : * value when it is set, or whose value is 0 when the nodata value is not set.
9295 : *
9296 : * The query is done in an efficient way without reading the actual pixel
9297 : * values. If not possible, or not implemented at all by the driver,
9298 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9299 : * be returned.
9300 : *
9301 : * The values that can be returned by the function are the following,
9302 : * potentially combined with the binary or operator :
9303 : * <ul>
9304 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9305 : * GetDataCoverageStatus(). This flag should be returned together with
9306 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9307 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9308 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9309 : * the queried window. This is typically identified by the concept of missing
9310 : * block in formats that supports it.
9311 : * </li>
9312 : * </ul>
9313 : *
9314 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9315 : * should be interpreted more as hint of potential presence of data. For example
9316 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9317 : * nodata value), instead of using the missing block mechanism,
9318 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9319 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9320 : *
9321 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9322 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9323 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9324 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9325 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9326 : * the function will exit, so that you can potentially refine the requested area
9327 : * to find which particular region(s) have missing blocks.
9328 : *
9329 : * @see GDALGetDataCoverageStatus()
9330 : *
9331 : * @param nXOff The pixel offset to the top left corner of the region
9332 : * of the band to be queried. This would be zero to start from the left side.
9333 : *
9334 : * @param nYOff The line offset to the top left corner of the region
9335 : * of the band to be queried. This would be zero to start from the top.
9336 : *
9337 : * @param nXSize The width of the region of the band to be queried in pixels.
9338 : *
9339 : * @param nYSize The height of the region of the band to be queried in lines.
9340 : *
9341 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9342 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9343 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9344 : * as the computation of the coverage matches the mask, the computation will be
9345 : * stopped. *pdfDataPct will not be valid in that case.
9346 : *
9347 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9348 : * to the (approximate) percentage in [0,100] of pixels in the queried
9349 : * sub-window that have valid values. The implementation might not always be
9350 : * able to compute it, in which case it will be set to a negative value.
9351 : *
9352 : * @return a binary-or'ed combination of possible values
9353 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9354 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9355 : *
9356 : * @note Added in GDAL 2.2
9357 : */
9358 :
9359 : /**
9360 : * \brief Get the coverage status of a sub-window of the raster.
9361 : *
9362 : * Returns whether a sub-window of the raster contains only data, only empty
9363 : * blocks or a mix of both. This function can be used to determine quickly
9364 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9365 : * be sparse.
9366 : *
9367 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9368 : * value when it is set, or whose value is 0 when the nodata value is not set.
9369 : *
9370 : * The query is done in an efficient way without reading the actual pixel
9371 : * values. If not possible, or not implemented at all by the driver,
9372 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9373 : * be returned.
9374 : *
9375 : * The values that can be returned by the function are the following,
9376 : * potentially combined with the binary or operator :
9377 : * <ul>
9378 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9379 : * GetDataCoverageStatus(). This flag should be returned together with
9380 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9381 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9382 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9383 : * the queried window. This is typically identified by the concept of missing
9384 : * block in formats that supports it.
9385 : * </li>
9386 : * </ul>
9387 : *
9388 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9389 : * should be interpreted more as hint of potential presence of data. For example
9390 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9391 : * nodata value), instead of using the missing block mechanism,
9392 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9393 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9394 : *
9395 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9396 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9397 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9398 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9399 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9400 : * the function will exit, so that you can potentially refine the requested area
9401 : * to find which particular region(s) have missing blocks.
9402 : *
9403 : * @see GDALGetDataCoverageStatus()
9404 : *
9405 : * @param nXOff The pixel offset to the top left corner of the region
9406 : * of the band to be queried. This would be zero to start from the left side.
9407 : *
9408 : * @param nYOff The line offset to the top left corner of the region
9409 : * of the band to be queried. This would be zero to start from the top.
9410 : *
9411 : * @param nXSize The width of the region of the band to be queried in pixels.
9412 : *
9413 : * @param nYSize The height of the region of the band to be queried in lines.
9414 : *
9415 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9416 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9417 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9418 : * as the computation of the coverage matches the mask, the computation will be
9419 : * stopped. *pdfDataPct will not be valid in that case.
9420 : *
9421 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9422 : * to the (approximate) percentage in [0,100] of pixels in the queried
9423 : * sub-window that have valid values. The implementation might not always be
9424 : * able to compute it, in which case it will be set to a negative value.
9425 : *
9426 : * @return a binary-or'ed combination of possible values
9427 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9428 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9429 : *
9430 : * @note Added in GDAL 2.2
9431 : */
9432 :
9433 4620 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9434 : int nYSize, int nMaskFlagStop,
9435 : double *pdfDataPct)
9436 : {
9437 4620 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9438 4620 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9439 4620 : nYOff + nYSize > nRasterYSize)
9440 : {
9441 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9442 0 : if (pdfDataPct)
9443 0 : *pdfDataPct = 0.0;
9444 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9445 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9446 : }
9447 4620 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9448 4620 : pdfDataPct);
9449 : }
9450 :
9451 : /************************************************************************/
9452 : /* IGetDataCoverageStatus() */
9453 : /************************************************************************/
9454 :
9455 684 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9456 : int /*nXSize*/, int /*nYSize*/,
9457 : int /*nMaskFlagStop*/,
9458 : double *pdfDataPct)
9459 : {
9460 684 : if (pdfDataPct != nullptr)
9461 0 : *pdfDataPct = 100.0;
9462 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9463 684 : GDAL_DATA_COVERAGE_STATUS_DATA;
9464 : }
9465 :
9466 : //! @cond Doxygen_Suppress
9467 : /************************************************************************/
9468 : /* EnterReadWrite() */
9469 : /************************************************************************/
9470 :
9471 7824010 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9472 : {
9473 7824010 : if (poDS != nullptr)
9474 7060390 : return poDS->EnterReadWrite(eRWFlag);
9475 763627 : return FALSE;
9476 : }
9477 :
9478 : /************************************************************************/
9479 : /* LeaveReadWrite() */
9480 : /************************************************************************/
9481 :
9482 1127310 : void GDALRasterBand::LeaveReadWrite()
9483 : {
9484 1127310 : if (poDS != nullptr)
9485 1127020 : poDS->LeaveReadWrite();
9486 1127530 : }
9487 :
9488 : /************************************************************************/
9489 : /* InitRWLock() */
9490 : /************************************************************************/
9491 :
9492 3980140 : void GDALRasterBand::InitRWLock()
9493 : {
9494 3980140 : if (poDS != nullptr)
9495 3979730 : poDS->InitRWLock();
9496 3980140 : }
9497 :
9498 : //! @endcond
9499 :
9500 : // clang-format off
9501 :
9502 : /**
9503 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9504 : * \brief Set metadata.
9505 : *
9506 : * CAUTION: depending on the format, older values of the updated information
9507 : * might still be found in the file in a "ghost" state, even if no longer
9508 : * accessible through the GDAL API. This is for example the case of the GTiff
9509 : * format (this is not a exhaustive list)
9510 : *
9511 : * The C function GDALSetMetadata() does the same thing as this method.
9512 : *
9513 : * @param papszMetadata the metadata in name=value string list format to
9514 : * apply.
9515 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9516 : * domain.
9517 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9518 : * metadata has been accepted, but is likely not maintained persistently
9519 : * by the underlying object between sessions.
9520 : */
9521 :
9522 : /**
9523 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9524 : * \brief Set single metadata item.
9525 : *
9526 : * CAUTION: depending on the format, older values of the updated information
9527 : * might still be found in the file in a "ghost" state, even if no longer
9528 : * accessible through the GDAL API. This is for example the case of the GTiff
9529 : * format (this is not a exhaustive list)
9530 : *
9531 : * The C function GDALSetMetadataItem() does the same thing as this method.
9532 : *
9533 : * @param pszName the key for the metadata item to fetch.
9534 : * @param pszValue the value to assign to the key.
9535 : * @param pszDomain the domain to set within, use NULL for the default domain.
9536 : *
9537 : * @return CE_None on success, or an error code on failure.
9538 : */
9539 :
9540 : // clang-format on
9541 :
9542 : //! @cond Doxygen_Suppress
9543 : /************************************************************************/
9544 : /* EnablePixelTypeSignedByteWarning() */
9545 : /************************************************************************/
9546 :
9547 156224 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9548 : {
9549 156224 : m_bEnablePixelTypeSignedByteWarning = b;
9550 156224 : }
9551 :
9552 4884 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9553 : {
9554 4884 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9555 4884 : }
9556 :
9557 : //! @endcond
9558 :
9559 : /************************************************************************/
9560 : /* GetMetadataItem() */
9561 : /************************************************************************/
9562 :
9563 619271 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9564 : const char *pszDomain)
9565 : {
9566 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9567 619271 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9568 461729 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9569 321396 : EQUAL(pszName, "PIXELTYPE"))
9570 : {
9571 2 : CPLError(CE_Warning, CPLE_AppDefined,
9572 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9573 : "used to signal signed 8-bit raster. Change your code to "
9574 : "test for the new GDT_Int8 data type instead.");
9575 : }
9576 619271 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9577 : }
9578 :
9579 : /************************************************************************/
9580 : /* WindowIterator */
9581 : /************************************************************************/
9582 :
9583 : //! @cond Doxygen_Suppress
9584 :
9585 2 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
9586 : int nRasterYSize,
9587 : int nBlockXSize, int nBlockYSize,
9588 2 : int nRow, int nCol)
9589 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
9590 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
9591 2 : m_col(nCol)
9592 : {
9593 2 : }
9594 :
9595 10 : bool GDALRasterBand::WindowIterator::operator==(
9596 : const WindowIterator &other) const
9597 : {
9598 1 : return m_row == other.m_row && m_col == other.m_col &&
9599 1 : m_nRasterXSize == other.m_nRasterXSize &&
9600 1 : m_nRasterYSize == other.m_nRasterYSize &&
9601 12 : m_nBlockXSize == other.m_nBlockXSize &&
9602 11 : m_nBlockYSize == other.m_nBlockYSize;
9603 : }
9604 :
9605 10 : bool GDALRasterBand::WindowIterator::operator!=(
9606 : const WindowIterator &other) const
9607 : {
9608 10 : return !(*this == other);
9609 : }
9610 :
9611 : GDALRasterBand::WindowIterator::value_type
9612 9 : GDALRasterBand::WindowIterator::operator*() const
9613 : {
9614 : GDALRasterWindow ret;
9615 9 : ret.nXOff = m_col * m_nBlockXSize;
9616 9 : ret.nYOff = m_row * m_nBlockYSize;
9617 9 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
9618 9 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
9619 :
9620 9 : return ret;
9621 : }
9622 :
9623 9 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
9624 : {
9625 9 : m_col++;
9626 9 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
9627 : {
9628 3 : m_col = 0;
9629 3 : m_row++;
9630 : }
9631 9 : return *this;
9632 : }
9633 :
9634 2 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
9635 2 : const GDALRasterBand &band)
9636 2 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
9637 2 : m_nBlockXSize(-1), m_nBlockYSize(-1)
9638 : {
9639 2 : band.GetBlockSize(&m_nBlockXSize, &m_nBlockYSize);
9640 2 : }
9641 :
9642 : GDALRasterBand::WindowIterator
9643 1 : GDALRasterBand::WindowIteratorWrapper::begin() const
9644 : {
9645 1 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9646 1 : m_nBlockYSize, 0, 0);
9647 : }
9648 :
9649 : GDALRasterBand::WindowIterator
9650 1 : GDALRasterBand::WindowIteratorWrapper::end() const
9651 : {
9652 1 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9653 1 : m_nBlockYSize,
9654 1 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
9655 : }
9656 :
9657 : //! @endcond
9658 :
9659 : /** Return an object whose begin() and end() methods can be used to iterate
9660 : * over a GDALRasterWindow for each block in this raster band. The iteration
9661 : * order is from left to right, then from top to bottom.
9662 : *
9663 : \code{.cpp}
9664 : std::vector<double> pixelValues;
9665 : for (const auto& window : poBand->IterateWindows()) {
9666 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
9667 : window.nXSize, window.nYSize);
9668 : // check eErr
9669 : }
9670 : \endcode
9671 : *
9672 : *
9673 : * @since GDAL 3.12
9674 : */
9675 2 : GDALRasterBand::WindowIteratorWrapper GDALRasterBand::IterateWindows() const
9676 : {
9677 2 : return WindowIteratorWrapper(*this);
9678 : }
9679 :
9680 : /************************************************************************/
9681 : /* GDALMDArrayFromRasterBand */
9682 : /************************************************************************/
9683 :
9684 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9685 : {
9686 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9687 :
9688 : GDALDataset *m_poDS;
9689 : GDALRasterBand *m_poBand;
9690 : GDALExtendedDataType m_dt;
9691 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9692 : std::string m_osUnit;
9693 : std::vector<GByte> m_pabyNoData{};
9694 : std::shared_ptr<GDALMDArray> m_varX{};
9695 : std::shared_ptr<GDALMDArray> m_varY{};
9696 : std::string m_osFilename{};
9697 :
9698 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9699 : const size_t *count, const GInt64 *arrayStep,
9700 : const GPtrDiff_t *bufferStride,
9701 : const GDALExtendedDataType &bufferDataType,
9702 : void *pBuffer) const;
9703 :
9704 : protected:
9705 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9706 46 : : GDALAbstractMDArray(std::string(),
9707 46 : std::string(poDS->GetDescription()) +
9708 : CPLSPrintf(" band %d", poBand->GetBand())),
9709 46 : GDALMDArray(std::string(),
9710 46 : std::string(poDS->GetDescription()) +
9711 : CPLSPrintf(" band %d", poBand->GetBand())),
9712 : m_poDS(poDS), m_poBand(poBand),
9713 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9714 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9715 : {
9716 23 : m_poDS->Reference();
9717 :
9718 23 : int bHasNoData = false;
9719 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9720 : {
9721 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9722 0 : if (bHasNoData)
9723 : {
9724 0 : m_pabyNoData.resize(m_dt.GetSize());
9725 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9726 : m_dt.GetNumericDataType(), 0, 1);
9727 : }
9728 : }
9729 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9730 : {
9731 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9732 0 : if (bHasNoData)
9733 : {
9734 0 : m_pabyNoData.resize(m_dt.GetSize());
9735 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9736 : m_dt.GetNumericDataType(), 0, 1);
9737 : }
9738 : }
9739 : else
9740 : {
9741 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9742 23 : if (bHasNoData)
9743 : {
9744 1 : m_pabyNoData.resize(m_dt.GetSize());
9745 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9746 : m_dt.GetNumericDataType(), 0, 1);
9747 : }
9748 : }
9749 :
9750 23 : const int nXSize = poBand->GetXSize();
9751 23 : const int nYSize = poBand->GetYSize();
9752 :
9753 23 : auto poSRS = m_poDS->GetSpatialRef();
9754 46 : std::string osTypeY;
9755 46 : std::string osTypeX;
9756 46 : std::string osDirectionY;
9757 46 : std::string osDirectionX;
9758 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9759 : {
9760 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9761 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9762 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9763 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9764 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9765 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9766 : {
9767 5 : if (mapping == std::vector<int>{1, 2})
9768 : {
9769 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9770 5 : osDirectionY = "NORTH";
9771 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9772 5 : osDirectionX = "EAST";
9773 : }
9774 : }
9775 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9776 : {
9777 16 : if (mapping == std::vector<int>{2, 1})
9778 : {
9779 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9780 16 : osDirectionY = "NORTH";
9781 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9782 16 : osDirectionX = "EAST";
9783 : }
9784 : }
9785 : }
9786 :
9787 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9788 : "/", "Y", osTypeY, osDirectionY, nYSize),
9789 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9790 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9791 :
9792 23 : GDALGeoTransform gt;
9793 23 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
9794 : {
9795 44 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
9796 44 : gt[0], gt[1], 0.5);
9797 22 : m_dims[1]->SetIndexingVariable(m_varX);
9798 :
9799 44 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
9800 44 : gt[3], gt[5], 0.5);
9801 22 : m_dims[0]->SetIndexingVariable(m_varY);
9802 : }
9803 23 : }
9804 :
9805 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9806 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9807 : const GDALExtendedDataType &bufferDataType,
9808 : void *pDstBuffer) const override;
9809 :
9810 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9811 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9812 : const GDALExtendedDataType &bufferDataType,
9813 : const void *pSrcBuffer) override
9814 : {
9815 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9816 : bufferStride, bufferDataType,
9817 1 : const_cast<void *>(pSrcBuffer));
9818 : }
9819 :
9820 : public:
9821 46 : ~GDALMDArrayFromRasterBand()
9822 23 : {
9823 23 : m_poDS->ReleaseRef();
9824 46 : }
9825 :
9826 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9827 : GDALRasterBand *poBand)
9828 : {
9829 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9830 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9831 23 : array->SetSelf(array);
9832 46 : return array;
9833 : }
9834 :
9835 2 : bool IsWritable() const override
9836 : {
9837 2 : return m_poDS->GetAccess() == GA_Update;
9838 : }
9839 :
9840 97 : const std::string &GetFilename() const override
9841 : {
9842 97 : return m_osFilename;
9843 : }
9844 :
9845 : const std::vector<std::shared_ptr<GDALDimension>> &
9846 299 : GetDimensions() const override
9847 : {
9848 299 : return m_dims;
9849 : }
9850 :
9851 138 : const GDALExtendedDataType &GetDataType() const override
9852 : {
9853 138 : return m_dt;
9854 : }
9855 :
9856 3 : const std::string &GetUnit() const override
9857 : {
9858 3 : return m_osUnit;
9859 : }
9860 :
9861 29 : const void *GetRawNoDataValue() const override
9862 : {
9863 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9864 : }
9865 :
9866 2 : double GetOffset(bool *pbHasOffset,
9867 : GDALDataType *peStorageType) const override
9868 : {
9869 2 : int bHasOffset = false;
9870 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9871 2 : if (pbHasOffset)
9872 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9873 2 : if (peStorageType)
9874 1 : *peStorageType = GDT_Unknown;
9875 2 : return dfRes;
9876 : }
9877 :
9878 2 : double GetScale(bool *pbHasScale,
9879 : GDALDataType *peStorageType) const override
9880 : {
9881 2 : int bHasScale = false;
9882 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9883 2 : if (pbHasScale)
9884 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9885 2 : if (peStorageType)
9886 1 : *peStorageType = GDT_Unknown;
9887 2 : return dfRes;
9888 : }
9889 :
9890 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9891 : {
9892 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9893 84 : if (!poSrcSRS)
9894 2 : return nullptr;
9895 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9896 :
9897 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9898 82 : constexpr int iYDim = 0;
9899 82 : constexpr int iXDim = 1;
9900 246 : for (auto &m : axisMapping)
9901 : {
9902 164 : if (m == 1)
9903 82 : m = iXDim + 1;
9904 82 : else if (m == 2)
9905 82 : m = iYDim + 1;
9906 : else
9907 0 : m = 0;
9908 : }
9909 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9910 82 : return poSRS;
9911 : }
9912 :
9913 29 : std::vector<GUInt64> GetBlockSize() const override
9914 : {
9915 29 : int nBlockXSize = 0;
9916 29 : int nBlockYSize = 0;
9917 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9918 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9919 29 : static_cast<GUInt64>(nBlockXSize)};
9920 : }
9921 :
9922 : class MDIAsAttribute : public GDALAttribute
9923 : {
9924 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9925 : const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
9926 : std::string m_osValue;
9927 :
9928 : public:
9929 2 : MDIAsAttribute(const std::string &name, const std::string &value)
9930 2 : : GDALAbstractMDArray(std::string(), name),
9931 4 : GDALAttribute(std::string(), name), m_osValue(value)
9932 : {
9933 2 : }
9934 :
9935 : const std::vector<std::shared_ptr<GDALDimension>> &
9936 : GetDimensions() const override;
9937 :
9938 2 : const GDALExtendedDataType &GetDataType() const override
9939 : {
9940 2 : return m_dt;
9941 : }
9942 :
9943 1 : bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
9944 : const GPtrDiff_t *,
9945 : const GDALExtendedDataType &bufferDataType,
9946 : void *pDstBuffer) const override
9947 : {
9948 1 : const char *pszStr = m_osValue.c_str();
9949 1 : GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
9950 : bufferDataType);
9951 1 : return true;
9952 : }
9953 : };
9954 :
9955 : std::vector<std::shared_ptr<GDALAttribute>>
9956 14 : GetAttributes(CSLConstList) const override
9957 : {
9958 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9959 14 : auto papszMD = m_poBand->GetMetadata();
9960 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9961 : {
9962 2 : char *pszKey = nullptr;
9963 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9964 2 : if (pszKey && pszValue)
9965 : {
9966 : res.emplace_back(
9967 2 : std::make_shared<MDIAsAttribute>(pszKey, pszValue));
9968 : }
9969 2 : CPLFree(pszKey);
9970 : }
9971 14 : return res;
9972 : }
9973 : };
9974 :
9975 31 : bool GDALMDArrayFromRasterBand::IRead(
9976 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9977 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9978 : void *pDstBuffer) const
9979 : {
9980 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9981 31 : bufferDataType, pDstBuffer);
9982 : }
9983 :
9984 : const std::vector<std::shared_ptr<GDALDimension>> &
9985 3 : GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
9986 : {
9987 3 : return m_dims;
9988 : }
9989 :
9990 : /************************************************************************/
9991 : /* ReadWrite() */
9992 : /************************************************************************/
9993 :
9994 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9995 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9996 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9997 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9998 : {
9999 32 : constexpr size_t iDimX = 1;
10000 32 : constexpr size_t iDimY = 0;
10001 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
10002 : arrayStartIdx, count, arrayStep, bufferStride,
10003 32 : bufferDataType, pBuffer);
10004 : }
10005 :
10006 : /************************************************************************/
10007 : /* GDALMDRasterIOFromBand() */
10008 : /************************************************************************/
10009 :
10010 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
10011 : size_t iDimX, size_t iDimY,
10012 : const GUInt64 *arrayStartIdx, const size_t *count,
10013 : const GInt64 *arrayStep,
10014 : const GPtrDiff_t *bufferStride,
10015 : const GDALExtendedDataType &bufferDataType,
10016 : void *pBuffer)
10017 : {
10018 65 : const auto eDT(bufferDataType.GetNumericDataType());
10019 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
10020 65 : const int nX =
10021 65 : arrayStep[iDimX] > 0
10022 65 : ? static_cast<int>(arrayStartIdx[iDimX])
10023 2 : : static_cast<int>(arrayStartIdx[iDimX] -
10024 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
10025 65 : const int nY =
10026 65 : arrayStep[iDimY] > 0
10027 65 : ? static_cast<int>(arrayStartIdx[iDimY])
10028 2 : : static_cast<int>(arrayStartIdx[iDimY] -
10029 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
10030 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10031 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10032 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10033 65 : int nStrideXSign = 1;
10034 65 : if (arrayStep[iDimX] < 0)
10035 : {
10036 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10037 2 : nStrideXSign = -1;
10038 : }
10039 65 : int nStrideYSign = 1;
10040 65 : if (arrayStep[iDimY] < 0)
10041 : {
10042 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10043 2 : nStrideYSign = -1;
10044 : }
10045 :
10046 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10047 65 : static_cast<int>(count[iDimX]),
10048 65 : static_cast<int>(count[iDimY]), eDT,
10049 : static_cast<GSpacing>(
10050 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10051 : static_cast<GSpacing>(
10052 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10053 65 : nullptr) == CE_None;
10054 : }
10055 :
10056 : /************************************************************************/
10057 : /* AsMDArray() */
10058 : /************************************************************************/
10059 :
10060 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10061 : *
10062 : * The band must be linked to a GDALDataset. If this dataset is not already
10063 : * marked as shared, it will be, so that the returned array holds a reference
10064 : * to it.
10065 : *
10066 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10067 : * returned array will have an associated indexing variable.
10068 : *
10069 : * This is the same as the C function GDALRasterBandAsMDArray().
10070 : *
10071 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10072 : *
10073 : * @return a new array, or nullptr.
10074 : *
10075 : * @since GDAL 3.1
10076 : */
10077 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10078 : {
10079 23 : if (!poDS)
10080 : {
10081 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10082 0 : return nullptr;
10083 : }
10084 23 : if (!poDS->GetShared())
10085 : {
10086 23 : poDS->MarkAsShared();
10087 : }
10088 : return GDALMDArrayFromRasterBand::Create(
10089 23 : poDS, const_cast<GDALRasterBand *>(this));
10090 : }
10091 :
10092 : /************************************************************************/
10093 : /* InterpolateAtPoint() */
10094 : /************************************************************************/
10095 :
10096 : /**
10097 : * \brief Interpolates the value between pixels using a resampling algorithm,
10098 : * taking pixel/line coordinates as input.
10099 : *
10100 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10101 : * @param dfLine line coordinate as a double, where interpolation should be done.
10102 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10103 : * @param pdfRealValue pointer to real part of interpolated value
10104 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10105 : *
10106 : * @return CE_None on success, or an error code on failure.
10107 : * @since GDAL 3.10
10108 : */
10109 :
10110 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10111 : GDALRIOResampleAlg eInterpolation,
10112 : double *pdfRealValue,
10113 : double *pdfImagValue) const
10114 : {
10115 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10116 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10117 : eInterpolation != GRIORA_CubicSpline)
10118 : {
10119 2 : CPLError(CE_Failure, CPLE_AppDefined,
10120 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10121 : "methods "
10122 : "allowed");
10123 :
10124 2 : return CE_Failure;
10125 : }
10126 :
10127 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10128 165 : if (!m_poPointsCache)
10129 85 : m_poPointsCache = new GDALDoublePointsCache();
10130 :
10131 : const bool res =
10132 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10133 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10134 :
10135 165 : return res ? CE_None : CE_Failure;
10136 : }
10137 :
10138 : /************************************************************************/
10139 : /* GDALRasterInterpolateAtPoint() */
10140 : /************************************************************************/
10141 :
10142 : /**
10143 : * \brief Interpolates the value between pixels using
10144 : * a resampling algorithm
10145 : *
10146 : * @see GDALRasterBand::InterpolateAtPoint()
10147 : * @since GDAL 3.10
10148 : */
10149 :
10150 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10151 : double dfLine,
10152 : GDALRIOResampleAlg eInterpolation,
10153 : double *pdfRealValue, double *pdfImagValue)
10154 : {
10155 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10156 :
10157 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10158 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10159 144 : pdfRealValue, pdfImagValue);
10160 : }
10161 :
10162 : /************************************************************************/
10163 : /* InterpolateAtGeolocation() */
10164 : /************************************************************************/
10165 :
10166 : /**
10167 : * \brief Interpolates the value between pixels using a resampling algorithm,
10168 : * taking georeferenced coordinates as input.
10169 : *
10170 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10171 : * must be in the "natural" SRS of the dataset, that is the one returned by
10172 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10173 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10174 : * array (generally WGS 84) if there is a geolocation array.
10175 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10176 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10177 : * be a easting, and dfGeolocY a northing.
10178 : *
10179 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10180 : * expressed in that CRS, and that tuple must be conformant with the
10181 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10182 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10183 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10184 : * before calling this method, and in that case, dfGeolocX must be a longitude
10185 : * or an easting value, and dfGeolocX a latitude or a northing value.
10186 : *
10187 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10188 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10189 : * it for details on how that transformation is done.
10190 : *
10191 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10192 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10193 : * where interpolation should be done.
10194 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10195 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10196 : * where interpolation should be done.
10197 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10198 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10199 : * @param pdfRealValue pointer to real part of interpolated value
10200 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10201 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10202 : *
10203 : * @return CE_None on success, or an error code on failure.
10204 : * @since GDAL 3.11
10205 : */
10206 :
10207 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
10208 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10209 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10210 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
10211 : {
10212 : double dfPixel;
10213 : double dfLine;
10214 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10215 : &dfLine,
10216 15 : papszTransformerOptions) != CE_None)
10217 : {
10218 1 : return CE_Failure;
10219 : }
10220 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10221 14 : pdfImagValue);
10222 : }
10223 :
10224 : /************************************************************************/
10225 : /* GDALRasterInterpolateAtGeolocation() */
10226 : /************************************************************************/
10227 :
10228 : /**
10229 : * \brief Interpolates the value between pixels using a resampling algorithm,
10230 : * taking georeferenced coordinates as input.
10231 : *
10232 : * @see GDALRasterBand::InterpolateAtGeolocation()
10233 : * @since GDAL 3.11
10234 : */
10235 :
10236 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10237 : double dfGeolocX, double dfGeolocY,
10238 : OGRSpatialReferenceH hSRS,
10239 : GDALRIOResampleAlg eInterpolation,
10240 : double *pdfRealValue,
10241 : double *pdfImagValue,
10242 : CSLConstList papszTransformerOptions)
10243 : {
10244 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10245 :
10246 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10247 15 : return poBand->InterpolateAtGeolocation(
10248 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10249 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10250 : }
10251 :
10252 : /************************************************************************/
10253 : /* GDALRasterBand::SplitRasterIO() */
10254 : /************************************************************************/
10255 :
10256 : //! @cond Doxygen_Suppress
10257 :
10258 : /** Implements IRasterIO() by dividing the request in 2.
10259 : *
10260 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10261 : *
10262 : * Return CE_Warning if the split could not be done, CE_None in case of
10263 : * success and CE_Failure in case of error.
10264 : *
10265 : * @since 3.12
10266 : */
10267 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10268 : [[maybe_unused]] int nXSize,
10269 : [[maybe_unused]] int nYSize, void *pData,
10270 : int nBufXSize, int nBufYSize,
10271 : GDALDataType eBufType,
10272 : GSpacing nPixelSpace, GSpacing nLineSpace,
10273 : GDALRasterIOExtraArg *psExtraArg)
10274 : {
10275 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10276 :
10277 999 : GByte *pabyData = static_cast<GByte *>(pData);
10278 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10279 : {
10280 : GDALRasterIOExtraArg sArg;
10281 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
10282 499 : const int nHalfHeight = nBufYSize / 2;
10283 :
10284 499 : sArg.pfnProgress = GDALScaledProgress;
10285 499 : sArg.pProgressData = GDALCreateScaledProgress(
10286 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10287 499 : if (sArg.pProgressData == nullptr)
10288 499 : sArg.pfnProgress = nullptr;
10289 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10290 : pabyData, nBufXSize, nHalfHeight, eBufType,
10291 499 : nPixelSpace, nLineSpace, &sArg);
10292 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10293 :
10294 499 : if (eErr == CE_None)
10295 : {
10296 499 : sArg.pfnProgress = GDALScaledProgress;
10297 499 : sArg.pProgressData = GDALCreateScaledProgress(
10298 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10299 499 : if (sArg.pProgressData == nullptr)
10300 499 : sArg.pfnProgress = nullptr;
10301 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10302 : nBufYSize - nHalfHeight,
10303 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
10304 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10305 499 : nLineSpace, &sArg);
10306 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10307 : }
10308 499 : return eErr;
10309 : }
10310 500 : else if (nBufXSize >= 2)
10311 : {
10312 : GDALRasterIOExtraArg sArg;
10313 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
10314 500 : const int nHalfWidth = nBufXSize / 2;
10315 :
10316 500 : sArg.pfnProgress = GDALScaledProgress;
10317 500 : sArg.pProgressData = GDALCreateScaledProgress(
10318 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10319 500 : if (sArg.pProgressData == nullptr)
10320 500 : sArg.pfnProgress = nullptr;
10321 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10322 : pabyData, nHalfWidth, nBufYSize, eBufType,
10323 500 : nPixelSpace, nLineSpace, &sArg);
10324 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10325 :
10326 500 : if (eErr == CE_None)
10327 : {
10328 500 : sArg.pfnProgress = GDALScaledProgress;
10329 500 : sArg.pProgressData = GDALCreateScaledProgress(
10330 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10331 500 : if (sArg.pProgressData == nullptr)
10332 500 : sArg.pfnProgress = nullptr;
10333 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10334 : nBufXSize - nHalfWidth, nBufYSize,
10335 500 : pabyData + nHalfWidth * nPixelSpace,
10336 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
10337 500 : nPixelSpace, nLineSpace, &sArg);
10338 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10339 : }
10340 500 : return eErr;
10341 : }
10342 :
10343 0 : return CE_Warning;
10344 : }
10345 :
10346 : //! @endcond
10347 :
10348 : /************************************************************************/
10349 : /* ThrowIfNotSameDimensions() */
10350 : /************************************************************************/
10351 :
10352 : //! @cond Doxygen_Suppress
10353 : /* static */
10354 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
10355 : const GDALRasterBand &second)
10356 : {
10357 320 : if (first.GetXSize() != second.GetXSize() ||
10358 151 : first.GetYSize() != second.GetYSize())
10359 : {
10360 36 : throw std::runtime_error("Bands do not have the same dimensions");
10361 : }
10362 133 : }
10363 :
10364 : //! @endcond
10365 :
10366 : /************************************************************************/
10367 : /* GDALRasterBandUnaryOp() */
10368 : /************************************************************************/
10369 :
10370 : /** Apply a unary operation on this band.
10371 : *
10372 : * The resulting band is lazy evaluated. A reference is taken on the input
10373 : * dataset.
10374 : *
10375 : * @since 3.12
10376 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10377 : */
10378 : GDALComputedRasterBandH
10379 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
10380 : GDALRasterAlgebraUnaryOperation eOp)
10381 : {
10382 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10383 6 : GDALComputedRasterBand::Operation cppOp{};
10384 6 : switch (eOp)
10385 : {
10386 2 : case GRAUO_LOGICAL_NOT:
10387 : return new GDALComputedRasterBand(
10388 : GDALComputedRasterBand::Operation::OP_NE,
10389 2 : *(GDALRasterBand::FromHandle(hBand)), true);
10390 1 : case GRAUO_ABS:
10391 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
10392 1 : break;
10393 1 : case GRAUO_SQRT:
10394 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
10395 1 : break;
10396 1 : case GRAUO_LOG:
10397 : #ifndef HAVE_MUPARSER
10398 : CPLError(
10399 : CE_Failure, CPLE_NotSupported,
10400 : "log(band) not available on a GDAL build without muparser");
10401 : return nullptr;
10402 : #else
10403 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
10404 1 : break;
10405 : #endif
10406 1 : case GRAUO_LOG10:
10407 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
10408 1 : break;
10409 : }
10410 : return new GDALComputedRasterBand(cppOp,
10411 4 : *(GDALRasterBand::FromHandle(hBand)));
10412 : }
10413 :
10414 : /************************************************************************/
10415 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
10416 : /************************************************************************/
10417 :
10418 : static GDALComputedRasterBand::Operation
10419 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
10420 : GDALRasterAlgebraBinaryOperation eOp)
10421 : {
10422 120 : switch (eOp)
10423 : {
10424 26 : case GRABO_ADD:
10425 26 : return GDALComputedRasterBand::Operation::OP_ADD;
10426 2 : case GRABO_SUB:
10427 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
10428 24 : case GRABO_MUL:
10429 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
10430 3 : case GRABO_DIV:
10431 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
10432 6 : case GRABO_GT:
10433 6 : return GDALComputedRasterBand::Operation::OP_GT;
10434 8 : case GRABO_GE:
10435 8 : return GDALComputedRasterBand::Operation::OP_GE;
10436 6 : case GRABO_LT:
10437 6 : return GDALComputedRasterBand::Operation::OP_LT;
10438 6 : case GRABO_LE:
10439 6 : return GDALComputedRasterBand::Operation::OP_LE;
10440 6 : case GRABO_EQ:
10441 6 : return GDALComputedRasterBand::Operation::OP_EQ;
10442 6 : case GRABO_NE:
10443 6 : break;
10444 12 : case GRABO_LOGICAL_AND:
10445 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
10446 12 : case GRABO_LOGICAL_OR:
10447 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
10448 3 : case GRABO_POW:
10449 3 : return GDALComputedRasterBand::Operation::OP_POW;
10450 : }
10451 6 : return GDALComputedRasterBand::Operation::OP_NE;
10452 : }
10453 :
10454 : /************************************************************************/
10455 : /* GDALRasterBandBinaryOpBand() */
10456 : /************************************************************************/
10457 :
10458 : /** Apply a binary operation on this band with another one.
10459 : *
10460 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
10461 : * "hBand1 - hBand2".
10462 : *
10463 : * The resulting band is lazy evaluated. A reference is taken on both input
10464 : * datasets.
10465 : *
10466 : * @since 3.12
10467 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10468 : */
10469 : GDALComputedRasterBandH
10470 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
10471 : GDALRasterAlgebraBinaryOperation eOp,
10472 : GDALRasterBandH hOtherBand)
10473 : {
10474 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10475 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
10476 : #ifndef HAVE_MUPARSER
10477 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10478 : {
10479 : CPLError(
10480 : CE_Failure, CPLE_NotSupported,
10481 : "Band comparison operators not available on a GDAL build without "
10482 : "muparser");
10483 : return nullptr;
10484 : }
10485 : else if (eOp == GRABO_POW)
10486 : {
10487 : CPLError(
10488 : CE_Failure, CPLE_NotSupported,
10489 : "pow(band, band) not available on a GDAL build without muparser");
10490 : return nullptr;
10491 : }
10492 : #endif
10493 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
10494 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
10495 : try
10496 : {
10497 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
10498 : }
10499 13 : catch (const std::exception &e)
10500 : {
10501 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
10502 13 : return nullptr;
10503 : }
10504 : return new GDALComputedRasterBand(
10505 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
10506 44 : secondBand);
10507 : }
10508 :
10509 : /************************************************************************/
10510 : /* GDALRasterBandBinaryOpDouble() */
10511 : /************************************************************************/
10512 :
10513 : /** Apply a binary operation on this band with a constant
10514 : *
10515 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
10516 : * "hBand - constant".
10517 : *
10518 : * The resulting band is lazy evaluated. A reference is taken on the input
10519 : * dataset.
10520 : *
10521 : * @since 3.12
10522 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10523 : */
10524 : GDALComputedRasterBandH
10525 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
10526 : GDALRasterAlgebraBinaryOperation eOp,
10527 : double constant)
10528 : {
10529 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10530 : #ifndef HAVE_MUPARSER
10531 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10532 : {
10533 : CPLError(
10534 : CE_Failure, CPLE_NotSupported,
10535 : "Band comparison operators not available on a GDAL build without "
10536 : "muparser");
10537 : return nullptr;
10538 : }
10539 : #endif
10540 : return new GDALComputedRasterBand(
10541 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10542 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
10543 : }
10544 :
10545 : /************************************************************************/
10546 : /* GDALRasterBandBinaryOpDoubleToBand() */
10547 : /************************************************************************/
10548 :
10549 : /** Apply a binary operation on the constant with this band
10550 : *
10551 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
10552 : * "constant - hBand".
10553 : *
10554 : * The resulting band is lazy evaluated. A reference is taken on the input
10555 : * dataset.
10556 : *
10557 : * @since 3.12
10558 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10559 : */
10560 : GDALComputedRasterBandH
10561 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
10562 : GDALRasterAlgebraBinaryOperation eOp,
10563 : GDALRasterBandH hBand)
10564 : {
10565 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10566 : #ifndef HAVE_MUPARSER
10567 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10568 : {
10569 : CPLError(
10570 : CE_Failure, CPLE_NotSupported,
10571 : "Band comparison operators not available on a GDAL build without "
10572 : "muparser");
10573 : return nullptr;
10574 : }
10575 : #endif
10576 18 : switch (eOp)
10577 : {
10578 15 : case GRABO_ADD:
10579 : case GRABO_MUL:
10580 : {
10581 : return new GDALComputedRasterBand(
10582 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10583 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
10584 : }
10585 :
10586 2 : case GRABO_DIV:
10587 : case GRABO_GT:
10588 : case GRABO_GE:
10589 : case GRABO_LT:
10590 : case GRABO_LE:
10591 : case GRABO_EQ:
10592 : case GRABO_NE:
10593 : case GRABO_LOGICAL_AND:
10594 : case GRABO_LOGICAL_OR:
10595 : case GRABO_POW:
10596 : {
10597 : return new GDALComputedRasterBand(
10598 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
10599 2 : *(GDALRasterBand::FromHandle(hBand)));
10600 : }
10601 :
10602 1 : case GRABO_SUB:
10603 : {
10604 1 : break;
10605 : }
10606 : }
10607 :
10608 : return new GDALComputedRasterBand(
10609 : GDALComputedRasterBand::Operation::OP_ADD,
10610 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
10611 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
10612 1 : constant);
10613 : }
10614 :
10615 : /************************************************************************/
10616 : /* operator+() */
10617 : /************************************************************************/
10618 :
10619 : /** Add this band with another one.
10620 : *
10621 : * The resulting band is lazy evaluated. A reference is taken on both input
10622 : * datasets.
10623 : *
10624 : * @since 3.12
10625 : * @throw std::runtime_error if both bands do not have the same dimensions.
10626 : */
10627 : GDALComputedRasterBand
10628 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
10629 : {
10630 8 : ThrowIfNotSameDimensions(*this, other);
10631 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10632 7 : *this, other);
10633 : }
10634 :
10635 : /************************************************************************/
10636 : /* operator+() */
10637 : /************************************************************************/
10638 :
10639 : /** Add this band with a constant.
10640 : *
10641 : * The resulting band is lazy evaluated. A reference is taken on the input
10642 : * dataset.
10643 : *
10644 : * @since 3.12
10645 : */
10646 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
10647 : {
10648 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10649 13 : *this, constant);
10650 : }
10651 :
10652 : /************************************************************************/
10653 : /* operator+() */
10654 : /************************************************************************/
10655 :
10656 : /** Add a band with a constant.
10657 : *
10658 : * The resulting band is lazy evaluated. A reference is taken on the input
10659 : * dataset.
10660 : *
10661 : * @since 3.12
10662 : */
10663 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
10664 : {
10665 1 : return other + constant;
10666 : }
10667 :
10668 : /************************************************************************/
10669 : /* operator-() */
10670 : /************************************************************************/
10671 :
10672 : /** Return a band whose value is the opposite value of the band for each
10673 : * pixel.
10674 : *
10675 : * The resulting band is lazy evaluated. A reference is taken on the input
10676 : * dataset.
10677 : *
10678 : * @since 3.12
10679 : */
10680 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
10681 : {
10682 2 : return 0 - *this;
10683 : }
10684 :
10685 : /************************************************************************/
10686 : /* operator-() */
10687 : /************************************************************************/
10688 :
10689 : /** Subtract this band with another one.
10690 : *
10691 : * The resulting band is lazy evaluated. A reference is taken on both input
10692 : * datasets.
10693 : *
10694 : * @since 3.12
10695 : * @throw std::runtime_error if both bands do not have the same dimensions.
10696 : */
10697 : GDALComputedRasterBand
10698 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
10699 : {
10700 2 : ThrowIfNotSameDimensions(*this, other);
10701 : return GDALComputedRasterBand(
10702 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
10703 : }
10704 :
10705 : /************************************************************************/
10706 : /* operator-() */
10707 : /************************************************************************/
10708 :
10709 : /** Subtract this band with a constant.
10710 : *
10711 : * The resulting band is lazy evaluated. A reference is taken on the input
10712 : * dataset.
10713 : *
10714 : * @since 3.12
10715 : */
10716 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
10717 : {
10718 : return GDALComputedRasterBand(
10719 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
10720 : }
10721 :
10722 : /************************************************************************/
10723 : /* operator-() */
10724 : /************************************************************************/
10725 :
10726 : /** Subtract a constant with a band.
10727 : *
10728 : * The resulting band is lazy evaluated. A reference is taken on the input
10729 : * dataset.
10730 : *
10731 : * @since 3.12
10732 : */
10733 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
10734 : {
10735 6 : return other * (-1.0) + constant;
10736 : }
10737 :
10738 : /************************************************************************/
10739 : /* operator*() */
10740 : /************************************************************************/
10741 :
10742 : /** Multiply this band with another one.
10743 : *
10744 : * The resulting band is lazy evaluated. A reference is taken on both input
10745 : * datasets.
10746 : *
10747 : * @since 3.12
10748 : * @throw std::runtime_error if both bands do not have the same dimensions.
10749 : */
10750 : GDALComputedRasterBand
10751 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
10752 : {
10753 2 : ThrowIfNotSameDimensions(*this, other);
10754 : return GDALComputedRasterBand(
10755 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
10756 : }
10757 :
10758 : /************************************************************************/
10759 : /* operator*() */
10760 : /************************************************************************/
10761 :
10762 : /** Multiply this band by a constant.
10763 : *
10764 : * The resulting band is lazy evaluated. A reference is taken on the input
10765 : * dataset.
10766 : *
10767 : * @since 3.12
10768 : */
10769 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
10770 : {
10771 : return GDALComputedRasterBand(
10772 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
10773 : }
10774 :
10775 : /************************************************************************/
10776 : /* operator*() */
10777 : /************************************************************************/
10778 :
10779 : /** Multiply a band with a constant.
10780 : *
10781 : * The resulting band is lazy evaluated. A reference is taken on the input
10782 : * dataset.
10783 : *
10784 : * @since 3.12
10785 : */
10786 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
10787 : {
10788 2 : return other * constant;
10789 : }
10790 :
10791 : /************************************************************************/
10792 : /* operator/() */
10793 : /************************************************************************/
10794 :
10795 : /** Divide this band with another one.
10796 : *
10797 : * The resulting band is lazy evaluated. A reference is taken on both input
10798 : * datasets.
10799 : *
10800 : * @since 3.12
10801 : * @throw std::runtime_error if both bands do not have the same dimensions.
10802 : */
10803 : GDALComputedRasterBand
10804 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
10805 : {
10806 2 : ThrowIfNotSameDimensions(*this, other);
10807 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10808 2 : *this, other);
10809 : }
10810 :
10811 : /************************************************************************/
10812 : /* operator/() */
10813 : /************************************************************************/
10814 :
10815 : /** Divide this band by a constant.
10816 : *
10817 : * The resulting band is lazy evaluated. A reference is taken on the input
10818 : * dataset.
10819 : *
10820 : * @since 3.12
10821 : */
10822 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
10823 : {
10824 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10825 0 : *this, constant);
10826 : }
10827 :
10828 : /************************************************************************/
10829 : /* operator/() */
10830 : /************************************************************************/
10831 :
10832 : /** Divide a constant by a band.
10833 : *
10834 : * The resulting band is lazy evaluated. A reference is taken on the input
10835 : * dataset.
10836 : *
10837 : * @since 3.12
10838 : */
10839 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
10840 : {
10841 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10842 1 : constant, other);
10843 : }
10844 :
10845 : /************************************************************************/
10846 : /* ThrowIfNotMuparser() */
10847 : /************************************************************************/
10848 :
10849 : #ifndef HAVE_MUPARSER
10850 : static GDALComputedRasterBand ThrowIfNotMuparser()
10851 : {
10852 : throw std::runtime_error("Operator not available on a "
10853 : "GDAL build without muparser");
10854 : }
10855 : #endif
10856 :
10857 : /************************************************************************/
10858 : /* operator>() */
10859 : /************************************************************************/
10860 :
10861 : /** Return a band whose value is 1 if the pixel value of the left operand
10862 : * is greater than the pixel value of the right operand.
10863 : *
10864 : * The resulting band is lazy evaluated. A reference is taken on the input
10865 : * dataset.
10866 : *
10867 : * @since 3.12
10868 : */
10869 : GDALComputedRasterBand
10870 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
10871 : {
10872 : #ifndef HAVE_MUPARSER
10873 : (void)other;
10874 : return ThrowIfNotMuparser();
10875 : #else
10876 3 : ThrowIfNotSameDimensions(*this, other);
10877 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10878 2 : *this, other);
10879 : #endif
10880 : }
10881 :
10882 : /************************************************************************/
10883 : /* operator>() */
10884 : /************************************************************************/
10885 :
10886 : /** Return a band whose value is 1 if the pixel value of the left operand
10887 : * is greater than the constant.
10888 : *
10889 : * The resulting band is lazy evaluated. A reference is taken on the input
10890 : * dataset.
10891 : *
10892 : * @since 3.12
10893 : */
10894 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
10895 : {
10896 : #ifndef HAVE_MUPARSER
10897 : (void)constant;
10898 : return ThrowIfNotMuparser();
10899 : #else
10900 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10901 3 : *this, constant);
10902 : #endif
10903 : }
10904 :
10905 : /************************************************************************/
10906 : /* operator>() */
10907 : /************************************************************************/
10908 :
10909 : /** Return a band whose value is 1 if the constant is greater than the pixel
10910 : * value of the right operand.
10911 : *
10912 : * The resulting band is lazy evaluated. A reference is taken on the input
10913 : * dataset.
10914 : *
10915 : * @since 3.12
10916 : */
10917 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
10918 : {
10919 : #ifndef HAVE_MUPARSER
10920 : (void)constant;
10921 : (void)other;
10922 : return ThrowIfNotMuparser();
10923 : #else
10924 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10925 2 : constant, other);
10926 : #endif
10927 : }
10928 :
10929 : /************************************************************************/
10930 : /* operator>=() */
10931 : /************************************************************************/
10932 :
10933 : /** Return a band whose value is 1 if the pixel value of the left operand
10934 : * is greater or equal to the pixel value of the right operand.
10935 : *
10936 : * The resulting band is lazy evaluated. A reference is taken on the input
10937 : * dataset.
10938 : *
10939 : * @since 3.12
10940 : */
10941 : GDALComputedRasterBand
10942 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
10943 : {
10944 : #ifndef HAVE_MUPARSER
10945 : (void)other;
10946 : return ThrowIfNotMuparser();
10947 : #else
10948 4 : ThrowIfNotSameDimensions(*this, other);
10949 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10950 3 : *this, other);
10951 : #endif
10952 : }
10953 :
10954 : /************************************************************************/
10955 : /* operator>=() */
10956 : /************************************************************************/
10957 :
10958 : /** Return a band whose value is 1 if the pixel value of the left operand
10959 : * is greater or equal to the constant.
10960 : *
10961 : * The resulting band is lazy evaluated. A reference is taken on the input
10962 : * dataset.
10963 : *
10964 : * @since 3.12
10965 : */
10966 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
10967 : {
10968 : #ifndef HAVE_MUPARSER
10969 : (void)constant;
10970 : return ThrowIfNotMuparser();
10971 : #else
10972 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10973 3 : *this, constant);
10974 : #endif
10975 : }
10976 :
10977 : /************************************************************************/
10978 : /* operator>=() */
10979 : /************************************************************************/
10980 :
10981 : /** Return a band whose value is 1 if the constant is greater or equal to
10982 : * the pixel value of the right operand.
10983 : *
10984 : * The resulting band is lazy evaluated. A reference is taken on the input
10985 : * dataset.
10986 : *
10987 : * @since 3.12
10988 : */
10989 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
10990 : {
10991 : #ifndef HAVE_MUPARSER
10992 : (void)constant;
10993 : (void)other;
10994 : return ThrowIfNotMuparser();
10995 : #else
10996 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10997 2 : constant, other);
10998 : #endif
10999 : }
11000 :
11001 : /************************************************************************/
11002 : /* operator<() */
11003 : /************************************************************************/
11004 :
11005 : /** Return a band whose value is 1 if the pixel value of the left operand
11006 : * is lesser than the pixel value of the right operand.
11007 : *
11008 : * The resulting band is lazy evaluated. A reference is taken on the input
11009 : * dataset.
11010 : *
11011 : * @since 3.12
11012 : */
11013 : GDALComputedRasterBand
11014 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
11015 : {
11016 : #ifndef HAVE_MUPARSER
11017 : (void)other;
11018 : return ThrowIfNotMuparser();
11019 : #else
11020 3 : ThrowIfNotSameDimensions(*this, other);
11021 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11022 2 : *this, other);
11023 : #endif
11024 : }
11025 :
11026 : /************************************************************************/
11027 : /* operator<() */
11028 : /************************************************************************/
11029 :
11030 : /** Return a band whose value is 1 if the pixel value of the left operand
11031 : * is lesser than the constant.
11032 : *
11033 : * The resulting band is lazy evaluated. A reference is taken on the input
11034 : * dataset.
11035 : *
11036 : * @since 3.12
11037 : */
11038 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11039 : {
11040 : #ifndef HAVE_MUPARSER
11041 : (void)constant;
11042 : return ThrowIfNotMuparser();
11043 : #else
11044 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11045 3 : *this, constant);
11046 : #endif
11047 : }
11048 :
11049 : /************************************************************************/
11050 : /* operator<() */
11051 : /************************************************************************/
11052 :
11053 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11054 : * value of the right operand.
11055 : *
11056 : * The resulting band is lazy evaluated. A reference is taken on the input
11057 : * dataset.
11058 : *
11059 : * @since 3.12
11060 : */
11061 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11062 : {
11063 : #ifndef HAVE_MUPARSER
11064 : (void)constant;
11065 : (void)other;
11066 : return ThrowIfNotMuparser();
11067 : #else
11068 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11069 2 : constant, other);
11070 : #endif
11071 : }
11072 :
11073 : /************************************************************************/
11074 : /* operator<=() */
11075 : /************************************************************************/
11076 :
11077 : /** Return a band whose value is 1 if the pixel value of the left operand
11078 : * is lesser or equal to the pixel value of the right operand.
11079 : *
11080 : * The resulting band is lazy evaluated. A reference is taken on the input
11081 : * dataset.
11082 : *
11083 : * @since 3.12
11084 : */
11085 : GDALComputedRasterBand
11086 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11087 : {
11088 : #ifndef HAVE_MUPARSER
11089 : (void)other;
11090 : return ThrowIfNotMuparser();
11091 : #else
11092 4 : ThrowIfNotSameDimensions(*this, other);
11093 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11094 3 : *this, other);
11095 : #endif
11096 : }
11097 :
11098 : /************************************************************************/
11099 : /* operator<=() */
11100 : /************************************************************************/
11101 :
11102 : /** Return a band whose value is 1 if the pixel value of the left operand
11103 : * is lesser or equal to the constant.
11104 : *
11105 : * The resulting band is lazy evaluated. A reference is taken on the input
11106 : * dataset.
11107 : *
11108 : * @since 3.12
11109 : */
11110 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11111 : {
11112 : #ifndef HAVE_MUPARSER
11113 : (void)constant;
11114 : return ThrowIfNotMuparser();
11115 : #else
11116 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11117 3 : *this, constant);
11118 : #endif
11119 : }
11120 :
11121 : /************************************************************************/
11122 : /* operator<=() */
11123 : /************************************************************************/
11124 :
11125 : /** Return a band whose value is 1 if the constant is lesser or equal to
11126 : * the pixel value of the right operand.
11127 : *
11128 : * The resulting band is lazy evaluated. A reference is taken on the input
11129 : * dataset.
11130 : *
11131 : * @since 3.12
11132 : */
11133 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11134 : {
11135 : #ifndef HAVE_MUPARSER
11136 : (void)constant;
11137 : (void)other;
11138 : return ThrowIfNotMuparser();
11139 : #else
11140 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11141 2 : constant, other);
11142 : #endif
11143 : }
11144 :
11145 : /************************************************************************/
11146 : /* operator==() */
11147 : /************************************************************************/
11148 :
11149 : /** Return a band whose value is 1 if the pixel value of the left operand
11150 : * is equal to the pixel value of the right operand.
11151 : *
11152 : * The resulting band is lazy evaluated. A reference is taken on the input
11153 : * dataset.
11154 : *
11155 : * @since 3.12
11156 : */
11157 : GDALComputedRasterBand
11158 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11159 : {
11160 : #ifndef HAVE_MUPARSER
11161 : (void)other;
11162 : return ThrowIfNotMuparser();
11163 : #else
11164 3 : ThrowIfNotSameDimensions(*this, other);
11165 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11166 2 : *this, other);
11167 : #endif
11168 : }
11169 :
11170 : /************************************************************************/
11171 : /* operator==() */
11172 : /************************************************************************/
11173 :
11174 : /** Return a band whose value is 1 if the pixel value of the left operand
11175 : * is equal to the constant.
11176 : *
11177 : * The resulting band is lazy evaluated. A reference is taken on the input
11178 : * dataset.
11179 : *
11180 : * @since 3.12
11181 : */
11182 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11183 : {
11184 : #ifndef HAVE_MUPARSER
11185 : (void)constant;
11186 : return ThrowIfNotMuparser();
11187 : #else
11188 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11189 8 : *this, constant);
11190 : #endif
11191 : }
11192 :
11193 : /************************************************************************/
11194 : /* operator==() */
11195 : /************************************************************************/
11196 :
11197 : /** Return a band whose value is 1 if the constant is equal to
11198 : * the pixel value of the right operand.
11199 : *
11200 : * The resulting band is lazy evaluated. A reference is taken on the input
11201 : * dataset.
11202 : *
11203 : * @since 3.12
11204 : */
11205 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
11206 : {
11207 : #ifndef HAVE_MUPARSER
11208 : (void)constant;
11209 : (void)other;
11210 : return ThrowIfNotMuparser();
11211 : #else
11212 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11213 2 : constant, other);
11214 : #endif
11215 : }
11216 :
11217 : /************************************************************************/
11218 : /* operator!=() */
11219 : /************************************************************************/
11220 :
11221 : /** Return a band whose value is 1 if the pixel value of the left operand
11222 : * is different from the pixel value of the right operand.
11223 : *
11224 : * The resulting band is lazy evaluated. A reference is taken on the input
11225 : * dataset.
11226 : *
11227 : * @since 3.12
11228 : */
11229 : GDALComputedRasterBand
11230 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
11231 : {
11232 : #ifndef HAVE_MUPARSER
11233 : (void)other;
11234 : return ThrowIfNotMuparser();
11235 : #else
11236 3 : ThrowIfNotSameDimensions(*this, other);
11237 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11238 2 : *this, other);
11239 : #endif
11240 : }
11241 :
11242 : /************************************************************************/
11243 : /* operator!=() */
11244 : /************************************************************************/
11245 :
11246 : /** Return a band whose value is 1 if the pixel value of the left operand
11247 : * is different from the constant.
11248 : *
11249 : * The resulting band is lazy evaluated. A reference is taken on the input
11250 : * dataset.
11251 : *
11252 : * @since 3.12
11253 : */
11254 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
11255 : {
11256 : #ifndef HAVE_MUPARSER
11257 : (void)constant;
11258 : return ThrowIfNotMuparser();
11259 : #else
11260 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11261 6 : *this, constant);
11262 : #endif
11263 : }
11264 :
11265 : /************************************************************************/
11266 : /* operator!=() */
11267 : /************************************************************************/
11268 :
11269 : /** Return a band whose value is 1 if the constant is different from
11270 : * the pixel value of the right operand.
11271 : *
11272 : * The resulting band is lazy evaluated. A reference is taken on the input
11273 : * dataset.
11274 : *
11275 : * @since 3.12
11276 : */
11277 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
11278 : {
11279 : #ifndef HAVE_MUPARSER
11280 : (void)constant;
11281 : (void)other;
11282 : return ThrowIfNotMuparser();
11283 : #else
11284 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11285 2 : constant, other);
11286 : #endif
11287 : }
11288 :
11289 : #if defined(__GNUC__)
11290 : #pragma GCC diagnostic push
11291 : #pragma GCC diagnostic ignored "-Weffc++"
11292 : #endif
11293 :
11294 : /************************************************************************/
11295 : /* operator&&() */
11296 : /************************************************************************/
11297 :
11298 : /** Return a band whose value is 1 if the pixel value of the left and right
11299 : * operands is true.
11300 : *
11301 : * The resulting band is lazy evaluated. A reference is taken on the input
11302 : * dataset.
11303 : *
11304 : * @since 3.12
11305 : */
11306 : GDALComputedRasterBand
11307 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
11308 : {
11309 : #ifndef HAVE_MUPARSER
11310 : (void)other;
11311 : return ThrowIfNotMuparser();
11312 : #else
11313 3 : ThrowIfNotSameDimensions(*this, other);
11314 : return GDALComputedRasterBand(
11315 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
11316 : #endif
11317 : }
11318 :
11319 : /************************************************************************/
11320 : /* operator&&() */
11321 : /************************************************************************/
11322 :
11323 : /** Return a band whose value is 1 if the pixel value of the left operand
11324 : * is true, as well as the constant
11325 : *
11326 : * The resulting band is lazy evaluated. A reference is taken on the input
11327 : * dataset.
11328 : *
11329 : * @since 3.12
11330 : */
11331 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
11332 : {
11333 : #ifndef HAVE_MUPARSER
11334 : (void)constant;
11335 : return ThrowIfNotMuparser();
11336 : #else
11337 : return GDALComputedRasterBand(
11338 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
11339 : #endif
11340 : }
11341 :
11342 : /************************************************************************/
11343 : /* operator&&() */
11344 : /************************************************************************/
11345 :
11346 : /** Return a band whose value is 1 if the constant is true, as well as
11347 : * the pixel value of the right operand.
11348 : *
11349 : * The resulting band is lazy evaluated. A reference is taken on the input
11350 : * dataset.
11351 : *
11352 : * @since 3.12
11353 : */
11354 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
11355 : {
11356 : #ifndef HAVE_MUPARSER
11357 : (void)constant;
11358 : (void)other;
11359 : return ThrowIfNotMuparser();
11360 : #else
11361 : return GDALComputedRasterBand(
11362 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
11363 : #endif
11364 : }
11365 :
11366 : /************************************************************************/
11367 : /* operator||() */
11368 : /************************************************************************/
11369 :
11370 : /** Return a band whose value is 1 if the pixel value of the left or right
11371 : * operands is true.
11372 : *
11373 : * The resulting band is lazy evaluated. A reference is taken on the input
11374 : * dataset.
11375 : *
11376 : * @since 3.12
11377 : */
11378 : GDALComputedRasterBand
11379 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
11380 : {
11381 : #ifndef HAVE_MUPARSER
11382 : (void)other;
11383 : return ThrowIfNotMuparser();
11384 : #else
11385 4 : ThrowIfNotSameDimensions(*this, other);
11386 : return GDALComputedRasterBand(
11387 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
11388 : #endif
11389 : }
11390 :
11391 : /************************************************************************/
11392 : /* operator||() */
11393 : /************************************************************************/
11394 :
11395 : /** Return a band whose value is 1 if the pixel value of the left operand
11396 : * is true, or if the constant is true
11397 : *
11398 : * The resulting band is lazy evaluated. A reference is taken on the input
11399 : * dataset.
11400 : *
11401 : * @since 3.12
11402 : */
11403 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
11404 : {
11405 : #ifndef HAVE_MUPARSER
11406 : (void)constant;
11407 : return ThrowIfNotMuparser();
11408 : #else
11409 : return GDALComputedRasterBand(
11410 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
11411 : #endif
11412 : }
11413 :
11414 : /************************************************************************/
11415 : /* operator||() */
11416 : /************************************************************************/
11417 :
11418 : /** Return a band whose value is 1 if the constant is true, or
11419 : * the pixel value of the right operand is true
11420 : *
11421 : * The resulting band is lazy evaluated. A reference is taken on the input
11422 : * dataset.
11423 : *
11424 : * @since 3.12
11425 : */
11426 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
11427 : {
11428 : #ifndef HAVE_MUPARSER
11429 : (void)constant;
11430 : (void)other;
11431 : return ThrowIfNotMuparser();
11432 : #else
11433 : return GDALComputedRasterBand(
11434 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
11435 : #endif
11436 : }
11437 :
11438 : #if defined(__GNUC__)
11439 : #pragma GCC diagnostic pop
11440 : #endif
11441 :
11442 : /************************************************************************/
11443 : /* operator!() */
11444 : /************************************************************************/
11445 :
11446 : /** Return a band whose value is the logical negation of the pixel value
11447 : *
11448 : * The resulting band is lazy evaluated. A reference is taken on the input
11449 : * dataset.
11450 : *
11451 : * @since 3.12
11452 : */
11453 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
11454 : {
11455 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11456 2 : *this, true);
11457 : }
11458 :
11459 : namespace gdal
11460 : {
11461 :
11462 : /************************************************************************/
11463 : /* IfThenElse() */
11464 : /************************************************************************/
11465 :
11466 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11467 : * is not zero, or the one from elseBand otherwise.
11468 : *
11469 : * Variants of this method exits where thenBand and/or elseBand can be double
11470 : * values.
11471 : *
11472 : * The resulting band is lazy evaluated. A reference is taken on the input
11473 : * datasets.
11474 : *
11475 : * This method is the same as the C function GDALRasterBandIfThenElse()
11476 : *
11477 : * @since 3.12
11478 : */
11479 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11480 : const GDALRasterBand &thenBand,
11481 : const GDALRasterBand &elseBand)
11482 : {
11483 : #ifndef HAVE_MUPARSER
11484 : (void)condBand;
11485 : (void)thenBand;
11486 : (void)elseBand;
11487 : return ThrowIfNotMuparser();
11488 : #else
11489 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11490 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11491 : return GDALComputedRasterBand(
11492 : GDALComputedRasterBand::Operation::OP_TERNARY,
11493 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11494 : #endif
11495 : }
11496 :
11497 : //! @cond Doxygen_Suppress
11498 :
11499 : /************************************************************************/
11500 : /* IfThenElse() */
11501 : /************************************************************************/
11502 :
11503 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11504 : * is not zero, or the one from elseBand otherwise.
11505 : *
11506 : * The resulting band is lazy evaluated. A reference is taken on the input
11507 : * datasets.
11508 : *
11509 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11510 : * with thenBand = (condBand * 0) + thenValue
11511 : *
11512 : * @since 3.12
11513 : */
11514 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11515 : double thenValue,
11516 : const GDALRasterBand &elseBand)
11517 : {
11518 : #ifndef HAVE_MUPARSER
11519 : (void)condBand;
11520 : (void)thenValue;
11521 : (void)elseBand;
11522 : return ThrowIfNotMuparser();
11523 : #else
11524 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11525 : auto thenBand =
11526 1 : (condBand * 0)
11527 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11528 1 : thenValue;
11529 : return GDALComputedRasterBand(
11530 : GDALComputedRasterBand::Operation::OP_TERNARY,
11531 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11532 : #endif
11533 : }
11534 :
11535 : /************************************************************************/
11536 : /* IfThenElse() */
11537 : /************************************************************************/
11538 :
11539 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11540 : * is not zero, or the one from elseValue otherwise.
11541 : *
11542 : * The resulting band is lazy evaluated. A reference is taken on the input
11543 : * datasets.
11544 : *
11545 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11546 : * with elseBand = (condBand * 0) + elseValue
11547 :
11548 : * @since 3.12
11549 : */
11550 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11551 : const GDALRasterBand &thenBand,
11552 : double elseValue)
11553 : {
11554 : #ifndef HAVE_MUPARSER
11555 : (void)condBand;
11556 : (void)thenBand;
11557 : (void)elseValue;
11558 : return ThrowIfNotMuparser();
11559 : #else
11560 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11561 : auto elseBand =
11562 1 : (condBand * 0)
11563 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11564 1 : elseValue;
11565 : return GDALComputedRasterBand(
11566 : GDALComputedRasterBand::Operation::OP_TERNARY,
11567 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11568 : #endif
11569 : }
11570 :
11571 : /************************************************************************/
11572 : /* IfThenElse() */
11573 : /************************************************************************/
11574 :
11575 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11576 : * is not zero, or the one from elseValue otherwise.
11577 : *
11578 : * The resulting band is lazy evaluated. A reference is taken on the input
11579 : * datasets.
11580 : *
11581 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11582 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
11583 : *
11584 : * @since 3.12
11585 : */
11586 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11587 : double thenValue, double elseValue)
11588 : {
11589 : #ifndef HAVE_MUPARSER
11590 : (void)condBand;
11591 : (void)thenValue;
11592 : (void)elseValue;
11593 : return ThrowIfNotMuparser();
11594 : #else
11595 : auto thenBand =
11596 3 : (condBand * 0)
11597 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11598 6 : thenValue;
11599 : auto elseBand =
11600 3 : (condBand * 0)
11601 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11602 3 : elseValue;
11603 : return GDALComputedRasterBand(
11604 : GDALComputedRasterBand::Operation::OP_TERNARY,
11605 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11606 : #endif
11607 : }
11608 :
11609 : //! @endcond
11610 :
11611 : } // namespace gdal
11612 :
11613 : /************************************************************************/
11614 : /* GDALRasterBandIfThenElse() */
11615 : /************************************************************************/
11616 :
11617 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
11618 : * is not zero, or the one from hElseBand otherwise.
11619 : *
11620 : * The resulting band is lazy evaluated. A reference is taken on the input
11621 : * datasets.
11622 : *
11623 : * This function is the same as the C++ method gdal::IfThenElse()
11624 : *
11625 : * @since 3.12
11626 : */
11627 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
11628 : GDALRasterBandH hThenBand,
11629 : GDALRasterBandH hElseBand)
11630 : {
11631 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
11632 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
11633 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
11634 : #ifndef HAVE_MUPARSER
11635 : CPLError(CE_Failure, CPLE_NotSupported,
11636 : "Band comparison operators not available on a GDAL build without "
11637 : "muparser");
11638 : return nullptr;
11639 : #else
11640 :
11641 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
11642 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
11643 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
11644 : try
11645 : {
11646 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11647 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11648 : }
11649 2 : catch (const std::exception &e)
11650 : {
11651 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11652 2 : return nullptr;
11653 : }
11654 : return new GDALComputedRasterBand(
11655 : GDALComputedRasterBand::Operation::OP_TERNARY,
11656 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11657 : #endif
11658 : }
11659 :
11660 : /************************************************************************/
11661 : /* GDALRasterBand::AsType() */
11662 : /************************************************************************/
11663 :
11664 : /** Cast this band to another type.
11665 : *
11666 : * The resulting band is lazy evaluated. A reference is taken on the input
11667 : * dataset.
11668 : *
11669 : * This method is the same as the C function GDALRasterBandAsDataType()
11670 : *
11671 : * @since 3.12
11672 : */
11673 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
11674 : {
11675 10 : if (dt == GDT_Unknown)
11676 : {
11677 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
11678 : }
11679 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
11680 9 : *this, dt);
11681 : }
11682 :
11683 : /************************************************************************/
11684 : /* GDALRasterBandAsDataType() */
11685 : /************************************************************************/
11686 :
11687 : /** Cast this band to another type.
11688 : *
11689 : * The resulting band is lazy evaluated. A reference is taken on the input
11690 : * dataset.
11691 : *
11692 : * This function is the same as the C++ method GDALRasterBand::AsType()
11693 : *
11694 : * @since 3.12
11695 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11696 : */
11697 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
11698 : GDALDataType eDT)
11699 : {
11700 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11701 16 : if (eDT == GDT_Unknown)
11702 : {
11703 1 : CPLError(CE_Failure, CPLE_NotSupported,
11704 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
11705 1 : return nullptr;
11706 : }
11707 : return new GDALComputedRasterBand(
11708 : GDALComputedRasterBand::Operation::OP_CAST,
11709 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
11710 : }
11711 :
11712 : /************************************************************************/
11713 : /* GetBandVector() */
11714 : /************************************************************************/
11715 :
11716 : static std::vector<const GDALRasterBand *>
11717 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
11718 : {
11719 10 : std::vector<const GDALRasterBand *> bands;
11720 27 : for (size_t i = 0; i < nBandCount; ++i)
11721 : {
11722 20 : if (i > 0)
11723 : {
11724 10 : GDALRasterBand::ThrowIfNotSameDimensions(
11725 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
11726 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
11727 : }
11728 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
11729 : }
11730 7 : return bands;
11731 : }
11732 :
11733 : /************************************************************************/
11734 : /* GDALOperationOnNBands() */
11735 : /************************************************************************/
11736 :
11737 : static GDALComputedRasterBandH
11738 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
11739 : GDALRasterBandH *pahBands)
11740 : {
11741 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
11742 11 : if (nBandCount == 0)
11743 : {
11744 1 : CPLError(CE_Failure, CPLE_AppDefined,
11745 : "At least one band should be passed");
11746 1 : return nullptr;
11747 : }
11748 :
11749 20 : std::vector<const GDALRasterBand *> bands;
11750 : try
11751 : {
11752 10 : bands = GetBandVector(nBandCount, pahBands);
11753 : }
11754 3 : catch (const std::exception &e)
11755 : {
11756 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11757 3 : return nullptr;
11758 : }
11759 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
11760 : }
11761 :
11762 : /************************************************************************/
11763 : /* GDALMaximumOfNBands() */
11764 : /************************************************************************/
11765 :
11766 : /** Return a band whose each pixel value is the maximum of the corresponding
11767 : * pixel values in the input bands.
11768 : *
11769 : * The resulting band is lazy evaluated. A reference is taken on input
11770 : * datasets.
11771 : *
11772 : * This function is the same as the C ++ method gdal::max()
11773 : *
11774 : * @since 3.12
11775 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11776 : */
11777 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
11778 : GDALRasterBandH *pahBands)
11779 : {
11780 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
11781 4 : nBandCount, pahBands);
11782 : }
11783 :
11784 : /************************************************************************/
11785 : /* gdal::max() */
11786 : /************************************************************************/
11787 :
11788 : namespace gdal
11789 : {
11790 : /** Return a band whose each pixel value is the maximum of the corresponding
11791 : * pixel values in the inputs (bands or constants)
11792 : *
11793 : * The resulting band is lazy evaluated. A reference is taken on input
11794 : * datasets.
11795 : *
11796 : * Two or more bands can be passed.
11797 : *
11798 : * This method is the same as the C function GDALMaximumOfNBands()
11799 : *
11800 : * @since 3.12
11801 : * @throw std::runtime_error if bands do not have the same dimensions.
11802 : */
11803 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
11804 : const GDALRasterBand &second)
11805 : {
11806 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11807 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
11808 1 : first, second);
11809 : }
11810 : } // namespace gdal
11811 :
11812 : /************************************************************************/
11813 : /* GDALRasterBandMaxConstant() */
11814 : /************************************************************************/
11815 :
11816 : /** Return a band whose each pixel value is the maximum of the corresponding
11817 : * pixel values in the input band and the constant.
11818 : *
11819 : * The resulting band is lazy evaluated. A reference is taken on the input
11820 : * dataset.
11821 : *
11822 : * This function is the same as the C ++ method gdal::max()
11823 : *
11824 : * @since 3.12
11825 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11826 : */
11827 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
11828 : double dfConstant)
11829 : {
11830 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11831 : GDALComputedRasterBand::Operation::OP_MAX,
11832 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11833 6 : dfConstant));
11834 : }
11835 :
11836 : /************************************************************************/
11837 : /* GDALMinimumOfNBands() */
11838 : /************************************************************************/
11839 :
11840 : /** Return a band whose each pixel value is the minimum of the corresponding
11841 : * pixel values in the input bands.
11842 : *
11843 : * The resulting band is lazy evaluated. A reference is taken on input
11844 : * datasets.
11845 : *
11846 : * This function is the same as the C ++ method gdal::min()
11847 : *
11848 : * @since 3.12
11849 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11850 : */
11851 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
11852 : GDALRasterBandH *pahBands)
11853 : {
11854 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
11855 4 : nBandCount, pahBands);
11856 : }
11857 :
11858 : /************************************************************************/
11859 : /* gdal::min() */
11860 : /************************************************************************/
11861 :
11862 : namespace gdal
11863 : {
11864 : /** Return a band whose each pixel value is the minimum of the corresponding
11865 : * pixel values in the inputs (bands or constants)
11866 : *
11867 : * The resulting band is lazy evaluated. A reference is taken on input
11868 : * datasets.
11869 : *
11870 : * Two or more bands can be passed.
11871 : *
11872 : * This method is the same as the C function GDALMinimumOfNBands()
11873 : *
11874 : * @since 3.12
11875 : * @throw std::runtime_error if bands do not have the same dimensions.
11876 : */
11877 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
11878 : const GDALRasterBand &second)
11879 : {
11880 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11881 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
11882 0 : first, second);
11883 : }
11884 : } // namespace gdal
11885 :
11886 : /************************************************************************/
11887 : /* GDALRasterBandMinConstant() */
11888 : /************************************************************************/
11889 :
11890 : /** Return a band whose each pixel value is the minimum of the corresponding
11891 : * pixel values in the input band and the constant.
11892 : *
11893 : * The resulting band is lazy evaluated. A reference is taken on the input
11894 : * dataset.
11895 : *
11896 : * This function is the same as the C ++ method gdal::min()
11897 : *
11898 : * @since 3.12
11899 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11900 : */
11901 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
11902 : double dfConstant)
11903 : {
11904 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11905 : GDALComputedRasterBand::Operation::OP_MIN,
11906 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11907 6 : dfConstant));
11908 : }
11909 :
11910 : /************************************************************************/
11911 : /* GDALMeanOfNBands() */
11912 : /************************************************************************/
11913 :
11914 : /** Return a band whose each pixel value is the arithmetic mean of the
11915 : * corresponding pixel values in the input bands.
11916 : *
11917 : * The resulting band is lazy evaluated. A reference is taken on input
11918 : * datasets.
11919 : *
11920 : * This function is the same as the C ++ method gdal::mean()
11921 : *
11922 : * @since 3.12
11923 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11924 : */
11925 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
11926 : GDALRasterBandH *pahBands)
11927 : {
11928 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
11929 3 : nBandCount, pahBands);
11930 : }
11931 :
11932 : /************************************************************************/
11933 : /* gdal::mean() */
11934 : /************************************************************************/
11935 :
11936 : namespace gdal
11937 : {
11938 :
11939 : /** Return a band whose each pixel value is the arithmetic mean of the
11940 : * corresponding pixel values in the input bands.
11941 : *
11942 : * The resulting band is lazy evaluated. A reference is taken on input
11943 : * datasets.
11944 : *
11945 : * Two or more bands can be passed.
11946 : *
11947 : * This method is the same as the C function GDALMeanOfNBands()
11948 : *
11949 : * @since 3.12
11950 : * @throw std::runtime_error if bands do not have the same dimensions.
11951 : */
11952 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
11953 : const GDALRasterBand &second)
11954 : {
11955 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11956 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
11957 0 : first, second);
11958 : }
11959 : } // namespace gdal
11960 :
11961 : /************************************************************************/
11962 : /* gdal::abs() */
11963 : /************************************************************************/
11964 :
11965 : namespace gdal
11966 : {
11967 :
11968 : /** Return a band whose each pixel value is the absolute value (or module
11969 : * for complex data type) of the corresponding pixel value in the input band.
11970 : *
11971 : * The resulting band is lazy evaluated. A reference is taken on input
11972 : * datasets.
11973 : *
11974 : * @since 3.12
11975 : */
11976 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
11977 : {
11978 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
11979 1 : band);
11980 : }
11981 : } // namespace gdal
11982 :
11983 : /************************************************************************/
11984 : /* gdal::fabs() */
11985 : /************************************************************************/
11986 :
11987 : namespace gdal
11988 : {
11989 :
11990 : /** Return a band whose each pixel value is the absolute value (or module
11991 : * for complex data type) of the corresponding pixel value in the input band.
11992 : *
11993 : * The resulting band is lazy evaluated. A reference is taken on input
11994 : * datasets.
11995 : *
11996 : * @since 3.12
11997 : */
11998 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
11999 : {
12000 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
12001 1 : band);
12002 : }
12003 : } // namespace gdal
12004 :
12005 : /************************************************************************/
12006 : /* gdal::sqrt() */
12007 : /************************************************************************/
12008 :
12009 : namespace gdal
12010 : {
12011 :
12012 : /** Return a band whose each pixel value is the square root of the
12013 : * corresponding pixel value in the input band.
12014 : *
12015 : * The resulting band is lazy evaluated. A reference is taken on input
12016 : * datasets.
12017 : *
12018 : * @since 3.12
12019 : */
12020 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
12021 : {
12022 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
12023 1 : band);
12024 : }
12025 : } // namespace gdal
12026 :
12027 : /************************************************************************/
12028 : /* gdal::log() */
12029 : /************************************************************************/
12030 :
12031 : namespace gdal
12032 : {
12033 :
12034 : /** Return a band whose each pixel value is the natural logarithm of the
12035 : * corresponding pixel value in the input band.
12036 : *
12037 : * The resulting band is lazy evaluated. A reference is taken on input
12038 : * datasets.
12039 : *
12040 : * @since 3.12
12041 : */
12042 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12043 : {
12044 : #ifndef HAVE_MUPARSER
12045 : (void)band;
12046 : return ThrowIfNotMuparser();
12047 : #else
12048 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12049 1 : band);
12050 : #endif
12051 : }
12052 : } // namespace gdal
12053 :
12054 : /************************************************************************/
12055 : /* gdal::log10() */
12056 : /************************************************************************/
12057 :
12058 : namespace gdal
12059 : {
12060 :
12061 : /** Return a band whose each pixel value is the logarithm base 10 of the
12062 : * corresponding pixel value in the input band.
12063 : *
12064 : * The resulting band is lazy evaluated. A reference is taken on input
12065 : * datasets.
12066 : *
12067 : * @since 3.12
12068 : */
12069 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12070 : {
12071 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12072 1 : band);
12073 : }
12074 : } // namespace gdal
12075 :
12076 : /************************************************************************/
12077 : /* gdal::pow() */
12078 : /************************************************************************/
12079 :
12080 : namespace gdal
12081 : {
12082 :
12083 : #ifndef DOXYGEN_SKIP
12084 : /** Return a band whose each pixel value is the constant raised to the power of
12085 : * the corresponding pixel value in the input band.
12086 : *
12087 : * The resulting band is lazy evaluated. A reference is taken on input
12088 : * datasets.
12089 : *
12090 : * @since 3.12
12091 : */
12092 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12093 : {
12094 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12095 1 : constant, band);
12096 : }
12097 : #endif
12098 :
12099 : } // namespace gdal
12100 :
12101 : /************************************************************************/
12102 : /* gdal::pow() */
12103 : /************************************************************************/
12104 :
12105 : namespace gdal
12106 : {
12107 :
12108 : /** Return a band whose each pixel value is the the corresponding pixel value
12109 : * in the input band raised to the power of the constant.
12110 : *
12111 : * The resulting band is lazy evaluated. A reference is taken on input
12112 : * datasets.
12113 : *
12114 : * @since 3.12
12115 : */
12116 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12117 : {
12118 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12119 1 : band, constant);
12120 : }
12121 : } // namespace gdal
12122 :
12123 : /************************************************************************/
12124 : /* gdal::pow() */
12125 : /************************************************************************/
12126 :
12127 : namespace gdal
12128 : {
12129 :
12130 : #ifndef DOXYGEN_SKIP
12131 : /** Return a band whose each pixel value is the the corresponding pixel value
12132 : * in the input band1 raised to the power of the corresponding pixel value
12133 : * in the input band2
12134 : *
12135 : * The resulting band is lazy evaluated. A reference is taken on input
12136 : * datasets.
12137 : *
12138 : * @since 3.12
12139 : * @throw std::runtime_error if bands do not have the same dimensions.
12140 : */
12141 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12142 : const GDALRasterBand &band2)
12143 : {
12144 : #ifndef HAVE_MUPARSER
12145 : (void)band1;
12146 : (void)band2;
12147 : return ThrowIfNotMuparser();
12148 : #else
12149 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12150 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12151 1 : band1, band2);
12152 : #endif
12153 : }
12154 : #endif
12155 : } // namespace gdal
|