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 <cassert>
20 : #include <climits>
21 : #include <cmath>
22 : #include <cstdarg>
23 : #include <cstddef>
24 : #include <cstdio>
25 : #include <cstdlib>
26 : #include <cstring>
27 : #include <algorithm>
28 : #include <limits>
29 : #include <memory>
30 : #include <new>
31 : #include <type_traits>
32 :
33 : #include "cpl_conv.h"
34 : #include "cpl_error.h"
35 : #include "cpl_float.h"
36 : #include "cpl_progress.h"
37 : #include "cpl_string.h"
38 : #include "cpl_virtualmem.h"
39 : #include "cpl_vsi.h"
40 : #include "gdal.h"
41 : #include "gdal_rat.h"
42 : #include "gdal_priv_templates.hpp"
43 : #include "gdal_interpolateatpoint.h"
44 : #include "gdal_minmax_element.hpp"
45 : #include "gdalmultidim_priv.h"
46 :
47 : /************************************************************************/
48 : /* GDALRasterBand() */
49 : /************************************************************************/
50 :
51 : /*! Constructor. Applications should never create GDALRasterBands directly. */
52 :
53 1640920 : GDALRasterBand::GDALRasterBand()
54 : : GDALRasterBand(
55 1640920 : CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
56 : {
57 1640820 : }
58 :
59 : /** Constructor. Applications should never create GDALRasterBands directly.
60 : * @param bForceCachedIOIn Whether cached IO should be forced.
61 : */
62 1917270 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
63 1917270 : : bForceCachedIO(bForceCachedIOIn)
64 :
65 : {
66 1917100 : }
67 :
68 : /************************************************************************/
69 : /* ~GDALRasterBand() */
70 : /************************************************************************/
71 :
72 : /*! Destructor. Applications should never destroy GDALRasterBands directly,
73 : instead destroy the GDALDataset. */
74 :
75 1917270 : GDALRasterBand::~GDALRasterBand()
76 :
77 : {
78 1917270 : if (poDS && poDS->IsMarkedSuppressOnClose())
79 : {
80 501 : if (poBandBlockCache)
81 438 : poBandBlockCache->DisableDirtyBlockWriting();
82 : }
83 1917280 : GDALRasterBand::FlushCache(true);
84 :
85 1917270 : delete poBandBlockCache;
86 :
87 1917270 : if (static_cast<GIntBig>(nBlockReads) >
88 1917270 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
89 220 : nBand == 1 && poDS != nullptr)
90 : {
91 320 : CPLDebug(
92 : "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
93 160 : nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
94 160 : poDS->GetDescription());
95 : }
96 :
97 1917270 : InvalidateMaskBand();
98 1917270 : nBand = -nBand;
99 :
100 1917270 : delete m_poPointsCache;
101 1917270 : }
102 :
103 : /************************************************************************/
104 : /* RasterIO() */
105 : /************************************************************************/
106 :
107 : /**
108 : * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
109 : * int nXOff, int nYOff, int nXSize, int nYSize,
110 : * void * pData, int nBufXSize, int nBufYSize,
111 : * GDALDataType eBufType,
112 : * GSpacing nPixelSpace,
113 : * GSpacing nLineSpace,
114 : * GDALRasterIOExtraArg* psExtraArg )
115 : * \brief Read/write a region of image data for this band.
116 : *
117 : * This method allows reading a region of a GDALRasterBand into a buffer,
118 : * or writing data from a buffer into a region of a GDALRasterBand. It
119 : * automatically takes care of data type translation if the data type
120 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
121 : * The method also takes care of image decimation / replication if the
122 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
123 : * region being accessed (nXSize x nYSize).
124 : *
125 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
126 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
127 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
128 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
129 : * Or use nLineSpace and a possibly shifted pData value.
130 : *
131 : * The nPixelSpace and nLineSpace parameters allow reading into or
132 : * writing from unusually organized buffers. This is primarily used
133 : * for buffers containing more than one bands raster data in interleaved
134 : * format.
135 : *
136 : * Some formats may efficiently implement decimation into a buffer by
137 : * reading from lower resolution overview images. The logic of the default
138 : * implementation in the base class GDALRasterBand is the following one. It
139 : * computes a target_downscaling_factor from the window of interest and buffer
140 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
141 : * It then walks through overviews and will select the first one whose
142 : * downscaling factor is greater than target_downscaling_factor / 1.2.
143 : *
144 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
145 : * The relationship between target_downscaling_factor and the select overview
146 : * level is the following one:
147 : *
148 : * target_downscaling_factor | selected_overview
149 : * ------------------------- | -----------------
150 : * ]0, 2 / 1.2] | full resolution band
151 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
152 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
153 : * ]8 / 1.2, infinity[ | 8x downsampled band
154 : *
155 : * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
156 : * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
157 : * option. Also note that starting with GDAL 3.9, when the resampling algorithm
158 : * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
159 : * this oversampling threshold defaults to 1. Consequently if there are overviews
160 : * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
161 : * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
162 : *
163 : * For highest performance full resolution data access, read and write
164 : * on "block boundaries" as returned by GetBlockSize(), or use the
165 : * ReadBlock() and WriteBlock() methods.
166 : *
167 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
168 : * functions.
169 : *
170 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
171 : * write a region of data.
172 : *
173 : * @param nXOff The pixel offset to the top left corner of the region
174 : * of the band to be accessed. This would be zero to start from the left side.
175 : *
176 : * @param nYOff The line offset to the top left corner of the region
177 : * of the band to be accessed. This would be zero to start from the top.
178 : *
179 : * @param nXSize The width of the region of the band to be accessed in pixels.
180 : *
181 : * @param nYSize The height of the region of the band to be accessed in lines.
182 : *
183 : * @param pData The buffer into which the data should be read, or from which
184 : * it should be written. This buffer must contain at least nBufXSize *
185 : * nBufYSize words of type eBufType. It is organized in left to right,
186 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
187 : * and nLineSpace parameters.
188 : * Note that even with eRWFlag==GF_Write, the content of the buffer might be
189 : * temporarily modified during the execution of this method (and eventually
190 : * restored back to its original content), so it is not safe to use a buffer
191 : * stored in a read-only section of the calling program.
192 : *
193 : * @param nBufXSize the width of the buffer image into which the desired region
194 : * is to be read, or from which it is to be written.
195 : *
196 : * @param nBufYSize the height of the buffer image into which the desired region
197 : * is to be read, or from which it is to be written.
198 : *
199 : * @param eBufType the type of the pixel values in the pData data buffer. The
200 : * pixel values will automatically be translated to/from the GDALRasterBand
201 : * data type as needed. Most driver implementations will use GDALCopyWords64()
202 : * to perform data type translation.
203 : *
204 : * @param nPixelSpace The byte offset from the start of one pixel value in
205 : * pData to the start of the next pixel value within a scanline. If defaulted
206 : * (0) the size of the datatype eBufType is used.
207 : *
208 : * @param nLineSpace The byte offset from the start of one scanline in
209 : * pData to the start of the next. If defaulted (0) the size of the datatype
210 : * eBufType * nBufXSize is used.
211 : *
212 : * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
213 : * structure with additional arguments to specify resampling and progress
214 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
215 : * configuration option can also be defined to override the default resampling
216 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
217 : *
218 : * @return CE_Failure if the access fails, otherwise CE_None.
219 : */
220 :
221 : /**
222 : * \brief Read/write a region of image data for this band.
223 : *
224 : * This method allows reading a region of a GDALRasterBand into a buffer,
225 : * or writing data from a buffer into a region of a GDALRasterBand. It
226 : * automatically takes care of data type translation if the data type
227 : * (eBufType) of the buffer is different than that of the GDALRasterBand.
228 : * The method also takes care of image decimation / replication if the
229 : * buffer size (nBufXSize x nBufYSize) is different than the size of the
230 : * region being accessed (nXSize x nYSize).
231 : *
232 : * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
233 : * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
234 : * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
235 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
236 : * Or use nLineSpace and a possibly shifted pData value.
237 : *
238 : * The nPixelSpace and nLineSpace parameters allow reading into or
239 : * writing from unusually organized buffers. This is primarily used
240 : * for buffers containing more than one bands raster data in interleaved
241 : * format.
242 : *
243 : * Some formats may efficiently implement decimation into a buffer by
244 : * reading from lower resolution overview images. The logic of the default
245 : * implementation in the base class GDALRasterBand is the following one. It
246 : * computes a target_downscaling_factor from the window of interest and buffer
247 : * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
248 : * It then walks through overviews and will select the first one whose
249 : * downscaling factor is greater than target_downscaling_factor / 1.2.
250 : *
251 : * Let's assume we have overviews at downscaling factors 2, 4 and 8.
252 : * The relationship between target_downscaling_factor and the select overview
253 : * level is the following one:
254 : *
255 : * target_downscaling_factor | selected_overview
256 : * ------------------------- | -----------------
257 : * ]0, 2 / 1.2] | full resolution band
258 : * ]2 / 1.2, 4 / 1.2] | 2x downsampled band
259 : * ]4 / 1.2, 8 / 1.2] | 4x downsampled band
260 : * ]8 / 1.2, infinity[ | 8x downsampled band
261 : *
262 : * For highest performance full resolution data access, read and write
263 : * on "block boundaries" as returned by GetBlockSize(), or use the
264 : * ReadBlock() and WriteBlock() methods.
265 : *
266 : * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
267 : * functions.
268 : *
269 : * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
270 : * more convenient to use for most common use cases.
271 : *
272 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
273 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
274 : * instance of this dataset) concurrently from several threads.
275 : *
276 : * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
277 : * write a region of data.
278 : *
279 : * @param nXOff The pixel offset to the top left corner of the region
280 : * of the band to be accessed. This would be zero to start from the left side.
281 : *
282 : * @param nYOff The line offset to the top left corner of the region
283 : * of the band to be accessed. This would be zero to start from the top.
284 : *
285 : * @param nXSize The width of the region of the band to be accessed in pixels.
286 : *
287 : * @param nYSize The height of the region of the band to be accessed in lines.
288 : *
289 : * @param[in,out] pData The buffer into which the data should be read, or from
290 : * which it should be written. This buffer must contain at least nBufXSize *
291 : * nBufYSize words of type eBufType. It is organized in left to right,
292 : * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
293 : * and nLineSpace parameters.
294 : *
295 : * @param nBufXSize the width of the buffer image into which the desired region
296 : * is to be read, or from which it is to be written.
297 : *
298 : * @param nBufYSize the height of the buffer image into which the desired region
299 : * is to be read, or from which it is to be written.
300 : *
301 : * @param eBufType the type of the pixel values in the pData data buffer. The
302 : * pixel values will automatically be translated to/from the GDALRasterBand
303 : * data type as needed.
304 : *
305 : * @param nPixelSpace The byte offset from the start of one pixel value in
306 : * pData to the start of the next pixel value within a scanline. If defaulted
307 : * (0) the size of the datatype eBufType is used.
308 : *
309 : * @param nLineSpace The byte offset from the start of one scanline in
310 : * pData to the start of the next. If defaulted (0) the size of the datatype
311 : * eBufType * nBufXSize is used.
312 : *
313 : * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
314 : * structure with additional arguments to specify resampling and progress
315 : * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
316 : * configuration option can also be defined to override the default resampling
317 : * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
318 : *
319 : * @return CE_Failure if the access fails, otherwise CE_None.
320 : *
321 : * @see GDALRasterBand::ReadRaster()
322 : */
323 :
324 4396310 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
325 : int nXSize, int nYSize, void *pData,
326 : int nBufXSize, int nBufYSize,
327 : GDALDataType eBufType, GSpacing nPixelSpace,
328 : GSpacing nLineSpace,
329 : GDALRasterIOExtraArg *psExtraArg)
330 :
331 : {
332 : GDALRasterIOExtraArg sExtraArg;
333 4396310 : if (psExtraArg == nullptr)
334 : {
335 3795740 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
336 3795740 : psExtraArg = &sExtraArg;
337 : }
338 600564 : else if (CPL_UNLIKELY(psExtraArg->nVersion >
339 : RASTERIO_EXTRA_ARG_CURRENT_VERSION))
340 : {
341 0 : ReportError(CE_Failure, CPLE_AppDefined,
342 : "Unhandled version of GDALRasterIOExtraArg");
343 0 : return CE_Failure;
344 : }
345 :
346 4396310 : GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
347 : nBufYSize);
348 :
349 4400980 : if (CPL_UNLIKELY(nullptr == pData))
350 : {
351 0 : ReportError(CE_Failure, CPLE_AppDefined,
352 : "The buffer into which the data should be read is null");
353 0 : return CE_Failure;
354 : }
355 :
356 : /* -------------------------------------------------------------------- */
357 : /* Some size values are "noop". Lets just return to avoid */
358 : /* stressing lower level functions. */
359 : /* -------------------------------------------------------------------- */
360 4400980 : if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
361 : nBufYSize < 1))
362 : {
363 2 : CPLDebug("GDAL",
364 : "RasterIO() skipped for odd window or buffer size.\n"
365 : " Window = (%d,%d)x%dx%d\n"
366 : " Buffer = %dx%d\n",
367 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
368 :
369 2 : return CE_None;
370 : }
371 :
372 4400980 : if (eRWFlag == GF_Write)
373 : {
374 363329 : if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
375 : {
376 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
377 : "An error occurred while writing a dirty block "
378 : "from GDALRasterBand::RasterIO");
379 0 : CPLErr eErr = eFlushBlockErr;
380 0 : eFlushBlockErr = CE_None;
381 0 : return eErr;
382 : }
383 363329 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
384 : {
385 7 : return CE_Failure;
386 : }
387 : }
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* If pixel and line spacing are defaulted assign reasonable */
391 : /* value assuming a packed buffer. */
392 : /* -------------------------------------------------------------------- */
393 4400960 : if (nPixelSpace == 0)
394 : {
395 3980990 : nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
396 : }
397 :
398 4387510 : if (nLineSpace == 0)
399 : {
400 3954610 : nLineSpace = nPixelSpace * nBufXSize;
401 : }
402 :
403 : /* -------------------------------------------------------------------- */
404 : /* Do some validation of parameters. */
405 : /* -------------------------------------------------------------------- */
406 4387510 : if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
407 : nXOff + nXSize > nRasterXSize || nYOff < 0 ||
408 : nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
409 : {
410 15 : ReportError(CE_Failure, CPLE_IllegalArg,
411 : "Access window out of range in RasterIO(). Requested\n"
412 : "(%d,%d) of size %dx%d on raster of %dx%d.",
413 : nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
414 15 : return CE_Failure;
415 : }
416 :
417 4387500 : if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
418 : {
419 0 : ReportError(
420 : CE_Failure, CPLE_IllegalArg,
421 : "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
422 : eRWFlag);
423 0 : return CE_Failure;
424 : }
425 4387500 : if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
426 : {
427 2 : ReportError(CE_Failure, CPLE_IllegalArg,
428 : "Illegal GDT_Unknown/GDT_TypeCount argument");
429 2 : return CE_Failure;
430 : }
431 :
432 4387500 : return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
433 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
434 4365700 : nLineSpace, psExtraArg);
435 : }
436 :
437 : /************************************************************************/
438 : /* RasterIOInternal() */
439 : /************************************************************************/
440 :
441 4374010 : CPLErr GDALRasterBand::RasterIOInternal(
442 : GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
443 : void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
444 : GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
445 : {
446 : /* -------------------------------------------------------------------- */
447 : /* Call the format specific function. */
448 : /* -------------------------------------------------------------------- */
449 :
450 4374010 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
451 :
452 : CPLErr eErr;
453 4341510 : if (bForceCachedIO)
454 23 : eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
455 : pData, nBufXSize, nBufYSize, eBufType,
456 : nPixelSpace, nLineSpace, psExtraArg);
457 : else
458 : eErr =
459 4369700 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
460 4341490 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
461 :
462 4369720 : if (bCallLeaveReadWrite)
463 600583 : LeaveReadWrite();
464 :
465 4355170 : return eErr;
466 : }
467 :
468 : /************************************************************************/
469 : /* GDALRasterIO() */
470 : /************************************************************************/
471 :
472 : /**
473 : * \brief Read/write a region of image data for this band.
474 : *
475 : * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
476 : * resolution, progress callback, etc. are needed)
477 : *
478 : * @see GDALRasterBand::RasterIO()
479 : */
480 :
481 3385240 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
482 : int nXOff, int nYOff, int nXSize, int nYSize,
483 : void *pData, int nBufXSize, int nBufYSize,
484 : GDALDataType eBufType, int nPixelSpace,
485 : int nLineSpace)
486 :
487 : {
488 3385240 : VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
489 :
490 3385240 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
491 :
492 3377970 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
493 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
494 3334620 : nLineSpace, nullptr));
495 : }
496 :
497 : /************************************************************************/
498 : /* GDALRasterIOEx() */
499 : /************************************************************************/
500 :
501 : /**
502 : * \brief Read/write a region of image data for this band.
503 : *
504 : * @see GDALRasterBand::RasterIO()
505 : * @since GDAL 2.0
506 : */
507 :
508 40198 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
509 : int nXOff, int nYOff, int nXSize, int nYSize,
510 : void *pData, int nBufXSize, int nBufYSize,
511 : GDALDataType eBufType, GSpacing nPixelSpace,
512 : GSpacing nLineSpace,
513 : GDALRasterIOExtraArg *psExtraArg)
514 :
515 : {
516 40198 : VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
517 :
518 40198 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
519 :
520 40198 : return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
521 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
522 40195 : nLineSpace, psExtraArg));
523 : }
524 :
525 : /************************************************************************/
526 : /* GetGDTFromCppType() */
527 : /************************************************************************/
528 :
529 : namespace
530 : {
531 : template <class T> struct GetGDTFromCppType;
532 :
533 : #define DEFINE_GetGDTFromCppType(T, eDT) \
534 : template <> struct GetGDTFromCppType<T> \
535 : { \
536 : static constexpr GDALDataType GDT = eDT; \
537 : }
538 :
539 : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
540 : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
541 : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
542 : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
543 : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
544 : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
545 : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
546 : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
547 : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
548 : DEFINE_GetGDTFromCppType(float, GDT_Float32);
549 : DEFINE_GetGDTFromCppType(double, GDT_Float64);
550 : // Not allowed by C++ standard
551 : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
552 : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
553 : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
554 : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
555 : } // namespace
556 :
557 : /************************************************************************/
558 : /* ReadRaster() */
559 : /************************************************************************/
560 :
561 : // clang-format off
562 : /** Read a region of image data for this band.
563 : *
564 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
565 : * for common use cases, like reading a whole band.
566 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
567 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
568 : * float, double, std::complex<float|double>.
569 : *
570 : * 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>&,
571 : * and can allocate memory automatically.
572 : *
573 : * To read a whole band (assuming it fits into memory), as an array of double:
574 : *
575 : \code{.cpp}
576 : double* myArray = static_cast<double*>(
577 : VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
578 : // TODO: check here that myArray != nullptr
579 : const size_t nArrayEltCount =
580 : static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
581 : if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
582 : {
583 : // do something
584 : }
585 : VSIFree(myArray)
586 : \endcode
587 : *
588 : * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
589 : *
590 : \code{.cpp}
591 : double* myArray = static_cast<double*>(
592 : VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
593 : // TODO: check here that myArray != nullptr
594 : const size_t nArrayEltCount = 128 * 128;
595 : if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
596 : {
597 : // do something
598 : }
599 : VSIFree(myArray)
600 : \endcode
601 : *
602 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
603 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
604 : * instance of this dataset) concurrently from several threads.
605 : *
606 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
607 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
608 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
609 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
610 : * Or use nLineSpace and a possibly shifted pData value.
611 : *
612 : * @param[out] pData The buffer into which the data should be written.
613 : * This buffer must contain at least nBufXSize *
614 : * nBufYSize words of type T. It is organized in left to right,
615 : * top to bottom pixel order, and fully packed.
616 : * The type of the buffer does not need to be the one of GetDataType(). The
617 : * method will perform data type translation (with potential rounding, clamping)
618 : * if needed.
619 : *
620 : * @param nArrayEltCount Number of values of pData. If non zero, the method will
621 : * check that it is at least greater or equal to nBufXSize * nBufYSize, and
622 : * return in error if it is not. If set to zero, then pData is trusted to be
623 : * large enough.
624 : *
625 : * @param dfXOff The pixel offset to the top left corner of the region
626 : * of the band to be accessed. This would be zero to start from the left side.
627 : * Defaults to 0.
628 : *
629 : * @param dfYOff The line offset to the top left corner of the region
630 : * of the band to be accessed. This would be zero to start from the top.
631 : * Defaults to 0.
632 : *
633 : * @param dfXSize The width of the region of the band to be accessed in pixels.
634 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
635 : * dfXSize is set to the band width.
636 : *
637 : * @param dfYSize The height of the region of the band to be accessed in lines.
638 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
639 : * dfYSize is set to the band height.
640 : *
641 : * @param nBufXSize the width of the buffer image into which the desired region
642 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
643 : * then nBufXSize is initialized with dfXSize.
644 : *
645 : * @param nBufYSize the height of the buffer image into which the desired region
646 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
647 : * then nBufYSize is initialized with dfYSize.
648 : *
649 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
650 : *
651 : * @param pfnProgress Progress function. May be nullptr.
652 : *
653 : * @param pProgressData User data of pfnProgress. May be nullptr.
654 : *
655 : * @return CE_Failure if the access fails, otherwise CE_None.
656 : *
657 : * @see GDALRasterBand::RasterIO()
658 : * @since GDAL 3.10
659 : */
660 : // clang-format on
661 :
662 : template <class T>
663 20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
664 : double dfXOff, double dfYOff, double dfXSize,
665 : double dfYSize, size_t nBufXSize,
666 : size_t nBufYSize,
667 : GDALRIOResampleAlg eResampleAlg,
668 : GDALProgressFunc pfnProgress,
669 : void *pProgressData) const
670 : {
671 20 : if (((nBufXSize | nBufYSize) >> 31) != 0)
672 : {
673 2 : return CE_Failure;
674 : }
675 :
676 18 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
677 : {
678 16 : dfXSize = nRasterXSize;
679 16 : dfYSize = nRasterYSize;
680 : }
681 2 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
682 2 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
683 2 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
684 2 : dfYOff + dfYSize > INT_MAX)
685 : {
686 0 : return CE_Failure;
687 : }
688 :
689 : GDALRasterIOExtraArg sExtraArg;
690 18 : sExtraArg.nVersion = 1;
691 18 : sExtraArg.eResampleAlg = eResampleAlg;
692 18 : sExtraArg.pfnProgress = pfnProgress;
693 18 : sExtraArg.pProgressData = pProgressData;
694 18 : sExtraArg.bFloatingPointWindowValidity = true;
695 18 : sExtraArg.dfXOff = dfXOff;
696 18 : sExtraArg.dfYOff = dfYOff;
697 18 : sExtraArg.dfXSize = dfXSize;
698 18 : sExtraArg.dfYSize = dfYSize;
699 18 : const int nXOff = static_cast<int>(dfXOff);
700 18 : const int nYOff = static_cast<int>(dfYOff);
701 18 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
702 18 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
703 18 : if (nBufXSize == 0 && nBufYSize == 0)
704 : {
705 17 : if (static_cast<int>(dfXSize) == dfXSize &&
706 17 : static_cast<int>(dfYSize) == dfYSize)
707 : {
708 17 : nBufXSize = static_cast<int>(dfXSize);
709 17 : nBufYSize = static_cast<int>(dfYSize);
710 : }
711 : else
712 : {
713 0 : CPLError(CE_Failure, CPLE_AppDefined,
714 : "nBufXSize and nBufYSize must be provided if dfXSize or "
715 : "dfYSize is not an integer value");
716 0 : return CE_Failure;
717 : }
718 : }
719 18 : if (nBufXSize == 0 || nBufYSize == 0)
720 : {
721 0 : CPLDebug("GDAL",
722 : "RasterIO() skipped for odd window or buffer size.\n"
723 : " Window = (%d,%d)x%dx%d\n"
724 : " Buffer = %dx%d\n",
725 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
726 : static_cast<int>(nBufYSize));
727 :
728 0 : return CE_None;
729 : }
730 :
731 18 : if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
732 : {
733 1 : CPLError(CE_Failure, CPLE_AppDefined,
734 : "Provided array is not large enough");
735 1 : return CE_Failure;
736 : }
737 :
738 17 : constexpr GSpacing nPixelSpace = sizeof(T);
739 17 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
740 17 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
741 :
742 17 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
743 :
744 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
745 : static_cast<int>(nBufXSize),
746 : static_cast<int>(nBufYSize), eBufType,
747 17 : nPixelSpace, nLineSpace, &sExtraArg);
748 : }
749 :
750 : //! @cond Doxygen_Suppress
751 :
752 : #define INSTANTIATE_READ_RASTER(T) \
753 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
754 : T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff, \
755 : double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize, \
756 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
757 : void *pProgressData) const;
758 :
759 : INSTANTIATE_READ_RASTER(uint8_t)
760 : INSTANTIATE_READ_RASTER(int8_t)
761 : INSTANTIATE_READ_RASTER(uint16_t)
762 : INSTANTIATE_READ_RASTER(int16_t)
763 : INSTANTIATE_READ_RASTER(uint32_t)
764 : INSTANTIATE_READ_RASTER(int32_t)
765 : INSTANTIATE_READ_RASTER(uint64_t)
766 : INSTANTIATE_READ_RASTER(int64_t)
767 : INSTANTIATE_READ_RASTER(GFloat16)
768 : INSTANTIATE_READ_RASTER(float)
769 : INSTANTIATE_READ_RASTER(double)
770 : // Not allowed by C++ standard
771 : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
772 : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
773 : INSTANTIATE_READ_RASTER(std::complex<float>)
774 : INSTANTIATE_READ_RASTER(std::complex<double>)
775 :
776 : //! @endcond
777 :
778 : /************************************************************************/
779 : /* ReadRaster() */
780 : /************************************************************************/
781 :
782 : /** Read a region of image data for this band.
783 : *
784 : * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
785 : * for common use cases, like reading a whole band.
786 : * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
787 : * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
788 : * float, double, std::complex<float|double>.
789 : *
790 : * To read a whole band (assuming it fits into memory), as a vector of double:
791 : *
792 : \code
793 : std::vector<double> myArray;
794 : if (poBand->ReadRaster(myArray) == CE_None)
795 : {
796 : // do something
797 : }
798 : \endcode
799 : *
800 : * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
801 : *
802 : \code{.cpp}
803 : std::vector<double> myArray;
804 : if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
805 : {
806 : // do something
807 : }
808 : \endcode
809 : *
810 : * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
811 : * be called on the same GDALRasterBand instance (or another GDALRasterBand
812 : * instance of this dataset) concurrently from several threads.
813 : *
814 : * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
815 : * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
816 : * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
817 : * If reads larger than the raster space are wished, GDALTranslate() might be used.
818 : * Or use nLineSpace and a possibly shifted pData value.
819 : *
820 : * @param[out] vData The vector into which the data should be written.
821 : * The vector will be resized, if needed, to contain at least nBufXSize *
822 : * nBufYSize values. The values in the vector are organized in left to right,
823 : * top to bottom pixel order, and fully packed.
824 : * The type of the vector does not need to be the one of GetDataType(). The
825 : * method will perform data type translation (with potential rounding, clamping)
826 : * if needed.
827 : *
828 : * @param dfXOff The pixel offset to the top left corner of the region
829 : * of the band to be accessed. This would be zero to start from the left side.
830 : * Defaults to 0.
831 : *
832 : * @param dfYOff The line offset to the top left corner of the region
833 : * of the band to be accessed. This would be zero to start from the top.
834 : * Defaults to 0.
835 : *
836 : * @param dfXSize The width of the region of the band to be accessed in pixels.
837 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
838 : * dfXSize is set to the band width.
839 : *
840 : * @param dfYSize The height of the region of the band to be accessed in lines.
841 : * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
842 : * dfYSize is set to the band height.
843 : *
844 : * @param nBufXSize the width of the buffer image into which the desired region
845 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
846 : * then nBufXSize is initialized with dfXSize.
847 : *
848 : * @param nBufYSize the height of the buffer image into which the desired region
849 : * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
850 : * then nBufYSize is initialized with dfYSize.
851 : *
852 : * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
853 : *
854 : * @param pfnProgress Progress function. May be nullptr.
855 : *
856 : * @param pProgressData User data of pfnProgress. May be nullptr.
857 : *
858 : * @return CE_Failure if the access fails, otherwise CE_None.
859 : *
860 : * @see GDALRasterBand::RasterIO()
861 : * @since GDAL 3.10
862 : */
863 : template <class T>
864 22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
865 : double dfYOff, double dfXSize, double dfYSize,
866 : size_t nBufXSize, size_t nBufYSize,
867 : GDALRIOResampleAlg eResampleAlg,
868 : GDALProgressFunc pfnProgress,
869 : void *pProgressData) const
870 : {
871 22 : if (((nBufXSize | nBufYSize) >> 31) != 0)
872 : {
873 2 : return CE_Failure;
874 : }
875 :
876 20 : if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
877 : {
878 13 : dfXSize = nRasterXSize;
879 13 : dfYSize = nRasterYSize;
880 : }
881 7 : else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
882 7 : !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
883 7 : !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
884 7 : dfYOff + dfYSize > INT_MAX)
885 : {
886 0 : return CE_Failure;
887 : }
888 :
889 : GDALRasterIOExtraArg sExtraArg;
890 20 : sExtraArg.nVersion = 1;
891 20 : sExtraArg.eResampleAlg = eResampleAlg;
892 20 : sExtraArg.pfnProgress = pfnProgress;
893 20 : sExtraArg.pProgressData = pProgressData;
894 20 : sExtraArg.bFloatingPointWindowValidity = true;
895 20 : sExtraArg.dfXOff = dfXOff;
896 20 : sExtraArg.dfYOff = dfYOff;
897 20 : sExtraArg.dfXSize = dfXSize;
898 20 : sExtraArg.dfYSize = dfYSize;
899 20 : const int nXOff = static_cast<int>(dfXOff);
900 20 : const int nYOff = static_cast<int>(dfYOff);
901 20 : const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
902 20 : const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
903 20 : if (nBufXSize == 0 && nBufYSize == 0)
904 : {
905 16 : if (static_cast<int>(dfXSize) == dfXSize &&
906 15 : static_cast<int>(dfYSize) == dfYSize)
907 : {
908 15 : nBufXSize = static_cast<int>(dfXSize);
909 15 : nBufYSize = static_cast<int>(dfYSize);
910 : }
911 : else
912 : {
913 1 : CPLError(CE_Failure, CPLE_AppDefined,
914 : "nBufXSize and nBufYSize must be provided if "
915 : "dfXSize or dfYSize is not an integer value");
916 1 : return CE_Failure;
917 : }
918 : }
919 19 : if (nBufXSize == 0 || nBufYSize == 0)
920 : {
921 0 : CPLDebug("GDAL",
922 : "RasterIO() skipped for odd window or buffer size.\n"
923 : " Window = (%d,%d)x%dx%d\n"
924 : " Buffer = %dx%d\n",
925 : nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
926 : static_cast<int>(nBufYSize));
927 :
928 0 : return CE_None;
929 : }
930 :
931 : if constexpr (SIZEOF_VOIDP < 8)
932 : {
933 : if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
934 : {
935 : CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
936 : return CE_Failure;
937 : }
938 : }
939 :
940 19 : if (vData.size() < nBufXSize * nBufYSize)
941 : {
942 : try
943 : {
944 17 : vData.resize(nBufXSize * nBufYSize);
945 : }
946 1 : catch (const std::exception &)
947 : {
948 1 : CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
949 1 : return CE_Failure;
950 : }
951 : }
952 :
953 18 : constexpr GSpacing nPixelSpace = sizeof(T);
954 18 : const GSpacing nLineSpace = nPixelSpace * nBufXSize;
955 18 : constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
956 :
957 18 : GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
958 :
959 : return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
960 : vData.data(), static_cast<int>(nBufXSize),
961 : static_cast<int>(nBufYSize), eBufType,
962 18 : nPixelSpace, nLineSpace, &sExtraArg);
963 : }
964 :
965 : //! @cond Doxygen_Suppress
966 :
967 : #define INSTANTIATE_READ_RASTER_VECTOR(T) \
968 : template CPLErr CPL_DLL GDALRasterBand::ReadRaster( \
969 : std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize, \
970 : double dfYSize, size_t nBufXSize, size_t nBufYSize, \
971 : GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress, \
972 : void *pProgressData) const;
973 :
974 : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
975 : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
976 : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
977 : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
978 : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
979 : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
980 : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
981 : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
982 : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
983 : INSTANTIATE_READ_RASTER_VECTOR(float)
984 : INSTANTIATE_READ_RASTER_VECTOR(double)
985 : // Not allowed by C++ standard
986 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
987 : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
988 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
989 : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
990 :
991 : //! @endcond
992 :
993 : /************************************************************************/
994 : /* ReadBlock() */
995 : /************************************************************************/
996 :
997 : /**
998 : * \brief Read a block of image data efficiently.
999 : *
1000 : * This method accesses a "natural" block from the raster band without
1001 : * resampling, or data type conversion. For a more generalized, but
1002 : * potentially less efficient access use RasterIO().
1003 : *
1004 : * This method is the same as the C GDALReadBlock() function.
1005 : *
1006 : * See the GetLockedBlockRef() method for a way of accessing internally cached
1007 : * block oriented data without an extra copy into an application buffer.
1008 : *
1009 : * The following code would efficiently compute a histogram of eight bit
1010 : * raster data. Note that the final block may be partial ... data beyond
1011 : * the edge of the underlying raster band in these edge blocks is of an
1012 : * undetermined value.
1013 : *
1014 : \code{.cpp}
1015 : CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
1016 :
1017 : {
1018 : memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
1019 :
1020 : CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
1021 :
1022 : int nXBlockSize, nYBlockSize;
1023 :
1024 : poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
1025 : int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
1026 : int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
1027 :
1028 : GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
1029 :
1030 : for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
1031 : {
1032 : for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
1033 : {
1034 : int nXValid, nYValid;
1035 :
1036 : poBand->ReadBlock( iXBlock, iYBlock, pabyData );
1037 :
1038 : // Compute the portion of the block that is valid
1039 : // for partial edge blocks.
1040 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
1041 :
1042 : // Collect the histogram counts.
1043 : for( int iY = 0; iY < nYValid; iY++ )
1044 : {
1045 : for( int iX = 0; iX < nXValid; iX++ )
1046 : {
1047 : panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
1048 : }
1049 : }
1050 : }
1051 : }
1052 : }
1053 : \endcode
1054 : *
1055 : * @param nXBlockOff the horizontal block offset, with zero indicating
1056 : * the left most block, 1 the next block and so forth.
1057 : *
1058 : * @param nYBlockOff the vertical block offset, with zero indicating
1059 : * the top most block, 1 the next block and so forth.
1060 : *
1061 : * @param pImage the buffer into which the data will be read. The buffer
1062 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1063 : * of type GetRasterDataType().
1064 : *
1065 : * @return CE_None on success or CE_Failure on an error.
1066 : */
1067 :
1068 894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1069 :
1070 : {
1071 : /* -------------------------------------------------------------------- */
1072 : /* Validate arguments. */
1073 : /* -------------------------------------------------------------------- */
1074 894 : CPLAssert(pImage != nullptr);
1075 :
1076 894 : if (!InitBlockInfo())
1077 0 : return CE_Failure;
1078 :
1079 894 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1080 : {
1081 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1082 : "Illegal nXBlockOff value (%d) in "
1083 : "GDALRasterBand::ReadBlock()\n",
1084 : nXBlockOff);
1085 :
1086 0 : return (CE_Failure);
1087 : }
1088 :
1089 894 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1090 : {
1091 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1092 : "Illegal nYBlockOff value (%d) in "
1093 : "GDALRasterBand::ReadBlock()\n",
1094 : nYBlockOff);
1095 :
1096 0 : return (CE_Failure);
1097 : }
1098 :
1099 : /* -------------------------------------------------------------------- */
1100 : /* Invoke underlying implementation method. */
1101 : /* -------------------------------------------------------------------- */
1102 :
1103 894 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
1104 894 : CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
1105 894 : if (bCallLeaveReadWrite)
1106 4 : LeaveReadWrite();
1107 894 : return eErr;
1108 : }
1109 :
1110 : /************************************************************************/
1111 : /* GDALReadBlock() */
1112 : /************************************************************************/
1113 :
1114 : /**
1115 : * \brief Read a block of image data efficiently.
1116 : *
1117 : * @see GDALRasterBand::ReadBlock()
1118 : */
1119 :
1120 77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1121 : void *pData)
1122 :
1123 : {
1124 77 : VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
1125 :
1126 77 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1127 77 : return (poBand->ReadBlock(nXOff, nYOff, pData));
1128 : }
1129 :
1130 : /************************************************************************/
1131 : /* IReadBlock() */
1132 : /************************************************************************/
1133 :
1134 : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
1135 : * ) \brief Read a block of data.
1136 : *
1137 : * Default internal implementation ... to be overridden by
1138 : * subclasses that support reading.
1139 : * @param nBlockXOff Block X Offset
1140 : * @param nBlockYOff Block Y Offset
1141 : * @param pData Pixel buffer into which to place read data.
1142 : * @return CE_None on success or CE_Failure on an error.
1143 : */
1144 :
1145 : /************************************************************************/
1146 : /* IWriteBlock() */
1147 : /************************************************************************/
1148 :
1149 : /**
1150 : * \fn GDALRasterBand::IWriteBlock(int, int, void*)
1151 : * Write a block of data.
1152 : *
1153 : * Default internal implementation ... to be overridden by
1154 : * subclasses that support writing.
1155 : * @param nBlockXOff Block X Offset
1156 : * @param nBlockYOff Block Y Offset
1157 : * @param pData Pixel buffer to write
1158 : * @return CE_None on success or CE_Failure on an error.
1159 : */
1160 :
1161 : /**/
1162 : /**/
1163 :
1164 0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
1165 : void * /*pData*/)
1166 :
1167 : {
1168 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
1169 0 : ReportError(CE_Failure, CPLE_NotSupported,
1170 : "WriteBlock() not supported for this dataset.");
1171 :
1172 0 : return (CE_Failure);
1173 : }
1174 :
1175 : /************************************************************************/
1176 : /* WriteBlock() */
1177 : /************************************************************************/
1178 :
1179 : /**
1180 : * \brief Write a block of image data efficiently.
1181 : *
1182 : * This method accesses a "natural" block from the raster band without
1183 : * resampling, or data type conversion. For a more generalized, but
1184 : * potentially less efficient access use RasterIO().
1185 : *
1186 : * This method is the same as the C GDALWriteBlock() function.
1187 : *
1188 : * See ReadBlock() for an example of block oriented data access.
1189 : *
1190 : * @param nXBlockOff the horizontal block offset, with zero indicating
1191 : * the left most block, 1 the next block and so forth.
1192 : *
1193 : * @param nYBlockOff the vertical block offset, with zero indicating
1194 : * the left most block, 1 the next block and so forth.
1195 : *
1196 : * @param pImage the buffer from which the data will be written. The buffer
1197 : * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
1198 : * of type GetRasterDataType(). Note that the content of the buffer might be
1199 : * temporarily modified during the execution of this method (and eventually
1200 : * restored back to its original content), so it is not safe to use a buffer
1201 : * stored in a read-only section of the calling program.
1202 : *
1203 : * @return CE_None on success or CE_Failure on an error.
1204 : */
1205 :
1206 4887 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
1207 :
1208 : {
1209 : /* -------------------------------------------------------------------- */
1210 : /* Validate arguments. */
1211 : /* -------------------------------------------------------------------- */
1212 4887 : CPLAssert(pImage != nullptr);
1213 :
1214 4887 : if (!InitBlockInfo())
1215 0 : return CE_Failure;
1216 :
1217 4887 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1218 : {
1219 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1220 : "Illegal nXBlockOff value (%d) in "
1221 : "GDALRasterBand::WriteBlock()\n",
1222 : nXBlockOff);
1223 :
1224 0 : return (CE_Failure);
1225 : }
1226 :
1227 4887 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1228 : {
1229 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1230 : "Illegal nYBlockOff value (%d) in "
1231 : "GDALRasterBand::WriteBlock()\n",
1232 : nYBlockOff);
1233 :
1234 0 : return (CE_Failure);
1235 : }
1236 :
1237 4887 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
1238 : {
1239 0 : return CE_Failure;
1240 : }
1241 :
1242 4887 : if (eFlushBlockErr != CE_None)
1243 : {
1244 0 : ReportError(eFlushBlockErr, CPLE_AppDefined,
1245 : "An error occurred while writing a dirty block "
1246 : "from GDALRasterBand::WriteBlock");
1247 0 : CPLErr eErr = eFlushBlockErr;
1248 0 : eFlushBlockErr = CE_None;
1249 0 : return eErr;
1250 : }
1251 :
1252 : /* -------------------------------------------------------------------- */
1253 : /* Invoke underlying implementation method. */
1254 : /* -------------------------------------------------------------------- */
1255 :
1256 4887 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
1257 4887 : CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
1258 4887 : if (bCallLeaveReadWrite)
1259 4887 : LeaveReadWrite();
1260 :
1261 4887 : return eErr;
1262 : }
1263 :
1264 : /************************************************************************/
1265 : /* GDALWriteBlock() */
1266 : /************************************************************************/
1267 :
1268 : /**
1269 : * \brief Write a block of image data efficiently.
1270 : *
1271 : * @see GDALRasterBand::WriteBlock()
1272 : */
1273 :
1274 0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
1275 : void *pData)
1276 :
1277 : {
1278 0 : VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
1279 :
1280 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1281 0 : return (poBand->WriteBlock(nXOff, nYOff, pData));
1282 : }
1283 :
1284 : /************************************************************************/
1285 : /* EmitErrorMessageIfWriteNotSupported() */
1286 : /************************************************************************/
1287 :
1288 : /**
1289 : * Emit an error message if a write operation to this band is not supported.
1290 : *
1291 : * The base implementation will emit an error message if the access mode is
1292 : * read-only. Derived classes may implement it to provide a custom message.
1293 : *
1294 : * @param pszCaller Calling function.
1295 : * @return true if an error message has been emitted.
1296 : */
1297 636944 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
1298 : const char *pszCaller) const
1299 : {
1300 636944 : if (eAccess == GA_ReadOnly)
1301 : {
1302 4 : ReportError(CE_Failure, CPLE_NoWriteAccess,
1303 : "%s: attempt to write to dataset opened in read-only mode.",
1304 : pszCaller);
1305 :
1306 4 : return true;
1307 : }
1308 636940 : return false;
1309 : }
1310 :
1311 : /************************************************************************/
1312 : /* GetActualBlockSize() */
1313 : /************************************************************************/
1314 : /**
1315 : * \brief Fetch the actual block size for a given block offset.
1316 : *
1317 : * Handles partial blocks at the edges of the raster and returns the true
1318 : * number of pixels
1319 : *
1320 : * @param nXBlockOff the horizontal block offset for which to calculate the
1321 : * number of valid pixels, with zero indicating the left most block, 1 the next
1322 : * block and so forth.
1323 : *
1324 : * @param nYBlockOff the vertical block offset, with zero indicating
1325 : * the top most block, 1 the next block and so forth.
1326 : *
1327 : * @param pnXValid pointer to an integer in which the number of valid pixels in
1328 : * the x direction will be stored
1329 : *
1330 : * @param pnYValid pointer to an integer in which the number of valid pixels in
1331 : * the y direction will be stored
1332 : *
1333 : * @return CE_None if the input parameters are valid, CE_Failure otherwise
1334 : *
1335 : * @since GDAL 2.2
1336 : */
1337 51654 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
1338 : int *pnXValid, int *pnYValid) const
1339 : {
1340 103307 : if (nXBlockOff < 0 || nBlockXSize == 0 ||
1341 103305 : nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
1342 103302 : nYBlockOff < 0 || nBlockYSize == 0 ||
1343 51651 : nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
1344 : {
1345 5 : return CE_Failure;
1346 : }
1347 :
1348 51649 : const int nXPixelOff = nXBlockOff * nBlockXSize;
1349 51649 : const int nYPixelOff = nYBlockOff * nBlockYSize;
1350 :
1351 51649 : *pnXValid = nBlockXSize;
1352 51649 : *pnYValid = nBlockYSize;
1353 :
1354 51649 : if (nXPixelOff >= nRasterXSize - nBlockXSize)
1355 : {
1356 50110 : *pnXValid = nRasterXSize - nXPixelOff;
1357 : }
1358 :
1359 51649 : if (nYPixelOff >= nRasterYSize - nBlockYSize)
1360 : {
1361 3677 : *pnYValid = nRasterYSize - nYPixelOff;
1362 : }
1363 :
1364 51649 : return CE_None;
1365 : }
1366 :
1367 : /************************************************************************/
1368 : /* GDALGetActualBlockSize() */
1369 : /************************************************************************/
1370 :
1371 : /**
1372 : * \brief Retrieve the actual block size for a given block offset.
1373 : *
1374 : * @see GDALRasterBand::GetActualBlockSize()
1375 : */
1376 :
1377 6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
1378 : int nYBlockOff, int *pnXValid,
1379 : int *pnYValid)
1380 :
1381 : {
1382 6 : VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
1383 :
1384 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1385 : return (
1386 6 : poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
1387 : }
1388 :
1389 : /************************************************************************/
1390 : /* GetSuggestedBlockAccessPattern() */
1391 : /************************************************************************/
1392 :
1393 : /**
1394 : * \brief Return the suggested/most efficient access pattern to blocks
1395 : * (for read operations).
1396 : *
1397 : * While all GDAL drivers have to expose a block size, not all can guarantee
1398 : * efficient random access (GSBAP_RANDOM) to any block.
1399 : * Some drivers for example decompress sequentially a compressed stream from
1400 : * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
1401 : * case best performance will be achieved while reading blocks in that order.
1402 : * (accessing blocks in random access in such rasters typically causes the
1403 : * decoding to be re-initialized from the start if accessing blocks in
1404 : * a non-sequential order)
1405 : *
1406 : * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
1407 : * returned by drivers that expose a somewhat artificial block size, because
1408 : * they can extract any part of a raster, but in a rather inefficient way.
1409 : *
1410 : * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
1411 : * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
1412 : * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
1413 : * most efficient strategy is to read as many pixels as possible in the less
1414 : * RasterIO() operations.
1415 : *
1416 : * The return of this method is for example used to determine the swath size
1417 : * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
1418 : *
1419 : * @since GDAL 3.6
1420 : */
1421 :
1422 : GDALSuggestedBlockAccessPattern
1423 2374 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
1424 : {
1425 2374 : return GSBAP_UNKNOWN;
1426 : }
1427 :
1428 : /************************************************************************/
1429 : /* GetRasterDataType() */
1430 : /************************************************************************/
1431 :
1432 : /**
1433 : * \brief Fetch the pixel data type for this band.
1434 : *
1435 : * This method is the same as the C function GDALGetRasterDataType().
1436 : *
1437 : * @return the data type of pixels for this band.
1438 : */
1439 :
1440 8895570 : GDALDataType GDALRasterBand::GetRasterDataType() const
1441 :
1442 : {
1443 8895570 : return eDataType;
1444 : }
1445 :
1446 : /************************************************************************/
1447 : /* GDALGetRasterDataType() */
1448 : /************************************************************************/
1449 :
1450 : /**
1451 : * \brief Fetch the pixel data type for this band.
1452 : *
1453 : * @see GDALRasterBand::GetRasterDataType()
1454 : */
1455 :
1456 905232 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
1457 :
1458 : {
1459 905232 : VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
1460 :
1461 905232 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1462 905232 : return poBand->GetRasterDataType();
1463 : }
1464 :
1465 : /************************************************************************/
1466 : /* GetBlockSize() */
1467 : /************************************************************************/
1468 :
1469 : /**
1470 : * \brief Fetch the "natural" block size of this band.
1471 : *
1472 : * GDAL contains a concept of the natural block size of rasters so that
1473 : * applications can organized data access efficiently for some file formats.
1474 : * The natural block size is the block size that is most efficient for
1475 : * accessing the format. For many formats this is simple a whole scanline
1476 : * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
1477 : *
1478 : * However, for tiled images this will typically be the tile size.
1479 : *
1480 : * Note that the X and Y block sizes don't have to divide the image size
1481 : * evenly, meaning that right and bottom edge blocks may be incomplete.
1482 : * See ReadBlock() for an example of code dealing with these issues.
1483 : *
1484 : * This method is the same as the C function GDALGetBlockSize().
1485 : *
1486 : * @param pnXSize integer to put the X block size into or NULL.
1487 : *
1488 : * @param pnYSize integer to put the Y block size into or NULL.
1489 : */
1490 :
1491 5412570 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
1492 :
1493 : {
1494 5412570 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1495 : {
1496 37621 : ReportError(CE_Failure, CPLE_AppDefined,
1497 37621 : "Invalid block dimension : %d * %d", nBlockXSize,
1498 37621 : nBlockYSize);
1499 4 : if (pnXSize != nullptr)
1500 4 : *pnXSize = 0;
1501 4 : if (pnYSize != nullptr)
1502 4 : *pnYSize = 0;
1503 : }
1504 : else
1505 : {
1506 5374950 : if (pnXSize != nullptr)
1507 5372970 : *pnXSize = nBlockXSize;
1508 5374950 : if (pnYSize != nullptr)
1509 5364830 : *pnYSize = nBlockYSize;
1510 : }
1511 5374950 : }
1512 :
1513 : /************************************************************************/
1514 : /* GDALGetBlockSize() */
1515 : /************************************************************************/
1516 :
1517 : /**
1518 : * \brief Fetch the "natural" block size of this band.
1519 : *
1520 : * @see GDALRasterBand::GetBlockSize()
1521 : */
1522 :
1523 41129 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
1524 : int *pnYSize)
1525 :
1526 : {
1527 41129 : VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
1528 :
1529 41129 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
1530 41129 : poBand->GetBlockSize(pnXSize, pnYSize);
1531 : }
1532 :
1533 : /************************************************************************/
1534 : /* InitBlockInfo() */
1535 : /************************************************************************/
1536 :
1537 : //! @cond Doxygen_Suppress
1538 3643360 : int GDALRasterBand::InitBlockInfo()
1539 :
1540 : {
1541 3643360 : if (poBandBlockCache != nullptr)
1542 3405160 : return poBandBlockCache->IsInitOK();
1543 :
1544 : /* Do some validation of raster and block dimensions in case the driver */
1545 : /* would have neglected to do it itself */
1546 238200 : if (nBlockXSize <= 0 || nBlockYSize <= 0)
1547 : {
1548 11 : ReportError(CE_Failure, CPLE_AppDefined,
1549 : "Invalid block dimension : %d * %d", nBlockXSize,
1550 : nBlockYSize);
1551 0 : return FALSE;
1552 : }
1553 :
1554 238189 : if (nRasterXSize <= 0 || nRasterYSize <= 0)
1555 : {
1556 2 : ReportError(CE_Failure, CPLE_AppDefined,
1557 : "Invalid raster dimension : %d * %d", nRasterXSize,
1558 : nRasterYSize);
1559 0 : return FALSE;
1560 : }
1561 :
1562 238187 : const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
1563 238192 : if (nDataTypeSize == 0)
1564 : {
1565 3 : ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
1566 0 : return FALSE;
1567 : }
1568 :
1569 : #if SIZEOF_VOIDP == 4
1570 : if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
1571 : {
1572 : /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
1573 : * multiplication in other cases */
1574 : if (nBlockXSize > INT_MAX / nDataTypeSize ||
1575 : nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
1576 : {
1577 : ReportError(CE_Failure, CPLE_NotSupported,
1578 : "Too big block : %d * %d for 32-bit build", nBlockXSize,
1579 : nBlockYSize);
1580 : return FALSE;
1581 : }
1582 : }
1583 : #endif
1584 :
1585 238189 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
1586 238189 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
1587 :
1588 : const char *pszBlockStrategy =
1589 238189 : CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
1590 238205 : bool bUseArray = true;
1591 238205 : if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
1592 : {
1593 238165 : if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1594 : GDAL_OF_DEFAULT_BLOCK_ACCESS)
1595 : {
1596 238146 : GUIntBig nBlockCount =
1597 238146 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
1598 238146 : if (poDS != nullptr)
1599 237944 : nBlockCount *= poDS->GetRasterCount();
1600 238146 : bUseArray = (nBlockCount < 1024 * 1024);
1601 : }
1602 19 : else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
1603 : GDAL_OF_HASHSET_BLOCK_ACCESS)
1604 : {
1605 0 : bUseArray = false;
1606 238165 : }
1607 : }
1608 40 : else if (EQUAL(pszBlockStrategy, "HASHSET"))
1609 40 : bUseArray = false;
1610 0 : else if (!EQUAL(pszBlockStrategy, "ARRAY"))
1611 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
1612 : pszBlockStrategy);
1613 :
1614 238205 : if (bUseArray)
1615 238134 : poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
1616 : else
1617 : {
1618 71 : if (nBand == 1)
1619 26 : CPLDebug("GDAL", "Use hashset band block cache");
1620 71 : poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
1621 : }
1622 238202 : if (poBandBlockCache == nullptr)
1623 0 : return FALSE;
1624 238202 : return poBandBlockCache->Init();
1625 : }
1626 :
1627 : //! @endcond
1628 :
1629 : /************************************************************************/
1630 : /* FlushCache() */
1631 : /************************************************************************/
1632 :
1633 : /**
1634 : * \brief Flush raster data cache.
1635 : *
1636 : * This call will recover memory used to cache data blocks for this raster
1637 : * band, and ensure that new requests are referred to the underlying driver.
1638 : *
1639 : * This method is the same as the C function GDALFlushRasterCache().
1640 : *
1641 : * @param bAtClosing Whether this is called from a GDALDataset destructor
1642 : * @return CE_None on success.
1643 : */
1644 :
1645 5646750 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
1646 :
1647 : {
1648 5762750 : if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
1649 115998 : poBandBlockCache)
1650 2939 : poBandBlockCache->DisableDirtyBlockWriting();
1651 :
1652 5640970 : CPLErr eGlobalErr = eFlushBlockErr;
1653 :
1654 5640970 : if (eFlushBlockErr != CE_None)
1655 : {
1656 0 : ReportError(
1657 : eFlushBlockErr, CPLE_AppDefined,
1658 : "An error occurred while writing a dirty block from FlushCache");
1659 0 : eFlushBlockErr = CE_None;
1660 : }
1661 :
1662 5640970 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1663 4865870 : return eGlobalErr;
1664 :
1665 775105 : return poBandBlockCache->FlushCache();
1666 : }
1667 :
1668 : /************************************************************************/
1669 : /* GDALFlushRasterCache() */
1670 : /************************************************************************/
1671 :
1672 : /**
1673 : * \brief Flush raster data cache.
1674 : *
1675 : * @see GDALRasterBand::FlushCache()
1676 : */
1677 :
1678 487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
1679 :
1680 : {
1681 487 : VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
1682 :
1683 487 : return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
1684 : }
1685 :
1686 : /************************************************************************/
1687 : /* DropCache() */
1688 : /************************************************************************/
1689 :
1690 : /**
1691 : * \brief Drop raster data cache : data in cache will be lost.
1692 : *
1693 : * This call will recover memory used to cache data blocks for this raster
1694 : * band, and ensure that new requests are referred to the underlying driver.
1695 : *
1696 : * This method is the same as the C function GDALDropRasterCache().
1697 : *
1698 : * @return CE_None on success.
1699 : * @since 3.9
1700 : */
1701 :
1702 1 : CPLErr GDALRasterBand::DropCache()
1703 :
1704 : {
1705 1 : CPLErr result = CE_None;
1706 :
1707 1 : if (poBandBlockCache)
1708 1 : poBandBlockCache->DisableDirtyBlockWriting();
1709 :
1710 1 : CPLErr eGlobalErr = eFlushBlockErr;
1711 :
1712 1 : if (eFlushBlockErr != CE_None)
1713 : {
1714 0 : ReportError(
1715 : eFlushBlockErr, CPLE_AppDefined,
1716 : "An error occurred while writing a dirty block from DropCache");
1717 0 : eFlushBlockErr = CE_None;
1718 : }
1719 :
1720 1 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1721 0 : result = eGlobalErr;
1722 : else
1723 1 : result = poBandBlockCache->FlushCache();
1724 :
1725 1 : if (poBandBlockCache)
1726 1 : poBandBlockCache->EnableDirtyBlockWriting();
1727 :
1728 1 : return result;
1729 : }
1730 :
1731 : /************************************************************************/
1732 : /* GDALDropRasterCache() */
1733 : /************************************************************************/
1734 :
1735 : /**
1736 : * \brief Drop raster data cache.
1737 : *
1738 : * @see GDALRasterBand::DropCache()
1739 : * @since 3.9
1740 : */
1741 :
1742 0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
1743 :
1744 : {
1745 0 : VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
1746 :
1747 0 : return GDALRasterBand::FromHandle(hBand)->DropCache();
1748 : }
1749 :
1750 : /************************************************************************/
1751 : /* UnreferenceBlock() */
1752 : /* */
1753 : /* Unreference the block from our array of blocks */
1754 : /* This method should only be called by */
1755 : /* GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
1756 : /* the block cache mutex) */
1757 : /************************************************************************/
1758 :
1759 29619 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
1760 : {
1761 : #ifdef notdef
1762 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1763 : {
1764 : if (poBandBlockCache == nullptr)
1765 : printf("poBandBlockCache == NULL\n"); /*ok*/
1766 : else
1767 : printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
1768 : printf("caller = %s\n", pszCaller); /*ok*/
1769 : printf("GDALRasterBand: %p\n", this); /*ok*/
1770 : printf("GDALRasterBand: nBand=%d\n", nBand); /*ok*/
1771 : printf("nRasterXSize = %d\n", nRasterXSize); /*ok*/
1772 : printf("nRasterYSize = %d\n", nRasterYSize); /*ok*/
1773 : printf("nBlockXSize = %d\n", nBlockXSize); /*ok*/
1774 : printf("nBlockYSize = %d\n", nBlockYSize); /*ok*/
1775 : poBlock->DumpBlock();
1776 : if (GetDataset() != nullptr)
1777 : printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
1778 : GDALRasterBlock::Verify();
1779 : abort();
1780 : }
1781 : #endif
1782 29619 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1783 29619 : return poBandBlockCache->UnreferenceBlock(poBlock);
1784 : }
1785 :
1786 : /************************************************************************/
1787 : /* AddBlockToFreeList() */
1788 : /* */
1789 : /* When GDALRasterBlock::Internalize() or FlushCacheBlock() are */
1790 : /* finished with a block about to be free'd, they pass it to that */
1791 : /* method. */
1792 : /************************************************************************/
1793 :
1794 : //! @cond Doxygen_Suppress
1795 29618 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
1796 : {
1797 29618 : CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
1798 29618 : return poBandBlockCache->AddBlockToFreeList(poBlock);
1799 : }
1800 :
1801 : //! @endcond
1802 :
1803 : /************************************************************************/
1804 : /* FlushBlock() */
1805 : /************************************************************************/
1806 :
1807 : /** Flush a block out of the block cache.
1808 : * @param nXBlockOff block x offset
1809 : * @param nYBlockOff blocky offset
1810 : * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
1811 : * @return CE_None in case of success, an error code otherwise.
1812 : */
1813 2310 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
1814 : int bWriteDirtyBlock)
1815 :
1816 : {
1817 2310 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1818 0 : return (CE_Failure);
1819 :
1820 : /* -------------------------------------------------------------------- */
1821 : /* Validate the request */
1822 : /* -------------------------------------------------------------------- */
1823 2310 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1824 : {
1825 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1826 : "Illegal nBlockXOff value (%d) in "
1827 : "GDALRasterBand::FlushBlock()\n",
1828 : nXBlockOff);
1829 :
1830 0 : return (CE_Failure);
1831 : }
1832 :
1833 2310 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1834 : {
1835 0 : ReportError(CE_Failure, CPLE_IllegalArg,
1836 : "Illegal nBlockYOff value (%d) in "
1837 : "GDALRasterBand::FlushBlock()\n",
1838 : nYBlockOff);
1839 :
1840 0 : return (CE_Failure);
1841 : }
1842 :
1843 2310 : return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
1844 2310 : bWriteDirtyBlock);
1845 : }
1846 :
1847 : /************************************************************************/
1848 : /* TryGetLockedBlockRef() */
1849 : /************************************************************************/
1850 :
1851 : /**
1852 : * \brief Try fetching block ref.
1853 : *
1854 : * This method will returned the requested block (locked) if it is already
1855 : * in the block cache for the layer. If not, nullptr is returned.
1856 : *
1857 : * If a non-NULL value is returned, then a lock for the block will have been
1858 : * acquired on behalf of the caller. It is absolutely imperative that the
1859 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1860 : * severe problems may result.
1861 : *
1862 : * @param nXBlockOff the horizontal block offset, with zero indicating
1863 : * the left most block, 1 the next block and so forth.
1864 : *
1865 : * @param nYBlockOff the vertical block offset, with zero indicating
1866 : * the top most block, 1 the next block and so forth.
1867 : *
1868 : * @return NULL if block not available, or locked block pointer.
1869 : */
1870 :
1871 10634800 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
1872 : int nYBlockOff)
1873 :
1874 : {
1875 10634800 : if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
1876 172246 : return nullptr;
1877 :
1878 : /* -------------------------------------------------------------------- */
1879 : /* Validate the request */
1880 : /* -------------------------------------------------------------------- */
1881 10462600 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1882 : {
1883 8 : ReportError(CE_Failure, CPLE_IllegalArg,
1884 : "Illegal nBlockXOff value (%d) in "
1885 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1886 : nXBlockOff);
1887 :
1888 0 : return (nullptr);
1889 : }
1890 :
1891 10462600 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1892 : {
1893 8 : ReportError(CE_Failure, CPLE_IllegalArg,
1894 : "Illegal nBlockYOff value (%d) in "
1895 : "GDALRasterBand::TryGetLockedBlockRef()\n",
1896 : nYBlockOff);
1897 :
1898 0 : return (nullptr);
1899 : }
1900 :
1901 10462600 : return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1902 : }
1903 :
1904 : /************************************************************************/
1905 : /* GetLockedBlockRef() */
1906 : /************************************************************************/
1907 :
1908 : /**
1909 : * \brief Fetch a pointer to an internally cached raster block.
1910 : *
1911 : * This method will returned the requested block (locked) if it is already
1912 : * in the block cache for the layer. If not, the block will be read from
1913 : * the driver, and placed in the layer block cached, then returned. If an
1914 : * error occurs reading the block from the driver, a NULL value will be
1915 : * returned.
1916 : *
1917 : * If a non-NULL value is returned, then a lock for the block will have been
1918 : * acquired on behalf of the caller. It is absolutely imperative that the
1919 : * caller release this lock (with GDALRasterBlock::DropLock()) or else
1920 : * severe problems may result.
1921 : *
1922 : * Note that calling GetLockedBlockRef() on a previously uncached band will
1923 : * enable caching.
1924 : *
1925 : * @param nXBlockOff the horizontal block offset, with zero indicating
1926 : * the left most block, 1 the next block and so forth.
1927 : *
1928 : * @param nYBlockOff the vertical block offset, with zero indicating
1929 : * the top most block, 1 the next block and so forth.
1930 : *
1931 : * @param bJustInitialize If TRUE the block will be allocated and initialized,
1932 : * but not actually read from the source. This is useful when it will just
1933 : * be completely set and written back.
1934 : *
1935 : * @return pointer to the block object, or NULL on failure.
1936 : */
1937 :
1938 10325200 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
1939 : int nYBlockOff,
1940 : int bJustInitialize)
1941 :
1942 : {
1943 : /* -------------------------------------------------------------------- */
1944 : /* Try and fetch from cache. */
1945 : /* -------------------------------------------------------------------- */
1946 10325200 : GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
1947 :
1948 : /* -------------------------------------------------------------------- */
1949 : /* If we didn't find it in our memory cache, instantiate a */
1950 : /* block (potentially load from disk) and "adopt" it into the */
1951 : /* cache. */
1952 : /* -------------------------------------------------------------------- */
1953 10325300 : if (poBlock == nullptr)
1954 : {
1955 3366650 : if (!InitBlockInfo())
1956 0 : return (nullptr);
1957 :
1958 : /* --------------------------------------------------------------------
1959 : */
1960 : /* Validate the request */
1961 : /* --------------------------------------------------------------------
1962 : */
1963 3366660 : if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
1964 : {
1965 5 : ReportError(CE_Failure, CPLE_IllegalArg,
1966 : "Illegal nBlockXOff value (%d) in "
1967 : "GDALRasterBand::GetLockedBlockRef()\n",
1968 : nXBlockOff);
1969 :
1970 0 : return (nullptr);
1971 : }
1972 :
1973 3366660 : if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
1974 : {
1975 2 : ReportError(CE_Failure, CPLE_IllegalArg,
1976 : "Illegal nBlockYOff value (%d) in "
1977 : "GDALRasterBand::GetLockedBlockRef()\n",
1978 : nYBlockOff);
1979 :
1980 0 : return (nullptr);
1981 : }
1982 :
1983 3366650 : poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
1984 3366670 : if (poBlock == nullptr)
1985 0 : return nullptr;
1986 :
1987 3366670 : poBlock->AddLock();
1988 :
1989 : /* We need to temporarily drop the read-write lock in the following */
1990 : /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
1991 : */
1992 : /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
1993 : /* block cache fills, T1 might need to flush dirty blocks of D2 in the
1994 : */
1995 : /* below Internalize(), which will cause GDALRasterBlock::Write() to be
1996 : */
1997 : /* called and attempt at taking the lock on T2 (already taken).
1998 : * Similarly */
1999 : /* for T2 with D1, hence a deadlock situation (#6163) */
2000 : /* But this may open the door to other problems... */
2001 3366670 : if (poDS)
2002 3365930 : poDS->TemporarilyDropReadWriteLock();
2003 : /* allocate data space */
2004 3366670 : CPLErr eErr = poBlock->Internalize();
2005 3366680 : if (poDS)
2006 3365930 : poDS->ReacquireReadWriteLock();
2007 3366670 : if (eErr != CE_None)
2008 : {
2009 0 : poBlock->DropLock();
2010 0 : delete poBlock;
2011 0 : return nullptr;
2012 : }
2013 :
2014 3366670 : if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
2015 : {
2016 0 : poBlock->DropLock();
2017 0 : delete poBlock;
2018 0 : return nullptr;
2019 : }
2020 :
2021 3366680 : if (!bJustInitialize)
2022 : {
2023 2881930 : const GUInt32 nErrorCounter = CPLGetErrorCounter();
2024 2881920 : int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
2025 2881920 : eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
2026 2881930 : if (bCallLeaveReadWrite)
2027 130023 : LeaveReadWrite();
2028 2881930 : if (eErr != CE_None)
2029 : {
2030 1160 : poBlock->DropLock();
2031 1160 : FlushBlock(nXBlockOff, nYBlockOff);
2032 1160 : ReportError(CE_Failure, CPLE_AppDefined,
2033 : "IReadBlock failed at X offset %d, Y offset %d%s",
2034 : nXBlockOff, nYBlockOff,
2035 1160 : (nErrorCounter != CPLGetErrorCounter())
2036 1158 : ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
2037 : : "");
2038 1160 : return nullptr;
2039 : }
2040 :
2041 2880770 : nBlockReads++;
2042 2880770 : if (static_cast<GIntBig>(nBlockReads) ==
2043 2880770 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
2044 220 : 1 &&
2045 220 : nBand == 1 && poDS != nullptr)
2046 : {
2047 160 : CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
2048 160 : poDS->GetDescription());
2049 : }
2050 : }
2051 : }
2052 :
2053 10324200 : return poBlock;
2054 : }
2055 :
2056 : /************************************************************************/
2057 : /* Fill() */
2058 : /************************************************************************/
2059 :
2060 : /**
2061 : * \brief Fill this band with a constant value.
2062 : *
2063 : * GDAL makes no guarantees
2064 : * about what values pixels in newly created files are set to, so this
2065 : * method can be used to clear a band to a specified "default" value.
2066 : * The fill value is passed in as a double but this will be converted
2067 : * to the underlying type before writing to the file. An optional
2068 : * second argument allows the imaginary component of a complex
2069 : * constant value to be specified.
2070 : *
2071 : * This method is the same as the C function GDALFillRaster().
2072 : *
2073 : * @param dfRealValue Real component of fill value
2074 : * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
2075 : *
2076 : * @return CE_Failure if the write fails, otherwise CE_None
2077 : */
2078 268648 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
2079 : {
2080 :
2081 : // General approach is to construct a source block of the file's
2082 : // native type containing the appropriate value and then copy this
2083 : // to each block in the image via the RasterBlock cache. Using
2084 : // the cache means we avoid file I/O if it is not necessary, at the
2085 : // expense of some extra memcpy's (since we write to the
2086 : // RasterBlock cache, which is then at some point written to the
2087 : // underlying file, rather than simply directly to the underlying
2088 : // file.)
2089 :
2090 : // Check we can write to the file.
2091 268648 : if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
2092 : {
2093 6 : return CE_Failure;
2094 : }
2095 :
2096 : // Make sure block parameters are set.
2097 268642 : if (!InitBlockInfo())
2098 0 : return CE_Failure;
2099 :
2100 : // Allocate the source block.
2101 268642 : auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
2102 268642 : int elementSize = GDALGetDataTypeSizeBytes(eDataType);
2103 268642 : auto blockByteSize = blockSize * elementSize;
2104 : unsigned char *srcBlock =
2105 268642 : static_cast<unsigned char *>(VSIMalloc(blockByteSize));
2106 268642 : if (srcBlock == nullptr)
2107 : {
2108 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2109 : "GDALRasterBand::Fill(): Out of memory "
2110 : "allocating " CPL_FRMT_GUIB " bytes.\n",
2111 : static_cast<GUIntBig>(blockByteSize));
2112 0 : return CE_Failure;
2113 : }
2114 :
2115 : // Initialize the source block.
2116 268642 : double complexSrc[2] = {dfRealValue, dfImaginaryValue};
2117 268642 : GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
2118 : elementSize, blockSize);
2119 :
2120 268642 : const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
2121 :
2122 : // Write block to block cache
2123 871119 : for (int j = 0; j < nBlocksPerColumn; ++j)
2124 : {
2125 1499290 : for (int i = 0; i < nBlocksPerRow; ++i)
2126 : {
2127 896810 : GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
2128 896810 : if (destBlock == nullptr)
2129 : {
2130 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
2131 : "GDALRasterBand::Fill(): Error "
2132 : "while retrieving cache block.");
2133 0 : VSIFree(srcBlock);
2134 0 : return CE_Failure;
2135 : }
2136 896810 : memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
2137 896810 : destBlock->MarkDirty();
2138 896810 : destBlock->DropLock();
2139 : }
2140 : }
2141 :
2142 268642 : if (bCallLeaveReadWrite)
2143 267633 : LeaveReadWrite();
2144 :
2145 : // Free up the source block
2146 268642 : VSIFree(srcBlock);
2147 :
2148 268642 : return CE_None;
2149 : }
2150 :
2151 : /************************************************************************/
2152 : /* GDALFillRaster() */
2153 : /************************************************************************/
2154 :
2155 : /**
2156 : * \brief Fill this band with a constant value.
2157 : *
2158 : * @see GDALRasterBand::Fill()
2159 : */
2160 268580 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
2161 : double dfImaginaryValue)
2162 : {
2163 268580 : VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
2164 :
2165 268580 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2166 268580 : return poBand->Fill(dfRealValue, dfImaginaryValue);
2167 : }
2168 :
2169 : /************************************************************************/
2170 : /* GetAccess() */
2171 : /************************************************************************/
2172 :
2173 : /**
2174 : * \brief Find out if we have update permission for this band.
2175 : *
2176 : * This method is the same as the C function GDALGetRasterAccess().
2177 : *
2178 : * @return Either GA_Update or GA_ReadOnly.
2179 : */
2180 :
2181 2975 : GDALAccess GDALRasterBand::GetAccess()
2182 :
2183 : {
2184 2975 : return eAccess;
2185 : }
2186 :
2187 : /************************************************************************/
2188 : /* GDALGetRasterAccess() */
2189 : /************************************************************************/
2190 :
2191 : /**
2192 : * \brief Find out if we have update permission for this band.
2193 : *
2194 : * @see GDALRasterBand::GetAccess()
2195 : */
2196 :
2197 2324 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
2198 :
2199 : {
2200 2324 : VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
2201 :
2202 2324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2203 2324 : return poBand->GetAccess();
2204 : }
2205 :
2206 : /************************************************************************/
2207 : /* GetCategoryNames() */
2208 : /************************************************************************/
2209 :
2210 : /**
2211 : * \brief Fetch the list of category names for this raster.
2212 : *
2213 : * The return list is a "StringList" in the sense of the CPL functions.
2214 : * That is a NULL terminated array of strings. Raster values without
2215 : * associated names will have an empty string in the returned list. The
2216 : * first entry in the list is for raster values of zero, and so on.
2217 : *
2218 : * The returned stringlist should not be altered or freed by the application.
2219 : * It may change on the next GDAL call, so please copy it if it is needed
2220 : * for any period of time.
2221 : *
2222 : * This method is the same as the C function GDALGetRasterCategoryNames().
2223 : *
2224 : * @return list of names, or NULL if none.
2225 : */
2226 :
2227 297 : char **GDALRasterBand::GetCategoryNames()
2228 :
2229 : {
2230 297 : return nullptr;
2231 : }
2232 :
2233 : /************************************************************************/
2234 : /* GDALGetRasterCategoryNames() */
2235 : /************************************************************************/
2236 :
2237 : /**
2238 : * \brief Fetch the list of category names for this raster.
2239 : *
2240 : * @see GDALRasterBand::GetCategoryNames()
2241 : */
2242 :
2243 191 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
2244 :
2245 : {
2246 191 : VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
2247 :
2248 191 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2249 191 : return poBand->GetCategoryNames();
2250 : }
2251 :
2252 : /************************************************************************/
2253 : /* SetCategoryNames() */
2254 : /************************************************************************/
2255 :
2256 : /**
2257 : * \fn GDALRasterBand::SetCategoryNames(char**)
2258 : * \brief Set the category names for this band.
2259 : *
2260 : * See the GetCategoryNames() method for more on the interpretation of
2261 : * category names.
2262 : *
2263 : * This method is the same as the C function GDALSetRasterCategoryNames().
2264 : *
2265 : * @param papszNames the NULL terminated StringList of category names. May
2266 : * be NULL to just clear the existing list.
2267 : *
2268 : * @return CE_None on success of CE_Failure on failure. If unsupported
2269 : * by the driver CE_Failure is returned, but no error message is reported.
2270 : */
2271 :
2272 : /**/
2273 : /**/
2274 :
2275 0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
2276 : {
2277 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2278 0 : ReportError(CE_Failure, CPLE_NotSupported,
2279 : "SetCategoryNames() not supported for this dataset.");
2280 :
2281 0 : return CE_Failure;
2282 : }
2283 :
2284 : /************************************************************************/
2285 : /* GDALSetCategoryNames() */
2286 : /************************************************************************/
2287 :
2288 : /**
2289 : * \brief Set the category names for this band.
2290 : *
2291 : * @see GDALRasterBand::SetCategoryNames()
2292 : */
2293 :
2294 2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
2295 : CSLConstList papszNames)
2296 :
2297 : {
2298 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
2299 :
2300 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2301 2 : return poBand->SetCategoryNames(const_cast<char **>(papszNames));
2302 : }
2303 :
2304 : /************************************************************************/
2305 : /* GetNoDataValue() */
2306 : /************************************************************************/
2307 :
2308 : /**
2309 : * \brief Fetch the no data value for this band.
2310 : *
2311 : * If there is no out of data value, an out of range value will generally
2312 : * be returned. The no data value for a band is generally a special marker
2313 : * value used to mark pixels that are not valid data. Such pixels should
2314 : * generally not be displayed, nor contribute to analysis operations.
2315 : *
2316 : * The no data value returned is 'raw', meaning that it has no offset and
2317 : * scale applied.
2318 : *
2319 : * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
2320 : * lossy if the nodata value cannot exactly been represented by a double.
2321 : * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
2322 : *
2323 : * This method is the same as the C function GDALGetRasterNoDataValue().
2324 : *
2325 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2326 : * is actually associated with this layer. May be NULL (default).
2327 : *
2328 : * @return the nodata value for this band.
2329 : */
2330 :
2331 31582 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
2332 :
2333 : {
2334 31582 : if (pbSuccess != nullptr)
2335 31582 : *pbSuccess = FALSE;
2336 :
2337 31582 : return -1e10;
2338 : }
2339 :
2340 : /************************************************************************/
2341 : /* GDALGetRasterNoDataValue() */
2342 : /************************************************************************/
2343 :
2344 : /**
2345 : * \brief Fetch the no data value for this band.
2346 : *
2347 : * @see GDALRasterBand::GetNoDataValue()
2348 : */
2349 :
2350 414357 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
2351 : int *pbSuccess)
2352 :
2353 : {
2354 414357 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
2355 :
2356 414357 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2357 414357 : return poBand->GetNoDataValue(pbSuccess);
2358 : }
2359 :
2360 : /************************************************************************/
2361 : /* GetNoDataValueAsInt64() */
2362 : /************************************************************************/
2363 :
2364 : /**
2365 : * \brief Fetch the no data value for this band.
2366 : *
2367 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2368 : *
2369 : * If there is no out of data value, an out of range value will generally
2370 : * be returned. The no data value for a band is generally a special marker
2371 : * value used to mark pixels that are not valid data. Such pixels should
2372 : * generally not be displayed, nor contribute to analysis operations.
2373 : *
2374 : * The no data value returned is 'raw', meaning that it has no offset and
2375 : * scale applied.
2376 : *
2377 : * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
2378 : *
2379 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2380 : * is actually associated with this layer. May be NULL (default).
2381 : *
2382 : * @return the nodata value for this band.
2383 : *
2384 : * @since GDAL 3.5
2385 : */
2386 :
2387 5 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
2388 :
2389 : {
2390 5 : if (pbSuccess != nullptr)
2391 5 : *pbSuccess = FALSE;
2392 :
2393 5 : return std::numeric_limits<int64_t>::min();
2394 : }
2395 :
2396 : /************************************************************************/
2397 : /* GDALGetRasterNoDataValueAsInt64() */
2398 : /************************************************************************/
2399 :
2400 : /**
2401 : * \brief Fetch the no data value for this band.
2402 : *
2403 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2404 : *
2405 : * @see GDALRasterBand::GetNoDataValueAsInt64()
2406 : *
2407 : * @since GDAL 3.5
2408 : */
2409 :
2410 31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2411 : int *pbSuccess)
2412 :
2413 : {
2414 31 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
2415 : std::numeric_limits<int64_t>::min());
2416 :
2417 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2418 31 : return poBand->GetNoDataValueAsInt64(pbSuccess);
2419 : }
2420 :
2421 : /************************************************************************/
2422 : /* GetNoDataValueAsUInt64() */
2423 : /************************************************************************/
2424 :
2425 : /**
2426 : * \brief Fetch the no data value for this band.
2427 : *
2428 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2429 : *
2430 : * If there is no out of data value, an out of range value will generally
2431 : * be returned. The no data value for a band is generally a special marker
2432 : * value used to mark pixels that are not valid data. Such pixels should
2433 : * generally not be displayed, nor contribute to analysis operations.
2434 : *
2435 : * The no data value returned is 'raw', meaning that it has no offset and
2436 : * scale applied.
2437 : *
2438 : * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
2439 : *
2440 : * @param pbSuccess pointer to a boolean to use to indicate if a value
2441 : * is actually associated with this layer. May be NULL (default).
2442 : *
2443 : * @return the nodata value for this band.
2444 : *
2445 : * @since GDAL 3.5
2446 : */
2447 :
2448 4 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
2449 :
2450 : {
2451 4 : if (pbSuccess != nullptr)
2452 4 : *pbSuccess = FALSE;
2453 :
2454 4 : return std::numeric_limits<uint64_t>::max();
2455 : }
2456 :
2457 : /************************************************************************/
2458 : /* GDALGetRasterNoDataValueAsUInt64() */
2459 : /************************************************************************/
2460 :
2461 : /**
2462 : * \brief Fetch the no data value for this band.
2463 : *
2464 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2465 : *
2466 : * @see GDALRasterBand::GetNoDataValueAsUInt64()
2467 : *
2468 : * @since GDAL 3.5
2469 : */
2470 :
2471 22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2472 : int *pbSuccess)
2473 :
2474 : {
2475 22 : VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
2476 : std::numeric_limits<uint64_t>::max());
2477 :
2478 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2479 22 : return poBand->GetNoDataValueAsUInt64(pbSuccess);
2480 : }
2481 :
2482 : /************************************************************************/
2483 : /* SetNoDataValueAsString() */
2484 : /************************************************************************/
2485 :
2486 : /**
2487 : * \brief Set the no data value for this band.
2488 : *
2489 : * Depending on drivers, changing the no data value may or may not have an
2490 : * effect on the pixel values of a raster that has just been created. It is
2491 : * thus advised to explicitly called Fill() if the intent is to initialize
2492 : * the raster to the nodata value.
2493 : * In any case, changing an existing no data value, when one already exists and
2494 : * the dataset exists or has been initialized, has no effect on the pixel whose
2495 : * value matched the previous nodata value.
2496 : *
2497 : * To clear the nodata value, use DeleteNoDataValue().
2498 : *
2499 : * @param pszNoData the value to set.
2500 : * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
2501 : * If the value cannot be exactly represented on the output data
2502 : * type, *pbCannotBeExactlyRepresented will be set to true.
2503 : *
2504 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2505 : * by the driver, CE_Failure is returned but no error message will have
2506 : * been emitted.
2507 : *
2508 : * @since 3.11
2509 : */
2510 :
2511 : CPLErr
2512 123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
2513 : bool *pbCannotBeExactlyRepresented)
2514 : {
2515 123 : if (pbCannotBeExactlyRepresented)
2516 123 : *pbCannotBeExactlyRepresented = false;
2517 123 : if (eDataType == GDT_Int64)
2518 : {
2519 8 : if (strchr(pszNoData, '.') ||
2520 3 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2521 : {
2522 2 : char *endptr = nullptr;
2523 2 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2524 4 : if (endptr == pszNoData + strlen(pszNoData) &&
2525 2 : GDALIsValueExactAs<int64_t>(dfVal))
2526 : {
2527 0 : return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
2528 : }
2529 : }
2530 : else
2531 : {
2532 : try
2533 : {
2534 7 : const auto val = std::stoll(pszNoData);
2535 1 : return SetNoDataValueAsInt64(static_cast<int64_t>(val));
2536 : }
2537 2 : catch (const std::exception &)
2538 : {
2539 : }
2540 : }
2541 : }
2542 118 : else if (eDataType == GDT_UInt64)
2543 : {
2544 2 : if (strchr(pszNoData, '.') ||
2545 1 : CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
2546 : {
2547 0 : char *endptr = nullptr;
2548 0 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2549 0 : if (endptr == pszNoData + strlen(pszNoData) &&
2550 0 : GDALIsValueExactAs<uint64_t>(dfVal))
2551 : {
2552 0 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
2553 : }
2554 : }
2555 : else
2556 : {
2557 : try
2558 : {
2559 1 : const auto val = std::stoull(pszNoData);
2560 1 : return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
2561 : }
2562 0 : catch (const std::exception &)
2563 : {
2564 : }
2565 : }
2566 : }
2567 117 : else if (eDataType == GDT_Float32)
2568 : {
2569 10 : char *endptr = nullptr;
2570 10 : const float fVal = CPLStrtof(pszNoData, &endptr);
2571 10 : if (endptr == pszNoData + strlen(pszNoData))
2572 : {
2573 10 : return SetNoDataValue(double(fVal));
2574 : }
2575 : }
2576 : else
2577 : {
2578 107 : char *endptr = nullptr;
2579 107 : const double dfVal = CPLStrtod(pszNoData, &endptr);
2580 214 : if (endptr == pszNoData + strlen(pszNoData) &&
2581 107 : GDALIsValueExactAs(dfVal, eDataType))
2582 : {
2583 106 : return SetNoDataValue(dfVal);
2584 : }
2585 : }
2586 5 : if (pbCannotBeExactlyRepresented)
2587 5 : *pbCannotBeExactlyRepresented = true;
2588 5 : return CE_Failure;
2589 : }
2590 :
2591 : /************************************************************************/
2592 : /* SetNoDataValue() */
2593 : /************************************************************************/
2594 :
2595 : /**
2596 : * \fn GDALRasterBand::SetNoDataValue(double)
2597 : * \brief Set the no data value for this band.
2598 : *
2599 : * Depending on drivers, changing the no data value may or may not have an
2600 : * effect on the pixel values of a raster that has just been created. It is
2601 : * thus advised to explicitly called Fill() if the intent is to initialize
2602 : * the raster to the nodata value.
2603 : * In any case, changing an existing no data value, when one already exists and
2604 : * the dataset exists or has been initialized, has no effect on the pixel whose
2605 : * value matched the previous nodata value.
2606 : *
2607 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2608 : * be represented by a double, use SetNoDataValueAsInt64() or
2609 : * SetNoDataValueAsUInt64() instead.
2610 : *
2611 : * To clear the nodata value, use DeleteNoDataValue().
2612 : *
2613 : * This method is the same as the C function GDALSetRasterNoDataValue().
2614 : *
2615 : * @param dfNoData the value to set.
2616 : *
2617 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2618 : * by the driver, CE_Failure is returned but no error message will have
2619 : * been emitted.
2620 : */
2621 :
2622 : /**/
2623 : /**/
2624 :
2625 0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
2626 :
2627 : {
2628 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2629 0 : ReportError(CE_Failure, CPLE_NotSupported,
2630 : "SetNoDataValue() not supported for this dataset.");
2631 :
2632 0 : return CE_Failure;
2633 : }
2634 :
2635 : /************************************************************************/
2636 : /* GDALSetRasterNoDataValue() */
2637 : /************************************************************************/
2638 :
2639 : /**
2640 : * \brief Set the no data value for this band.
2641 : *
2642 : * Depending on drivers, changing the no data value may or may not have an
2643 : * effect on the pixel values of a raster that has just been created. It is
2644 : * thus advised to explicitly called Fill() if the intent is to initialize
2645 : * the raster to the nodata value.
2646 : * In any case, changing an existing no data value, when one already exists and
2647 : * the dataset exists or has been initialized, has no effect on the pixel whose
2648 : * value matched the previous nodata value.
2649 : *
2650 : * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
2651 : * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
2652 : * GDALSetRasterNoDataValueAsUInt64() instead.
2653 : *
2654 : * @see GDALRasterBand::SetNoDataValue()
2655 : */
2656 :
2657 878 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
2658 : double dfValue)
2659 :
2660 : {
2661 878 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
2662 :
2663 878 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2664 878 : return poBand->SetNoDataValue(dfValue);
2665 : }
2666 :
2667 : /************************************************************************/
2668 : /* SetNoDataValueAsInt64() */
2669 : /************************************************************************/
2670 :
2671 : /**
2672 : * \brief Set the no data value for this band.
2673 : *
2674 : * This method should ONLY be called on rasters whose data type is GDT_Int64.
2675 : *
2676 : * Depending on drivers, changing the no data value may or may not have an
2677 : * effect on the pixel values of a raster that has just been created. It is
2678 : * thus advised to explicitly called Fill() if the intent is to initialize
2679 : * the raster to the nodata value.
2680 : * In ay case, changing an existing no data value, when one already exists and
2681 : * the dataset exists or has been initialized, has no effect on the pixel whose
2682 : * value matched the previous nodata value.
2683 : *
2684 : * To clear the nodata value, use DeleteNoDataValue().
2685 : *
2686 : * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
2687 : *
2688 : * @param nNoDataValue the value to set.
2689 : *
2690 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2691 : * by the driver, CE_Failure is returned but no error message will have
2692 : * been emitted.
2693 : *
2694 : * @since GDAL 3.5
2695 : */
2696 :
2697 0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
2698 :
2699 : {
2700 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2701 0 : ReportError(CE_Failure, CPLE_NotSupported,
2702 : "SetNoDataValueAsInt64() not supported for this dataset.");
2703 :
2704 0 : return CE_Failure;
2705 : }
2706 :
2707 : /************************************************************************/
2708 : /* GDALSetRasterNoDataValueAsInt64() */
2709 : /************************************************************************/
2710 :
2711 : /**
2712 : * \brief Set the no data value for this band.
2713 : *
2714 : * This function should ONLY be called on rasters whose data type is GDT_Int64.
2715 : *
2716 : * Depending on drivers, changing the no data value may or may not have an
2717 : * effect on the pixel values of a raster that has just been created. It is
2718 : * thus advised to explicitly called Fill() if the intent is to initialize
2719 : * the raster to the nodata value.
2720 : * In ay case, changing an existing no data value, when one already exists and
2721 : * the dataset exists or has been initialized, has no effect on the pixel whose
2722 : * value matched the previous nodata value.
2723 : *
2724 : * @see GDALRasterBand::SetNoDataValueAsInt64()
2725 : *
2726 : * @since GDAL 3.5
2727 : */
2728 :
2729 22 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
2730 : int64_t nValue)
2731 :
2732 : {
2733 22 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
2734 :
2735 22 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2736 22 : return poBand->SetNoDataValueAsInt64(nValue);
2737 : }
2738 :
2739 : /************************************************************************/
2740 : /* SetNoDataValueAsUInt64() */
2741 : /************************************************************************/
2742 :
2743 : /**
2744 : * \brief Set the no data value for this band.
2745 : *
2746 : * This method should ONLY be called on rasters whose data type is GDT_UInt64.
2747 : *
2748 : * Depending on drivers, changing the no data value may or may not have an
2749 : * effect on the pixel values of a raster that has just been created. It is
2750 : * thus advised to explicitly called Fill() if the intent is to initialize
2751 : * the raster to the nodata value.
2752 : * In ay case, changing an existing no data value, when one already exists and
2753 : * the dataset exists or has been initialized, has no effect on the pixel whose
2754 : * value matched the previous nodata value.
2755 : *
2756 : * To clear the nodata value, use DeleteNoDataValue().
2757 : *
2758 : * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
2759 : *
2760 : * @param nNoDataValue the value to set.
2761 : *
2762 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2763 : * by the driver, CE_Failure is returned but no error message will have
2764 : * been emitted.
2765 : *
2766 : * @since GDAL 3.5
2767 : */
2768 :
2769 0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
2770 :
2771 : {
2772 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2773 0 : ReportError(CE_Failure, CPLE_NotSupported,
2774 : "SetNoDataValueAsUInt64() not supported for this dataset.");
2775 :
2776 0 : return CE_Failure;
2777 : }
2778 :
2779 : /************************************************************************/
2780 : /* GDALSetRasterNoDataValueAsUInt64() */
2781 : /************************************************************************/
2782 :
2783 : /**
2784 : * \brief Set the no data value for this band.
2785 : *
2786 : * This function should ONLY be called on rasters whose data type is GDT_UInt64.
2787 : *
2788 : * Depending on drivers, changing the no data value may or may not have an
2789 : * effect on the pixel values of a raster that has just been created. It is
2790 : * thus advised to explicitly called Fill() if the intent is to initialize
2791 : * the raster to the nodata value.
2792 : * In ay case, changing an existing no data value, when one already exists and
2793 : * the dataset exists or has been initialized, has no effect on the pixel whose
2794 : * value matched the previous nodata value.
2795 : *
2796 : * @see GDALRasterBand::SetNoDataValueAsUInt64()
2797 : *
2798 : * @since GDAL 3.5
2799 : */
2800 :
2801 20 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
2802 : uint64_t nValue)
2803 :
2804 : {
2805 20 : VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
2806 :
2807 20 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2808 20 : return poBand->SetNoDataValueAsUInt64(nValue);
2809 : }
2810 :
2811 : /************************************************************************/
2812 : /* DeleteNoDataValue() */
2813 : /************************************************************************/
2814 :
2815 : /**
2816 : * \brief Remove the no data value for this band.
2817 : *
2818 : * This method is the same as the C function GDALDeleteRasterNoDataValue().
2819 : *
2820 : * @return CE_None on success, or CE_Failure on failure. If unsupported
2821 : * by the driver, CE_Failure is returned but no error message will have
2822 : * been emitted.
2823 : *
2824 : * @since GDAL 2.1
2825 : */
2826 :
2827 0 : CPLErr GDALRasterBand::DeleteNoDataValue()
2828 :
2829 : {
2830 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
2831 0 : ReportError(CE_Failure, CPLE_NotSupported,
2832 : "DeleteNoDataValue() not supported for this dataset.");
2833 :
2834 0 : return CE_Failure;
2835 : }
2836 :
2837 : /************************************************************************/
2838 : /* GDALDeleteRasterNoDataValue() */
2839 : /************************************************************************/
2840 :
2841 : /**
2842 : * \brief Remove the no data value for this band.
2843 : *
2844 : * @see GDALRasterBand::DeleteNoDataValue()
2845 : *
2846 : * @since GDAL 2.1
2847 : */
2848 :
2849 53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
2850 :
2851 : {
2852 53 : VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
2853 :
2854 53 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2855 53 : return poBand->DeleteNoDataValue();
2856 : }
2857 :
2858 : /************************************************************************/
2859 : /* GetMaximum() */
2860 : /************************************************************************/
2861 :
2862 : /**
2863 : * \brief Fetch the maximum value for this band.
2864 : *
2865 : * For file formats that don't know this intrinsically, the maximum supported
2866 : * value for the data type will generally be returned.
2867 : *
2868 : * This method is the same as the C function GDALGetRasterMaximum().
2869 : *
2870 : * @param pbSuccess pointer to a boolean to use to indicate if the
2871 : * returned value is a tight maximum or not. May be NULL (default).
2872 : *
2873 : * @return the maximum raster value (excluding no data pixels)
2874 : */
2875 :
2876 525 : double GDALRasterBand::GetMaximum(int *pbSuccess)
2877 :
2878 : {
2879 525 : const char *pszValue = nullptr;
2880 :
2881 525 : if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
2882 : {
2883 47 : if (pbSuccess != nullptr)
2884 42 : *pbSuccess = TRUE;
2885 :
2886 47 : return CPLAtofM(pszValue);
2887 : }
2888 :
2889 478 : if (pbSuccess != nullptr)
2890 474 : *pbSuccess = FALSE;
2891 :
2892 478 : switch (eDataType)
2893 : {
2894 327 : case GDT_Byte:
2895 : {
2896 327 : EnablePixelTypeSignedByteWarning(false);
2897 : const char *pszPixelType =
2898 327 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
2899 327 : EnablePixelTypeSignedByteWarning(true);
2900 327 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
2901 0 : return 127;
2902 :
2903 327 : return 255;
2904 : }
2905 :
2906 1 : case GDT_Int8:
2907 1 : return 127;
2908 :
2909 21 : case GDT_UInt16:
2910 21 : return 65535;
2911 :
2912 24 : case GDT_Int16:
2913 : case GDT_CInt16:
2914 24 : return 32767;
2915 :
2916 39 : case GDT_Int32:
2917 : case GDT_CInt32:
2918 39 : return 2147483647.0;
2919 :
2920 12 : case GDT_UInt32:
2921 12 : return 4294967295.0;
2922 :
2923 1 : case GDT_Int64:
2924 1 : return static_cast<double>(std::numeric_limits<GInt64>::max());
2925 :
2926 1 : case GDT_UInt64:
2927 1 : return static_cast<double>(std::numeric_limits<GUInt64>::max());
2928 :
2929 0 : case GDT_Float16:
2930 : case GDT_CFloat16:
2931 0 : return 65504.0;
2932 :
2933 30 : case GDT_Float32:
2934 : case GDT_CFloat32:
2935 30 : return 4294967295.0; // Not actually accurate.
2936 :
2937 22 : case GDT_Float64:
2938 : case GDT_CFloat64:
2939 22 : return 4294967295.0; // Not actually accurate.
2940 :
2941 0 : case GDT_Unknown:
2942 : case GDT_TypeCount:
2943 0 : break;
2944 : }
2945 0 : return 4294967295.0; // Not actually accurate.
2946 : }
2947 :
2948 : /************************************************************************/
2949 : /* GDALGetRasterMaximum() */
2950 : /************************************************************************/
2951 :
2952 : /**
2953 : * \brief Fetch the maximum value for this band.
2954 : *
2955 : * @see GDALRasterBand::GetMaximum()
2956 : */
2957 :
2958 324 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
2959 :
2960 : {
2961 324 : VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
2962 :
2963 324 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
2964 324 : return poBand->GetMaximum(pbSuccess);
2965 : }
2966 :
2967 : /************************************************************************/
2968 : /* GetMinimum() */
2969 : /************************************************************************/
2970 :
2971 : /**
2972 : * \brief Fetch the minimum value for this band.
2973 : *
2974 : * For file formats that don't know this intrinsically, the minimum supported
2975 : * value for the data type will generally be returned.
2976 : *
2977 : * This method is the same as the C function GDALGetRasterMinimum().
2978 : *
2979 : * @param pbSuccess pointer to a boolean to use to indicate if the
2980 : * returned value is a tight minimum or not. May be NULL (default).
2981 : *
2982 : * @return the minimum raster value (excluding no data pixels)
2983 : */
2984 :
2985 533 : double GDALRasterBand::GetMinimum(int *pbSuccess)
2986 :
2987 : {
2988 533 : const char *pszValue = nullptr;
2989 :
2990 533 : if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
2991 : {
2992 52 : if (pbSuccess != nullptr)
2993 47 : *pbSuccess = TRUE;
2994 :
2995 52 : return CPLAtofM(pszValue);
2996 : }
2997 :
2998 481 : if (pbSuccess != nullptr)
2999 477 : *pbSuccess = FALSE;
3000 :
3001 481 : switch (eDataType)
3002 : {
3003 330 : case GDT_Byte:
3004 : {
3005 330 : EnablePixelTypeSignedByteWarning(false);
3006 : const char *pszPixelType =
3007 330 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
3008 330 : EnablePixelTypeSignedByteWarning(true);
3009 330 : if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
3010 0 : return -128;
3011 :
3012 330 : return 0;
3013 : }
3014 :
3015 1 : case GDT_Int8:
3016 1 : return -128;
3017 :
3018 21 : case GDT_UInt16:
3019 21 : return 0;
3020 :
3021 24 : case GDT_Int16:
3022 : case GDT_CInt16:
3023 24 : return -32768;
3024 :
3025 39 : case GDT_Int32:
3026 : case GDT_CInt32:
3027 39 : return -2147483648.0;
3028 :
3029 12 : case GDT_UInt32:
3030 12 : return 0;
3031 :
3032 1 : case GDT_Int64:
3033 1 : return static_cast<double>(std::numeric_limits<GInt64>::lowest());
3034 :
3035 1 : case GDT_UInt64:
3036 1 : return 0;
3037 :
3038 0 : case GDT_Float16:
3039 : case GDT_CFloat16:
3040 0 : return -65504.0;
3041 :
3042 30 : case GDT_Float32:
3043 : case GDT_CFloat32:
3044 30 : return -4294967295.0; // Not actually accurate.
3045 :
3046 22 : case GDT_Float64:
3047 : case GDT_CFloat64:
3048 22 : return -4294967295.0; // Not actually accurate.
3049 :
3050 0 : case GDT_Unknown:
3051 : case GDT_TypeCount:
3052 0 : break;
3053 : }
3054 0 : return -4294967295.0; // Not actually accurate.
3055 : }
3056 :
3057 : /************************************************************************/
3058 : /* GDALGetRasterMinimum() */
3059 : /************************************************************************/
3060 :
3061 : /**
3062 : * \brief Fetch the minimum value for this band.
3063 : *
3064 : * @see GDALRasterBand::GetMinimum()
3065 : */
3066 :
3067 334 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
3068 :
3069 : {
3070 334 : VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
3071 :
3072 334 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3073 334 : return poBand->GetMinimum(pbSuccess);
3074 : }
3075 :
3076 : /************************************************************************/
3077 : /* GetColorInterpretation() */
3078 : /************************************************************************/
3079 :
3080 : /**
3081 : * \brief How should this band be interpreted as color?
3082 : *
3083 : * GCI_Undefined is returned when the format doesn't know anything
3084 : * about the color interpretation.
3085 : *
3086 : * This method is the same as the C function
3087 : * GDALGetRasterColorInterpretation().
3088 : *
3089 : * @return color interpretation value for band.
3090 : */
3091 :
3092 163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
3093 :
3094 : {
3095 163 : return GCI_Undefined;
3096 : }
3097 :
3098 : /************************************************************************/
3099 : /* GDALGetRasterColorInterpretation() */
3100 : /************************************************************************/
3101 :
3102 : /**
3103 : * \brief How should this band be interpreted as color?
3104 : *
3105 : * @see GDALRasterBand::GetColorInterpretation()
3106 : */
3107 :
3108 : GDALColorInterp CPL_STDCALL
3109 5606 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
3110 :
3111 : {
3112 5606 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
3113 :
3114 5606 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3115 5606 : return poBand->GetColorInterpretation();
3116 : }
3117 :
3118 : /************************************************************************/
3119 : /* SetColorInterpretation() */
3120 : /************************************************************************/
3121 :
3122 : /**
3123 : * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
3124 : * \brief Set color interpretation of a band.
3125 : *
3126 : * This method is the same as the C function GDALSetRasterColorInterpretation().
3127 : *
3128 : * @param eColorInterp the new color interpretation to apply to this band.
3129 : *
3130 : * @return CE_None on success or CE_Failure if method is unsupported by format.
3131 : */
3132 :
3133 : /**/
3134 : /**/
3135 :
3136 3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
3137 :
3138 : {
3139 3 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3140 3 : ReportError(CE_Failure, CPLE_NotSupported,
3141 : "SetColorInterpretation() not supported for this dataset.");
3142 3 : return CE_Failure;
3143 : }
3144 :
3145 : /************************************************************************/
3146 : /* GDALSetRasterColorInterpretation() */
3147 : /************************************************************************/
3148 :
3149 : /**
3150 : * \brief Set color interpretation of a band.
3151 : *
3152 : * @see GDALRasterBand::SetColorInterpretation()
3153 : */
3154 :
3155 1846 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
3156 : GDALRasterBandH hBand, GDALColorInterp eColorInterp)
3157 :
3158 : {
3159 1846 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
3160 :
3161 1846 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3162 1846 : return poBand->SetColorInterpretation(eColorInterp);
3163 : }
3164 :
3165 : /************************************************************************/
3166 : /* GetColorTable() */
3167 : /************************************************************************/
3168 :
3169 : /**
3170 : * \brief Fetch the color table associated with band.
3171 : *
3172 : * If there is no associated color table, the return result is NULL. The
3173 : * returned color table remains owned by the GDALRasterBand, and can't
3174 : * be depended on for long, nor should it ever be modified by the caller.
3175 : *
3176 : * This method is the same as the C function GDALGetRasterColorTable().
3177 : *
3178 : * @return internal color table, or NULL.
3179 : */
3180 :
3181 234 : GDALColorTable *GDALRasterBand::GetColorTable()
3182 :
3183 : {
3184 234 : return nullptr;
3185 : }
3186 :
3187 : /************************************************************************/
3188 : /* GDALGetRasterColorTable() */
3189 : /************************************************************************/
3190 :
3191 : /**
3192 : * \brief Fetch the color table associated with band.
3193 : *
3194 : * @see GDALRasterBand::GetColorTable()
3195 : */
3196 :
3197 1971 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
3198 :
3199 : {
3200 1971 : VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
3201 :
3202 1971 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3203 1971 : return GDALColorTable::ToHandle(poBand->GetColorTable());
3204 : }
3205 :
3206 : /************************************************************************/
3207 : /* SetColorTable() */
3208 : /************************************************************************/
3209 :
3210 : /**
3211 : * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
3212 : * \brief Set the raster color table.
3213 : *
3214 : * The driver will make a copy of all desired data in the colortable. It
3215 : * remains owned by the caller after the call.
3216 : *
3217 : * This method is the same as the C function GDALSetRasterColorTable().
3218 : *
3219 : * @param poCT the color table to apply. This may be NULL to clear the color
3220 : * table (where supported).
3221 : *
3222 : * @return CE_None on success, or CE_Failure on failure. If the action is
3223 : * unsupported by the driver, a value of CE_Failure is returned, but no
3224 : * error is issued.
3225 : */
3226 :
3227 : /**/
3228 : /**/
3229 :
3230 0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
3231 :
3232 : {
3233 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3234 0 : ReportError(CE_Failure, CPLE_NotSupported,
3235 : "SetColorTable() not supported for this dataset.");
3236 0 : return CE_Failure;
3237 : }
3238 :
3239 : /************************************************************************/
3240 : /* GDALSetRasterColorTable() */
3241 : /************************************************************************/
3242 :
3243 : /**
3244 : * \brief Set the raster color table.
3245 : *
3246 : * @see GDALRasterBand::SetColorTable()
3247 : */
3248 :
3249 78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
3250 : GDALColorTableH hCT)
3251 :
3252 : {
3253 78 : VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
3254 :
3255 78 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3256 78 : return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
3257 : }
3258 :
3259 : /************************************************************************/
3260 : /* HasArbitraryOverviews() */
3261 : /************************************************************************/
3262 :
3263 : /**
3264 : * \brief Check for arbitrary overviews.
3265 : *
3266 : * This returns TRUE if the underlying datastore can compute arbitrary
3267 : * overviews efficiently, such as is the case with OGDI over a network.
3268 : * Datastores with arbitrary overviews don't generally have any fixed
3269 : * overviews, but the RasterIO() method can be used in downsampling mode
3270 : * to get overview data efficiently.
3271 : *
3272 : * This method is the same as the C function GDALHasArbitraryOverviews(),
3273 : *
3274 : * @return TRUE if arbitrary overviews available (efficiently), otherwise
3275 : * FALSE.
3276 : */
3277 :
3278 260 : int GDALRasterBand::HasArbitraryOverviews()
3279 :
3280 : {
3281 260 : return FALSE;
3282 : }
3283 :
3284 : /************************************************************************/
3285 : /* GDALHasArbitraryOverviews() */
3286 : /************************************************************************/
3287 :
3288 : /**
3289 : * \brief Check for arbitrary overviews.
3290 : *
3291 : * @see GDALRasterBand::HasArbitraryOverviews()
3292 : */
3293 :
3294 181 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
3295 :
3296 : {
3297 181 : VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
3298 :
3299 181 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3300 181 : return poBand->HasArbitraryOverviews();
3301 : }
3302 :
3303 : /************************************************************************/
3304 : /* GetOverviewCount() */
3305 : /************************************************************************/
3306 :
3307 : /**
3308 : * \brief Return the number of overview layers available.
3309 : *
3310 : * This method is the same as the C function GDALGetOverviewCount().
3311 : *
3312 : * @return overview count, zero if none.
3313 : */
3314 :
3315 1066300 : int GDALRasterBand::GetOverviewCount()
3316 :
3317 : {
3318 1723040 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3319 656739 : poDS->AreOverviewsEnabled())
3320 656739 : return poDS->oOvManager.GetOverviewCount(nBand);
3321 :
3322 409557 : return 0;
3323 : }
3324 :
3325 : /************************************************************************/
3326 : /* GDALGetOverviewCount() */
3327 : /************************************************************************/
3328 :
3329 : /**
3330 : * \brief Return the number of overview layers available.
3331 : *
3332 : * @see GDALRasterBand::GetOverviewCount()
3333 : */
3334 :
3335 3289 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
3336 :
3337 : {
3338 3289 : VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
3339 :
3340 3289 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3341 3289 : return poBand->GetOverviewCount();
3342 : }
3343 :
3344 : /************************************************************************/
3345 : /* GetOverview() */
3346 : /************************************************************************/
3347 :
3348 : /**
3349 : * \brief Fetch overview raster band object.
3350 : *
3351 : * This method is the same as the C function GDALGetOverview().
3352 : *
3353 : * @param i overview index between 0 and GetOverviewCount()-1.
3354 : *
3355 : * @return overview GDALRasterBand.
3356 : */
3357 :
3358 846 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
3359 :
3360 : {
3361 1636 : if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
3362 790 : poDS->AreOverviewsEnabled())
3363 790 : return poDS->oOvManager.GetOverview(nBand, i);
3364 :
3365 56 : return nullptr;
3366 : }
3367 :
3368 : /************************************************************************/
3369 : /* GDALGetOverview() */
3370 : /************************************************************************/
3371 :
3372 : /**
3373 : * \brief Fetch overview raster band object.
3374 : *
3375 : * @see GDALRasterBand::GetOverview()
3376 : */
3377 :
3378 5658 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
3379 :
3380 : {
3381 5658 : VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
3382 :
3383 5658 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3384 5658 : return GDALRasterBand::ToHandle(poBand->GetOverview(i));
3385 : }
3386 :
3387 : /************************************************************************/
3388 : /* GetRasterSampleOverview() */
3389 : /************************************************************************/
3390 :
3391 : /**
3392 : * \brief Fetch best sampling overview.
3393 : *
3394 : * Returns the most reduced overview of the given band that still satisfies
3395 : * the desired number of samples. This function can be used with zero
3396 : * as the number of desired samples to fetch the most reduced overview.
3397 : * The same band as was passed in will be returned if it has not overviews,
3398 : * or if none of the overviews have enough samples.
3399 : *
3400 : * This method is the same as the C functions GDALGetRasterSampleOverview()
3401 : * and GDALGetRasterSampleOverviewEx().
3402 : *
3403 : * @param nDesiredSamples the returned band will have at least this many
3404 : * pixels.
3405 : *
3406 : * @return optimal overview or the band itself.
3407 : */
3408 :
3409 : GDALRasterBand *
3410 2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
3411 :
3412 : {
3413 2006 : GDALRasterBand *poBestBand = this;
3414 :
3415 2006 : double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
3416 :
3417 4023 : for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
3418 : {
3419 2017 : GDALRasterBand *poOBand = GetOverview(iOverview);
3420 :
3421 2017 : if (poOBand == nullptr)
3422 0 : continue;
3423 :
3424 : const double dfOSamples =
3425 2017 : poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
3426 :
3427 2017 : if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
3428 : {
3429 2014 : dfBestSamples = dfOSamples;
3430 2014 : poBestBand = poOBand;
3431 : }
3432 : }
3433 :
3434 2006 : return poBestBand;
3435 : }
3436 :
3437 : /************************************************************************/
3438 : /* GDALGetRasterSampleOverview() */
3439 : /************************************************************************/
3440 :
3441 : /**
3442 : * \brief Fetch best sampling overview.
3443 : *
3444 : * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
3445 : * billion samples.
3446 : *
3447 : * @see GDALRasterBand::GetRasterSampleOverview()
3448 : * @see GDALGetRasterSampleOverviewEx()
3449 : */
3450 :
3451 0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
3452 : int nDesiredSamples)
3453 :
3454 : {
3455 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
3456 :
3457 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3458 0 : return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
3459 0 : nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
3460 : }
3461 :
3462 : /************************************************************************/
3463 : /* GDALGetRasterSampleOverviewEx() */
3464 : /************************************************************************/
3465 :
3466 : /**
3467 : * \brief Fetch best sampling overview.
3468 : *
3469 : * @see GDALRasterBand::GetRasterSampleOverview()
3470 : * @since GDAL 2.0
3471 : */
3472 :
3473 : GDALRasterBandH CPL_STDCALL
3474 2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
3475 :
3476 : {
3477 2000 : VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
3478 :
3479 2000 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3480 2000 : return GDALRasterBand::ToHandle(
3481 4000 : poBand->GetRasterSampleOverview(nDesiredSamples));
3482 : }
3483 :
3484 : /************************************************************************/
3485 : /* BuildOverviews() */
3486 : /************************************************************************/
3487 :
3488 : /**
3489 : * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
3490 : * GDALProgressFunc, void*) \brief Build raster overview(s)
3491 : *
3492 : * If the operation is unsupported for the indicated dataset, then
3493 : * CE_Failure is returned, and CPLGetLastErrorNo() will return
3494 : * CPLE_NotSupported.
3495 : *
3496 : * WARNING: Most formats don't support per-band overview computation, but
3497 : * require that overviews are computed for all bands of a dataset, using
3498 : * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
3499 : * is the HFA driver which supports this method.
3500 : *
3501 : * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
3502 : * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
3503 : * applied.
3504 : * @param nOverviews number of overviews to build.
3505 : * @param panOverviewList the list of overview decimation factors to build.
3506 : * @param pfnProgress a function to call to report progress, or NULL.
3507 : * @param pProgressData application data to pass to the progress function.
3508 : * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
3509 : * key=value pairs, or NULL
3510 : *
3511 : * @return CE_None on success or CE_Failure if the operation doesn't work.
3512 : */
3513 :
3514 : /**/
3515 : /**/
3516 :
3517 0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
3518 : int /*nOverviews*/,
3519 : const int * /*panOverviewList*/,
3520 : GDALProgressFunc /*pfnProgress*/,
3521 : void * /*pProgressData*/,
3522 : CSLConstList /* papszOptions */)
3523 :
3524 : {
3525 0 : ReportError(CE_Failure, CPLE_NotSupported,
3526 : "BuildOverviews() not supported for this dataset.");
3527 :
3528 0 : return (CE_Failure);
3529 : }
3530 :
3531 : /************************************************************************/
3532 : /* GetOffset() */
3533 : /************************************************************************/
3534 :
3535 : /**
3536 : * \brief Fetch the raster value offset.
3537 : *
3538 : * This value (in combination with the GetScale() value) can be used to
3539 : * transform raw pixel values into the units returned by GetUnitType().
3540 : * For example this might be used to store elevations in GUInt16 bands
3541 : * with a precision of 0.1, and starting from -100.
3542 : *
3543 : * Units value = (raw value * scale) + offset
3544 : *
3545 : * Note that applying scale and offset is of the responsibility of the user,
3546 : * and is not done by methods such as RasterIO() or ReadBlock().
3547 : *
3548 : * For file formats that don't know this intrinsically a value of zero
3549 : * is returned.
3550 : *
3551 : * This method is the same as the C function GDALGetRasterOffset().
3552 : *
3553 : * @param pbSuccess pointer to a boolean to use to indicate if the
3554 : * returned value is meaningful or not. May be NULL (default).
3555 : *
3556 : * @return the raster offset.
3557 : */
3558 :
3559 463 : double GDALRasterBand::GetOffset(int *pbSuccess)
3560 :
3561 : {
3562 463 : if (pbSuccess != nullptr)
3563 354 : *pbSuccess = FALSE;
3564 :
3565 463 : return 0.0;
3566 : }
3567 :
3568 : /************************************************************************/
3569 : /* GDALGetRasterOffset() */
3570 : /************************************************************************/
3571 :
3572 : /**
3573 : * \brief Fetch the raster value offset.
3574 : *
3575 : * @see GDALRasterBand::GetOffset()
3576 : */
3577 :
3578 385 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
3579 :
3580 : {
3581 385 : VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
3582 :
3583 385 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3584 385 : return poBand->GetOffset(pbSuccess);
3585 : }
3586 :
3587 : /************************************************************************/
3588 : /* SetOffset() */
3589 : /************************************************************************/
3590 :
3591 : /**
3592 : * \fn GDALRasterBand::SetOffset(double)
3593 : * \brief Set scaling offset.
3594 : *
3595 : * Very few formats implement this method. When not implemented it will
3596 : * issue a CPLE_NotSupported error and return CE_Failure.
3597 : *
3598 : * This method is the same as the C function GDALSetRasterOffset().
3599 : *
3600 : * @param dfNewOffset the new offset.
3601 : *
3602 : * @return CE_None or success or CE_Failure on failure.
3603 : */
3604 :
3605 : /**/
3606 : /**/
3607 :
3608 0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
3609 : {
3610 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3611 0 : ReportError(CE_Failure, CPLE_NotSupported,
3612 : "SetOffset() not supported on this raster band.");
3613 :
3614 0 : return CE_Failure;
3615 : }
3616 :
3617 : /************************************************************************/
3618 : /* GDALSetRasterOffset() */
3619 : /************************************************************************/
3620 :
3621 : /**
3622 : * \brief Set scaling offset.
3623 : *
3624 : * @see GDALRasterBand::SetOffset()
3625 : */
3626 :
3627 86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
3628 : double dfNewOffset)
3629 :
3630 : {
3631 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
3632 :
3633 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3634 86 : return poBand->SetOffset(dfNewOffset);
3635 : }
3636 :
3637 : /************************************************************************/
3638 : /* GetScale() */
3639 : /************************************************************************/
3640 :
3641 : /**
3642 : * \brief Fetch the raster value scale.
3643 : *
3644 : * This value (in combination with the GetOffset() value) can be used to
3645 : * transform raw pixel values into the units returned by GetUnitType().
3646 : * For example this might be used to store elevations in GUInt16 bands
3647 : * with a precision of 0.1, and starting from -100.
3648 : *
3649 : * Units value = (raw value * scale) + offset
3650 : *
3651 : * Note that applying scale and offset is of the responsibility of the user,
3652 : * and is not done by methods such as RasterIO() or ReadBlock().
3653 : *
3654 : * For file formats that don't know this intrinsically a value of one
3655 : * is returned.
3656 : *
3657 : * This method is the same as the C function GDALGetRasterScale().
3658 : *
3659 : * @param pbSuccess pointer to a boolean to use to indicate if the
3660 : * returned value is meaningful or not. May be NULL (default).
3661 : *
3662 : * @return the raster scale.
3663 : */
3664 :
3665 463 : double GDALRasterBand::GetScale(int *pbSuccess)
3666 :
3667 : {
3668 463 : if (pbSuccess != nullptr)
3669 354 : *pbSuccess = FALSE;
3670 :
3671 463 : return 1.0;
3672 : }
3673 :
3674 : /************************************************************************/
3675 : /* GDALGetRasterScale() */
3676 : /************************************************************************/
3677 :
3678 : /**
3679 : * \brief Fetch the raster value scale.
3680 : *
3681 : * @see GDALRasterBand::GetScale()
3682 : */
3683 :
3684 383 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
3685 :
3686 : {
3687 383 : VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
3688 :
3689 383 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3690 383 : return poBand->GetScale(pbSuccess);
3691 : }
3692 :
3693 : /************************************************************************/
3694 : /* SetScale() */
3695 : /************************************************************************/
3696 :
3697 : /**
3698 : * \fn GDALRasterBand::SetScale(double)
3699 : * \brief Set scaling ratio.
3700 : *
3701 : * Very few formats implement this method. When not implemented it will
3702 : * issue a CPLE_NotSupported error and return CE_Failure.
3703 : *
3704 : * This method is the same as the C function GDALSetRasterScale().
3705 : *
3706 : * @param dfNewScale the new scale.
3707 : *
3708 : * @return CE_None or success or CE_Failure on failure.
3709 : */
3710 :
3711 : /**/
3712 : /**/
3713 :
3714 0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
3715 :
3716 : {
3717 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3718 0 : ReportError(CE_Failure, CPLE_NotSupported,
3719 : "SetScale() not supported on this raster band.");
3720 :
3721 0 : return CE_Failure;
3722 : }
3723 :
3724 : /************************************************************************/
3725 : /* GDALSetRasterScale() */
3726 : /************************************************************************/
3727 :
3728 : /**
3729 : * \brief Set scaling ratio.
3730 : *
3731 : * @see GDALRasterBand::SetScale()
3732 : */
3733 :
3734 87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
3735 :
3736 : {
3737 87 : VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
3738 :
3739 87 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3740 87 : return poBand->SetScale(dfNewOffset);
3741 : }
3742 :
3743 : /************************************************************************/
3744 : /* GetUnitType() */
3745 : /************************************************************************/
3746 :
3747 : /**
3748 : * \brief Return raster unit type.
3749 : *
3750 : * Return a name for the units of this raster's values. For instance, it
3751 : * might be "m" for an elevation model in meters, or "ft" for feet. If no
3752 : * units are available, a value of "" will be returned. The returned string
3753 : * should not be modified, nor freed by the calling application.
3754 : *
3755 : * This method is the same as the C function GDALGetRasterUnitType().
3756 : *
3757 : * @return unit name string.
3758 : */
3759 :
3760 183 : const char *GDALRasterBand::GetUnitType()
3761 :
3762 : {
3763 183 : return "";
3764 : }
3765 :
3766 : /************************************************************************/
3767 : /* GDALGetRasterUnitType() */
3768 : /************************************************************************/
3769 :
3770 : /**
3771 : * \brief Return raster unit type.
3772 : *
3773 : * @see GDALRasterBand::GetUnitType()
3774 : */
3775 :
3776 1454 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
3777 :
3778 : {
3779 1454 : VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
3780 :
3781 1454 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3782 1454 : return poBand->GetUnitType();
3783 : }
3784 :
3785 : /************************************************************************/
3786 : /* SetUnitType() */
3787 : /************************************************************************/
3788 :
3789 : /**
3790 : * \fn GDALRasterBand::SetUnitType(const char*)
3791 : * \brief Set unit type.
3792 : *
3793 : * Set the unit type for a raster band. Values should be one of
3794 : * "" (the default indicating it is unknown), "m" indicating meters,
3795 : * or "ft" indicating feet, though other nonstandard values are allowed.
3796 : *
3797 : * This method is the same as the C function GDALSetRasterUnitType().
3798 : *
3799 : * @param pszNewValue the new unit type value.
3800 : *
3801 : * @return CE_None on success or CE_Failure if not successful, or
3802 : * unsupported.
3803 : */
3804 :
3805 : /**/
3806 : /**/
3807 :
3808 0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
3809 :
3810 : {
3811 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
3812 0 : ReportError(CE_Failure, CPLE_NotSupported,
3813 : "SetUnitType() not supported on this raster band.");
3814 0 : return CE_Failure;
3815 : }
3816 :
3817 : /************************************************************************/
3818 : /* GDALSetRasterUnitType() */
3819 : /************************************************************************/
3820 :
3821 : /**
3822 : * \brief Set unit type.
3823 : *
3824 : * @see GDALRasterBand::SetUnitType()
3825 : *
3826 : * @since GDAL 1.8.0
3827 : */
3828 :
3829 86 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
3830 : const char *pszNewValue)
3831 :
3832 : {
3833 86 : VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
3834 :
3835 86 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3836 86 : return poBand->SetUnitType(pszNewValue);
3837 : }
3838 :
3839 : /************************************************************************/
3840 : /* GetXSize() */
3841 : /************************************************************************/
3842 :
3843 : /**
3844 : * \brief Fetch XSize of raster.
3845 : *
3846 : * This method is the same as the C function GDALGetRasterBandXSize().
3847 : *
3848 : * @return the width in pixels of this band.
3849 : */
3850 :
3851 8389160 : int GDALRasterBand::GetXSize() const
3852 :
3853 : {
3854 8389160 : return nRasterXSize;
3855 : }
3856 :
3857 : /************************************************************************/
3858 : /* GDALGetRasterBandXSize() */
3859 : /************************************************************************/
3860 :
3861 : /**
3862 : * \brief Fetch XSize of raster.
3863 : *
3864 : * @see GDALRasterBand::GetXSize()
3865 : */
3866 :
3867 57674 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
3868 :
3869 : {
3870 57674 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
3871 :
3872 57674 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3873 57674 : return poBand->GetXSize();
3874 : }
3875 :
3876 : /************************************************************************/
3877 : /* GetYSize() */
3878 : /************************************************************************/
3879 :
3880 : /**
3881 : * \brief Fetch YSize of raster.
3882 : *
3883 : * This method is the same as the C function GDALGetRasterBandYSize().
3884 : *
3885 : * @return the height in pixels of this band.
3886 : */
3887 :
3888 4562300 : int GDALRasterBand::GetYSize() const
3889 :
3890 : {
3891 4562300 : return nRasterYSize;
3892 : }
3893 :
3894 : /************************************************************************/
3895 : /* GDALGetRasterBandYSize() */
3896 : /************************************************************************/
3897 :
3898 : /**
3899 : * \brief Fetch YSize of raster.
3900 : *
3901 : * @see GDALRasterBand::GetYSize()
3902 : */
3903 :
3904 56532 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
3905 :
3906 : {
3907 56532 : VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
3908 :
3909 56532 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3910 56533 : return poBand->GetYSize();
3911 : }
3912 :
3913 : /************************************************************************/
3914 : /* GetBand() */
3915 : /************************************************************************/
3916 :
3917 : /**
3918 : * \brief Fetch the band number.
3919 : *
3920 : * This method returns the band that this GDALRasterBand objects represents
3921 : * within its dataset. This method may return a value of 0 to indicate
3922 : * GDALRasterBand objects without an apparently relationship to a dataset,
3923 : * such as GDALRasterBands serving as overviews.
3924 : *
3925 : * This method is the same as the C function GDALGetBandNumber().
3926 : *
3927 : * @return band number (1+) or 0 if the band number isn't known.
3928 : */
3929 :
3930 151986 : int GDALRasterBand::GetBand() const
3931 :
3932 : {
3933 151986 : return nBand;
3934 : }
3935 :
3936 : /************************************************************************/
3937 : /* GDALGetBandNumber() */
3938 : /************************************************************************/
3939 :
3940 : /**
3941 : * \brief Fetch the band number.
3942 : *
3943 : * @see GDALRasterBand::GetBand()
3944 : */
3945 :
3946 208 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
3947 :
3948 : {
3949 208 : VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
3950 :
3951 208 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3952 208 : return poBand->GetBand();
3953 : }
3954 :
3955 : /************************************************************************/
3956 : /* GetDataset() */
3957 : /************************************************************************/
3958 :
3959 : /**
3960 : * \brief Fetch the owning dataset handle.
3961 : *
3962 : * Note that some GDALRasterBands are not considered to be a part of a dataset,
3963 : * such as overviews or other "freestanding" bands.
3964 : *
3965 : * This method is the same as the C function GDALGetBandDataset().
3966 : *
3967 : * @return the pointer to the GDALDataset to which this band belongs, or
3968 : * NULL if this cannot be determined.
3969 : */
3970 :
3971 5263560 : GDALDataset *GDALRasterBand::GetDataset() const
3972 :
3973 : {
3974 5263560 : return poDS;
3975 : }
3976 :
3977 : /************************************************************************/
3978 : /* GDALGetBandDataset() */
3979 : /************************************************************************/
3980 :
3981 : /**
3982 : * \brief Fetch the owning dataset handle.
3983 : *
3984 : * @see GDALRasterBand::GetDataset()
3985 : */
3986 :
3987 445 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
3988 :
3989 : {
3990 445 : VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
3991 :
3992 445 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
3993 445 : return GDALDataset::ToHandle(poBand->GetDataset());
3994 : }
3995 :
3996 : /************************************************************************/
3997 : /* ComputeFloat16NoDataValue() */
3998 : /************************************************************************/
3999 :
4000 2232 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
4001 : double dfNoDataValue,
4002 : int &bGotNoDataValue,
4003 : GFloat16 &fNoDataValue,
4004 : bool &bGotFloat16NoDataValue)
4005 : {
4006 2232 : if (eDataType == GDT_Float16 && bGotNoDataValue)
4007 : {
4008 0 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4009 0 : if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
4010 : {
4011 0 : fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
4012 0 : bGotFloat16NoDataValue = true;
4013 0 : bGotNoDataValue = false;
4014 : }
4015 : }
4016 2232 : }
4017 :
4018 : /************************************************************************/
4019 : /* ComputeFloatNoDataValue() */
4020 : /************************************************************************/
4021 :
4022 2232 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
4023 : double dfNoDataValue,
4024 : int &bGotNoDataValue,
4025 : float &fNoDataValue,
4026 : bool &bGotFloatNoDataValue)
4027 : {
4028 2232 : if (eDataType == GDT_Float32 && bGotNoDataValue)
4029 : {
4030 88 : dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
4031 88 : if (GDALIsValueInRange<float>(dfNoDataValue))
4032 : {
4033 88 : fNoDataValue = static_cast<float>(dfNoDataValue);
4034 88 : bGotFloatNoDataValue = true;
4035 88 : bGotNoDataValue = false;
4036 : }
4037 : }
4038 2232 : }
4039 :
4040 : /************************************************************************/
4041 : /* struct GDALNoDataValues */
4042 : /************************************************************************/
4043 :
4044 : /**
4045 : * \brief No-data-values for all types
4046 : *
4047 : * The functions below pass various no-data-values around. To avoid
4048 : * long argument lists, this struct collects the no-data-values for
4049 : * all types into a single, convenient place.
4050 : **/
4051 :
4052 : struct GDALNoDataValues
4053 : {
4054 : int bGotNoDataValue;
4055 : double dfNoDataValue;
4056 :
4057 : bool bGotInt64NoDataValue;
4058 : int64_t nInt64NoDataValue;
4059 :
4060 : bool bGotUInt64NoDataValue;
4061 : uint64_t nUInt64NoDataValue;
4062 :
4063 : bool bGotFloatNoDataValue;
4064 : float fNoDataValue;
4065 :
4066 : bool bGotFloat16NoDataValue;
4067 : GFloat16 hfNoDataValue;
4068 :
4069 2276 : GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
4070 2276 : : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
4071 : bGotInt64NoDataValue(false), nInt64NoDataValue(0),
4072 : bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
4073 : bGotFloatNoDataValue(false), fNoDataValue(0.0f),
4074 2276 : bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
4075 : {
4076 2276 : if (eDataType == GDT_Int64)
4077 : {
4078 28 : int nGot = false;
4079 28 : nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
4080 28 : bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
4081 28 : if (bGotInt64NoDataValue)
4082 : {
4083 3 : dfNoDataValue = static_cast<double>(nInt64NoDataValue);
4084 3 : bGotNoDataValue =
4085 3 : nInt64NoDataValue <=
4086 6 : std::numeric_limits<int64_t>::max() - 1024 &&
4087 3 : static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
4088 : }
4089 : else
4090 25 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4091 : }
4092 2248 : else if (eDataType == GDT_UInt64)
4093 : {
4094 16 : int nGot = false;
4095 16 : nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
4096 16 : bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
4097 16 : if (bGotUInt64NoDataValue)
4098 : {
4099 3 : dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
4100 3 : bGotNoDataValue =
4101 3 : nUInt64NoDataValue <=
4102 6 : std::numeric_limits<uint64_t>::max() - 2048 &&
4103 3 : static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
4104 : }
4105 : else
4106 13 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4107 : }
4108 : else
4109 : {
4110 2232 : dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
4111 2232 : bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
4112 :
4113 2232 : ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4114 2232 : fNoDataValue, bGotFloatNoDataValue);
4115 :
4116 2232 : ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
4117 2232 : hfNoDataValue, bGotFloat16NoDataValue);
4118 : }
4119 2276 : }
4120 : };
4121 :
4122 : /************************************************************************/
4123 : /* ARE_REAL_EQUAL() */
4124 : /************************************************************************/
4125 :
4126 0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
4127 : {
4128 : using std::abs;
4129 0 : return dfVal1 == dfVal2 || /* Should cover infinity */
4130 0 : abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
4131 0 : abs(dfVal1 + dfVal2) * ulp;
4132 : }
4133 :
4134 : /************************************************************************/
4135 : /* GetHistogram() */
4136 : /************************************************************************/
4137 :
4138 : /**
4139 : * \brief Compute raster histogram.
4140 : *
4141 : * Note that the bucket size is (dfMax-dfMin) / nBuckets.
4142 : *
4143 : * For example to compute a simple 256 entry histogram of eight bit data,
4144 : * the following would be suitable. The unusual bounds are to ensure that
4145 : * bucket boundaries don't fall right on integer values causing possible errors
4146 : * due to rounding after scaling.
4147 : \code{.cpp}
4148 : GUIntBig anHistogram[256];
4149 :
4150 : poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
4151 : GDALDummyProgress, nullptr );
4152 : \endcode
4153 : *
4154 : * Note that setting bApproxOK will generally result in a subsampling of the
4155 : * file, and will utilize overviews if available. It should generally
4156 : * produce a representative histogram for the data that is suitable for use
4157 : * in generating histogram based luts for instance. Generally bApproxOK is
4158 : * much faster than an exactly computed histogram.
4159 : *
4160 : * This method is the same as the C functions GDALGetRasterHistogram() and
4161 : * GDALGetRasterHistogramEx().
4162 : *
4163 : * @param dfMin the lower bound of the histogram.
4164 : * @param dfMax the upper bound of the histogram.
4165 : * @param nBuckets the number of buckets in panHistogram.
4166 : * @param panHistogram array into which the histogram totals are placed.
4167 : * @param bIncludeOutOfRange if TRUE values below the histogram range will
4168 : * mapped into panHistogram[0], and values above will be mapped into
4169 : * panHistogram[nBuckets-1] otherwise out of range values are discarded.
4170 : * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
4171 : * @param pfnProgress function to report progress to completion.
4172 : * @param pProgressData application data to pass to pfnProgress.
4173 : *
4174 : * @return CE_None on success, or CE_Failure if something goes wrong.
4175 : */
4176 :
4177 42 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
4178 : GUIntBig *panHistogram,
4179 : int bIncludeOutOfRange, int bApproxOK,
4180 : GDALProgressFunc pfnProgress,
4181 : void *pProgressData)
4182 :
4183 : {
4184 42 : CPLAssert(nullptr != panHistogram);
4185 :
4186 42 : if (pfnProgress == nullptr)
4187 29 : pfnProgress = GDALDummyProgress;
4188 :
4189 : /* -------------------------------------------------------------------- */
4190 : /* If we have overviews, use them for the histogram. */
4191 : /* -------------------------------------------------------------------- */
4192 42 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
4193 : {
4194 : // FIXME: should we use the most reduced overview here or use some
4195 : // minimum number of samples like GDALRasterBand::ComputeStatistics()
4196 : // does?
4197 0 : GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
4198 :
4199 0 : if (poBestOverview != this)
4200 : {
4201 0 : return poBestOverview->GetHistogram(
4202 : dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
4203 0 : bApproxOK, pfnProgress, pProgressData);
4204 : }
4205 : }
4206 :
4207 : /* -------------------------------------------------------------------- */
4208 : /* Read actual data and build histogram. */
4209 : /* -------------------------------------------------------------------- */
4210 42 : if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
4211 : {
4212 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4213 0 : return CE_Failure;
4214 : }
4215 :
4216 : // Written this way to deal with NaN
4217 42 : if (!(dfMax > dfMin))
4218 : {
4219 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4220 : "dfMax should be strictly greater than dfMin");
4221 5 : return CE_Failure;
4222 : }
4223 :
4224 : GDALRasterIOExtraArg sExtraArg;
4225 37 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
4226 :
4227 37 : const double dfScale = nBuckets / (dfMax - dfMin);
4228 37 : if (dfScale == 0 || !std::isfinite(dfScale))
4229 : {
4230 5 : ReportError(CE_Failure, CPLE_IllegalArg,
4231 : "dfMin and dfMax should be finite values such that "
4232 : "nBuckets / (dfMax - dfMin) is non-zero");
4233 5 : return CE_Failure;
4234 : }
4235 32 : memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
4236 :
4237 32 : GDALNoDataValues sNoDataValues(this, eDataType);
4238 32 : GDALRasterBand *poMaskBand = nullptr;
4239 32 : if (!sNoDataValues.bGotNoDataValue)
4240 : {
4241 31 : const int l_nMaskFlags = GetMaskFlags();
4242 33 : if (l_nMaskFlags != GMF_ALL_VALID &&
4243 2 : GetColorInterpretation() != GCI_AlphaBand)
4244 : {
4245 2 : poMaskBand = GetMaskBand();
4246 : }
4247 : }
4248 :
4249 32 : bool bSignedByte = false;
4250 32 : if (eDataType == GDT_Byte)
4251 : {
4252 23 : EnablePixelTypeSignedByteWarning(false);
4253 : const char *pszPixelType =
4254 23 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4255 23 : EnablePixelTypeSignedByteWarning(true);
4256 23 : bSignedByte =
4257 23 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4258 : }
4259 :
4260 32 : if (bApproxOK && HasArbitraryOverviews())
4261 : {
4262 : /* --------------------------------------------------------------------
4263 : */
4264 : /* Figure out how much the image should be reduced to get an */
4265 : /* approximate value. */
4266 : /* --------------------------------------------------------------------
4267 : */
4268 : const double dfReduction =
4269 0 : sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
4270 : GDALSTAT_APPROX_NUMSAMPLES);
4271 :
4272 0 : int nXReduced = nRasterXSize;
4273 0 : int nYReduced = nRasterYSize;
4274 0 : if (dfReduction > 1.0)
4275 : {
4276 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
4277 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
4278 :
4279 : // Catch the case of huge resizing ratios here
4280 0 : if (nXReduced == 0)
4281 0 : nXReduced = 1;
4282 0 : if (nYReduced == 0)
4283 0 : nYReduced = 1;
4284 : }
4285 :
4286 0 : void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
4287 : nXReduced, nYReduced);
4288 0 : if (!pData)
4289 0 : return CE_Failure;
4290 :
4291 : const CPLErr eErr =
4292 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
4293 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
4294 0 : if (eErr != CE_None)
4295 : {
4296 0 : CPLFree(pData);
4297 0 : return eErr;
4298 : }
4299 :
4300 0 : GByte *pabyMaskData = nullptr;
4301 0 : if (poMaskBand)
4302 : {
4303 : pabyMaskData =
4304 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
4305 0 : if (!pabyMaskData)
4306 : {
4307 0 : CPLFree(pData);
4308 0 : return CE_Failure;
4309 : }
4310 :
4311 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
4312 : pabyMaskData, nXReduced, nYReduced,
4313 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
4314 : {
4315 0 : CPLFree(pData);
4316 0 : CPLFree(pabyMaskData);
4317 0 : return CE_Failure;
4318 : }
4319 : }
4320 :
4321 : // This isn't the fastest way to do this, but is easier for now.
4322 0 : for (int iY = 0; iY < nYReduced; iY++)
4323 : {
4324 0 : for (int iX = 0; iX < nXReduced; iX++)
4325 : {
4326 0 : const int iOffset = iX + iY * nXReduced;
4327 0 : double dfValue = 0.0;
4328 :
4329 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4330 0 : continue;
4331 :
4332 0 : switch (eDataType)
4333 : {
4334 0 : case GDT_Byte:
4335 : {
4336 0 : if (bSignedByte)
4337 0 : dfValue =
4338 0 : static_cast<signed char *>(pData)[iOffset];
4339 : else
4340 0 : dfValue = static_cast<GByte *>(pData)[iOffset];
4341 0 : break;
4342 : }
4343 0 : case GDT_Int8:
4344 0 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4345 0 : break;
4346 0 : case GDT_UInt16:
4347 0 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4348 0 : break;
4349 0 : case GDT_Int16:
4350 0 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4351 0 : break;
4352 0 : case GDT_UInt32:
4353 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4354 0 : break;
4355 0 : case GDT_Int32:
4356 0 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4357 0 : break;
4358 0 : case GDT_UInt64:
4359 0 : dfValue = static_cast<double>(
4360 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4361 0 : break;
4362 0 : case GDT_Int64:
4363 0 : dfValue = static_cast<double>(
4364 0 : static_cast<GInt64 *>(pData)[iOffset]);
4365 0 : break;
4366 0 : case GDT_Float16:
4367 : {
4368 : using namespace std;
4369 0 : const GFloat16 hfValue =
4370 0 : static_cast<GFloat16 *>(pData)[iOffset];
4371 0 : if (isnan(hfValue) ||
4372 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4373 0 : ARE_REAL_EQUAL(hfValue,
4374 : sNoDataValues.hfNoDataValue)))
4375 0 : continue;
4376 0 : dfValue = hfValue;
4377 0 : break;
4378 : }
4379 0 : case GDT_Float32:
4380 : {
4381 0 : const float fValue =
4382 0 : static_cast<float *>(pData)[iOffset];
4383 0 : if (std::isnan(fValue) ||
4384 0 : (sNoDataValues.bGotFloatNoDataValue &&
4385 0 : ARE_REAL_EQUAL(fValue,
4386 : sNoDataValues.fNoDataValue)))
4387 0 : continue;
4388 0 : dfValue = double(fValue);
4389 0 : break;
4390 : }
4391 0 : case GDT_Float64:
4392 0 : dfValue = static_cast<double *>(pData)[iOffset];
4393 0 : if (std::isnan(dfValue))
4394 0 : continue;
4395 0 : break;
4396 0 : case GDT_CInt16:
4397 : {
4398 0 : const double dfReal =
4399 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4400 0 : const double dfImag =
4401 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4402 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4403 0 : continue;
4404 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4405 : }
4406 0 : break;
4407 0 : case GDT_CInt32:
4408 : {
4409 0 : const double dfReal =
4410 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4411 0 : const double dfImag =
4412 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4413 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4414 0 : continue;
4415 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4416 : }
4417 0 : break;
4418 0 : case GDT_CFloat16:
4419 : {
4420 : const double dfReal =
4421 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4422 : const double dfImag =
4423 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4424 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4425 0 : continue;
4426 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4427 0 : break;
4428 : }
4429 0 : case GDT_CFloat32:
4430 : {
4431 0 : const double dfReal =
4432 0 : double(static_cast<float *>(pData)[iOffset * 2]);
4433 0 : const double dfImag = double(
4434 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4435 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4436 0 : continue;
4437 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4438 0 : break;
4439 : }
4440 0 : case GDT_CFloat64:
4441 : {
4442 0 : const double dfReal =
4443 0 : static_cast<double *>(pData)[iOffset * 2];
4444 0 : const double dfImag =
4445 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4446 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4447 0 : continue;
4448 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4449 0 : break;
4450 : }
4451 0 : case GDT_Unknown:
4452 : case GDT_TypeCount:
4453 0 : CPLAssert(false);
4454 : }
4455 :
4456 0 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4457 0 : sNoDataValues.bGotNoDataValue &&
4458 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4459 0 : continue;
4460 :
4461 : // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
4462 : // finite, the result of the multiplication cannot be NaN
4463 0 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4464 :
4465 0 : if (dfIndex < 0)
4466 : {
4467 0 : if (bIncludeOutOfRange)
4468 0 : panHistogram[0]++;
4469 : }
4470 0 : else if (dfIndex >= nBuckets)
4471 : {
4472 0 : if (bIncludeOutOfRange)
4473 0 : ++panHistogram[nBuckets - 1];
4474 : }
4475 : else
4476 : {
4477 0 : ++panHistogram[static_cast<int>(dfIndex)];
4478 : }
4479 : }
4480 : }
4481 :
4482 0 : CPLFree(pData);
4483 0 : CPLFree(pabyMaskData);
4484 : }
4485 : else // No arbitrary overviews.
4486 : {
4487 32 : if (!InitBlockInfo())
4488 0 : return CE_Failure;
4489 :
4490 : /* --------------------------------------------------------------------
4491 : */
4492 : /* Figure out the ratio of blocks we will read to get an */
4493 : /* approximate value. */
4494 : /* --------------------------------------------------------------------
4495 : */
4496 :
4497 32 : int nSampleRate = 1;
4498 32 : if (bApproxOK)
4499 : {
4500 8 : nSampleRate = static_cast<int>(std::max(
4501 16 : 1.0,
4502 8 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
4503 : // We want to avoid probing only the first column of blocks for
4504 : // a square shaped raster, because it is not unlikely that it may
4505 : // be padding only (#6378).
4506 8 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
4507 1 : nSampleRate += 1;
4508 : }
4509 :
4510 32 : GByte *pabyMaskData = nullptr;
4511 32 : if (poMaskBand)
4512 : {
4513 : pabyMaskData = static_cast<GByte *>(
4514 2 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
4515 2 : if (!pabyMaskData)
4516 : {
4517 0 : return CE_Failure;
4518 : }
4519 : }
4520 :
4521 : /* --------------------------------------------------------------------
4522 : */
4523 : /* Read the blocks, and add to histogram. */
4524 : /* --------------------------------------------------------------------
4525 : */
4526 32 : for (GIntBig iSampleBlock = 0;
4527 154 : iSampleBlock <
4528 154 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
4529 122 : iSampleBlock += nSampleRate)
4530 : {
4531 122 : if (!pfnProgress(
4532 122 : static_cast<double>(iSampleBlock) /
4533 122 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
4534 : "Compute Histogram", pProgressData))
4535 : {
4536 0 : CPLFree(pabyMaskData);
4537 0 : return CE_Failure;
4538 : }
4539 :
4540 122 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
4541 122 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
4542 :
4543 122 : int nXCheck = 0, nYCheck = 0;
4544 122 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
4545 :
4546 124 : if (poMaskBand &&
4547 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
4548 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
4549 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
4550 2 : 0, nBlockXSize, nullptr) != CE_None)
4551 : {
4552 0 : CPLFree(pabyMaskData);
4553 0 : return CE_Failure;
4554 : }
4555 :
4556 122 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
4557 122 : if (poBlock == nullptr)
4558 : {
4559 0 : CPLFree(pabyMaskData);
4560 0 : return CE_Failure;
4561 : }
4562 :
4563 122 : void *pData = poBlock->GetDataRef();
4564 :
4565 : // this is a special case for a common situation.
4566 122 : if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
4567 86 : (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
4568 83 : nXCheck == nBlockXSize && nBuckets == 256)
4569 : {
4570 83 : const GPtrDiff_t nPixels =
4571 83 : static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
4572 83 : GByte *pabyData = static_cast<GByte *>(pData);
4573 :
4574 72137 : for (GPtrDiff_t i = 0; i < nPixels; i++)
4575 : {
4576 72054 : if (pabyMaskData && pabyMaskData[i] == 0)
4577 0 : continue;
4578 72054 : if (!(sNoDataValues.bGotNoDataValue &&
4579 512 : (pabyData[i] ==
4580 512 : static_cast<GByte>(sNoDataValues.dfNoDataValue))))
4581 : {
4582 71798 : panHistogram[pabyData[i]]++;
4583 : }
4584 : }
4585 :
4586 83 : poBlock->DropLock();
4587 83 : continue; // To next sample block.
4588 : }
4589 :
4590 : // This isn't the fastest way to do this, but is easier for now.
4591 257 : for (int iY = 0; iY < nYCheck; iY++)
4592 : {
4593 36389 : for (int iX = 0; iX < nXCheck; iX++)
4594 : {
4595 36171 : const GPtrDiff_t iOffset =
4596 36171 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
4597 :
4598 36171 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
4599 2 : continue;
4600 :
4601 36169 : double dfValue = 0.0;
4602 :
4603 36169 : switch (eDataType)
4604 : {
4605 19716 : case GDT_Byte:
4606 : {
4607 19716 : if (bSignedByte)
4608 0 : dfValue =
4609 0 : static_cast<signed char *>(pData)[iOffset];
4610 : else
4611 19716 : dfValue = static_cast<GByte *>(pData)[iOffset];
4612 19716 : break;
4613 : }
4614 1 : case GDT_Int8:
4615 1 : dfValue = static_cast<GInt8 *>(pData)[iOffset];
4616 1 : break;
4617 16384 : case GDT_UInt16:
4618 16384 : dfValue = static_cast<GUInt16 *>(pData)[iOffset];
4619 16384 : break;
4620 3 : case GDT_Int16:
4621 3 : dfValue = static_cast<GInt16 *>(pData)[iOffset];
4622 3 : break;
4623 0 : case GDT_UInt32:
4624 0 : dfValue = static_cast<GUInt32 *>(pData)[iOffset];
4625 0 : break;
4626 60 : case GDT_Int32:
4627 60 : dfValue = static_cast<GInt32 *>(pData)[iOffset];
4628 60 : break;
4629 0 : case GDT_UInt64:
4630 0 : dfValue = static_cast<double>(
4631 0 : static_cast<GUInt64 *>(pData)[iOffset]);
4632 0 : break;
4633 0 : case GDT_Int64:
4634 0 : dfValue = static_cast<double>(
4635 0 : static_cast<GInt64 *>(pData)[iOffset]);
4636 0 : break;
4637 0 : case GDT_Float16:
4638 : {
4639 : using namespace std;
4640 0 : const GFloat16 hfValue =
4641 0 : static_cast<GFloat16 *>(pData)[iOffset];
4642 0 : if (isnan(hfValue) ||
4643 0 : (sNoDataValues.bGotFloat16NoDataValue &&
4644 0 : ARE_REAL_EQUAL(hfValue,
4645 : sNoDataValues.hfNoDataValue)))
4646 0 : continue;
4647 0 : dfValue = hfValue;
4648 0 : break;
4649 : }
4650 3 : case GDT_Float32:
4651 : {
4652 3 : const float fValue =
4653 3 : static_cast<float *>(pData)[iOffset];
4654 6 : if (std::isnan(fValue) ||
4655 6 : (sNoDataValues.bGotFloatNoDataValue &&
4656 3 : ARE_REAL_EQUAL(fValue,
4657 : sNoDataValues.fNoDataValue)))
4658 0 : continue;
4659 3 : dfValue = double(fValue);
4660 3 : break;
4661 : }
4662 2 : case GDT_Float64:
4663 2 : dfValue = static_cast<double *>(pData)[iOffset];
4664 2 : if (std::isnan(dfValue))
4665 0 : continue;
4666 2 : break;
4667 0 : case GDT_CInt16:
4668 : {
4669 0 : double dfReal =
4670 0 : static_cast<GInt16 *>(pData)[iOffset * 2];
4671 0 : double dfImag =
4672 0 : static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
4673 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4674 0 : break;
4675 : }
4676 0 : case GDT_CInt32:
4677 : {
4678 0 : double dfReal =
4679 0 : static_cast<GInt32 *>(pData)[iOffset * 2];
4680 0 : double dfImag =
4681 0 : static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
4682 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4683 0 : break;
4684 : }
4685 0 : case GDT_CFloat16:
4686 : {
4687 : double dfReal =
4688 0 : static_cast<GFloat16 *>(pData)[iOffset * 2];
4689 : double dfImag =
4690 0 : static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
4691 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4692 0 : continue;
4693 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4694 0 : break;
4695 : }
4696 0 : case GDT_CFloat32:
4697 : {
4698 0 : double dfReal = double(
4699 0 : static_cast<float *>(pData)[iOffset * 2]);
4700 0 : double dfImag = double(
4701 0 : static_cast<float *>(pData)[iOffset * 2 + 1]);
4702 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4703 0 : continue;
4704 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4705 0 : break;
4706 : }
4707 0 : case GDT_CFloat64:
4708 : {
4709 0 : double dfReal =
4710 0 : static_cast<double *>(pData)[iOffset * 2];
4711 0 : double dfImag =
4712 0 : static_cast<double *>(pData)[iOffset * 2 + 1];
4713 0 : if (std::isnan(dfReal) || std::isnan(dfImag))
4714 0 : continue;
4715 0 : dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
4716 0 : break;
4717 : }
4718 0 : case GDT_Unknown:
4719 : case GDT_TypeCount:
4720 0 : CPLAssert(false);
4721 : CPLFree(pabyMaskData);
4722 : return CE_Failure;
4723 : }
4724 :
4725 36169 : if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
4726 72338 : sNoDataValues.bGotNoDataValue &&
4727 0 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
4728 0 : continue;
4729 :
4730 : // Given that dfValue and dfMin are not NaN, and dfScale > 0
4731 : // and finite, the result of the multiplication cannot be
4732 : // NaN
4733 36169 : const double dfIndex = floor((dfValue - dfMin) * dfScale);
4734 :
4735 36169 : if (dfIndex < 0)
4736 : {
4737 1 : if (bIncludeOutOfRange)
4738 1 : panHistogram[0]++;
4739 : }
4740 36168 : else if (dfIndex >= nBuckets)
4741 : {
4742 7 : if (bIncludeOutOfRange)
4743 4 : ++panHistogram[nBuckets - 1];
4744 : }
4745 : else
4746 : {
4747 36161 : ++panHistogram[static_cast<int>(dfIndex)];
4748 : }
4749 : }
4750 : }
4751 :
4752 39 : poBlock->DropLock();
4753 : }
4754 :
4755 32 : CPLFree(pabyMaskData);
4756 : }
4757 :
4758 32 : pfnProgress(1.0, "Compute Histogram", pProgressData);
4759 :
4760 32 : return CE_None;
4761 : }
4762 :
4763 : /************************************************************************/
4764 : /* GDALGetRasterHistogram() */
4765 : /************************************************************************/
4766 :
4767 : /**
4768 : * \brief Compute raster histogram.
4769 : *
4770 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4771 : * exceeding 2 billion.
4772 : *
4773 : * @see GDALRasterBand::GetHistogram()
4774 : * @see GDALGetRasterHistogramEx()
4775 : */
4776 :
4777 0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
4778 : double dfMax, int nBuckets,
4779 : int *panHistogram,
4780 : int bIncludeOutOfRange, int bApproxOK,
4781 : GDALProgressFunc pfnProgress,
4782 : void *pProgressData)
4783 :
4784 : {
4785 0 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
4786 0 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
4787 :
4788 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4789 :
4790 : GUIntBig *panHistogramTemp =
4791 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
4792 0 : if (panHistogramTemp == nullptr)
4793 : {
4794 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
4795 : "Out of memory in GDALGetRasterHistogram().");
4796 0 : return CE_Failure;
4797 : }
4798 :
4799 0 : CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
4800 : bIncludeOutOfRange, bApproxOK,
4801 0 : pfnProgress, pProgressData);
4802 :
4803 0 : if (eErr == CE_None)
4804 : {
4805 0 : for (int i = 0; i < nBuckets; i++)
4806 : {
4807 0 : if (panHistogramTemp[i] > INT_MAX)
4808 : {
4809 0 : CPLError(CE_Warning, CPLE_AppDefined,
4810 : "Count for bucket %d, which is " CPL_FRMT_GUIB
4811 : " exceeds maximum 32 bit value",
4812 0 : i, panHistogramTemp[i]);
4813 0 : panHistogram[i] = INT_MAX;
4814 : }
4815 : else
4816 : {
4817 0 : panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
4818 : }
4819 : }
4820 : }
4821 :
4822 0 : CPLFree(panHistogramTemp);
4823 :
4824 0 : return eErr;
4825 : }
4826 :
4827 : /************************************************************************/
4828 : /* GDALGetRasterHistogramEx() */
4829 : /************************************************************************/
4830 :
4831 : /**
4832 : * \brief Compute raster histogram.
4833 : *
4834 : * @see GDALRasterBand::GetHistogram()
4835 : *
4836 : * @since GDAL 2.0
4837 : */
4838 :
4839 26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
4840 : GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
4841 : GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
4842 : GDALProgressFunc pfnProgress, void *pProgressData)
4843 :
4844 : {
4845 26 : VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
4846 26 : VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
4847 :
4848 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
4849 :
4850 26 : return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4851 : bIncludeOutOfRange, bApproxOK, pfnProgress,
4852 26 : pProgressData);
4853 : }
4854 :
4855 : /************************************************************************/
4856 : /* GetDefaultHistogram() */
4857 : /************************************************************************/
4858 :
4859 : /**
4860 : * \brief Fetch default raster histogram.
4861 : *
4862 : * The default method in GDALRasterBand will compute a default histogram. This
4863 : * method is overridden by derived classes (such as GDALPamRasterBand,
4864 : * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
4865 : * stored histogram.
4866 : *
4867 : * This method is the same as the C functions GDALGetDefaultHistogram() and
4868 : * GDALGetDefaultHistogramEx().
4869 : *
4870 : * @param pdfMin pointer to double value that will contain the lower bound of
4871 : * the histogram.
4872 : * @param pdfMax pointer to double value that will contain the upper bound of
4873 : * the histogram.
4874 : * @param pnBuckets pointer to int value that will contain the number of buckets
4875 : * in *ppanHistogram.
4876 : * @param ppanHistogram pointer to array into which the histogram totals are
4877 : * placed. To be freed with VSIFree
4878 : * @param bForce TRUE to force the computation. If FALSE and no default
4879 : * histogram is available, the method will return CE_Warning
4880 : * @param pfnProgress function to report progress to completion.
4881 : * @param pProgressData application data to pass to pfnProgress.
4882 : *
4883 : * @return CE_None on success, CE_Failure if something goes wrong, or
4884 : * CE_Warning if no default histogram is available.
4885 : */
4886 :
4887 24 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
4888 : int *pnBuckets,
4889 : GUIntBig **ppanHistogram, int bForce,
4890 : GDALProgressFunc pfnProgress,
4891 : void *pProgressData)
4892 :
4893 : {
4894 24 : CPLAssert(nullptr != pnBuckets);
4895 24 : CPLAssert(nullptr != ppanHistogram);
4896 24 : CPLAssert(nullptr != pdfMin);
4897 24 : CPLAssert(nullptr != pdfMax);
4898 :
4899 24 : *pnBuckets = 0;
4900 24 : *ppanHistogram = nullptr;
4901 :
4902 24 : if (!bForce)
4903 5 : return CE_Warning;
4904 :
4905 19 : int nBuckets = 256;
4906 :
4907 19 : bool bSignedByte = false;
4908 19 : if (eDataType == GDT_Byte)
4909 : {
4910 17 : EnablePixelTypeSignedByteWarning(false);
4911 : const char *pszPixelType =
4912 17 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
4913 17 : EnablePixelTypeSignedByteWarning(true);
4914 17 : bSignedByte =
4915 17 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
4916 : }
4917 :
4918 19 : if (GetRasterDataType() == GDT_Byte && !bSignedByte)
4919 : {
4920 17 : *pdfMin = -0.5;
4921 17 : *pdfMax = 255.5;
4922 : }
4923 2 : else if (GetRasterDataType() == GDT_Int8)
4924 : {
4925 1 : *pdfMin = -128 - 0.5;
4926 1 : *pdfMax = 127 + 0.5;
4927 : }
4928 : else
4929 : {
4930 :
4931 : const CPLErr eErr =
4932 1 : GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
4933 1 : if (eErr != CE_None)
4934 0 : return eErr;
4935 1 : if (*pdfMin == *pdfMax)
4936 : {
4937 1 : nBuckets = 1;
4938 1 : *pdfMin -= 0.5;
4939 1 : *pdfMax += 0.5;
4940 : }
4941 : else
4942 : {
4943 0 : const double dfHalfBucket =
4944 0 : (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
4945 0 : *pdfMin -= dfHalfBucket;
4946 0 : *pdfMax += dfHalfBucket;
4947 : }
4948 : }
4949 :
4950 19 : *ppanHistogram =
4951 19 : static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
4952 19 : if (*ppanHistogram == nullptr)
4953 : {
4954 0 : ReportError(CE_Failure, CPLE_OutOfMemory,
4955 : "Out of memory in InitBlockInfo().");
4956 0 : return CE_Failure;
4957 : }
4958 :
4959 19 : *pnBuckets = nBuckets;
4960 38 : CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
4961 19 : TRUE, FALSE, pfnProgress, pProgressData);
4962 19 : if (eErr != CE_None)
4963 : {
4964 0 : *pnBuckets = 0;
4965 : }
4966 19 : return eErr;
4967 : }
4968 :
4969 : /************************************************************************/
4970 : /* GDALGetDefaultHistogram() */
4971 : /************************************************************************/
4972 :
4973 : /**
4974 : * \brief Fetch default raster histogram.
4975 : *
4976 : * Use GDALGetRasterHistogramEx() instead to get correct counts for values
4977 : * exceeding 2 billion.
4978 : *
4979 : * @see GDALRasterBand::GDALGetDefaultHistogram()
4980 : * @see GDALGetRasterHistogramEx()
4981 : */
4982 :
4983 0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
4984 : double *pdfMin, double *pdfMax,
4985 : int *pnBuckets, int **ppanHistogram,
4986 : int bForce,
4987 : GDALProgressFunc pfnProgress,
4988 : void *pProgressData)
4989 :
4990 : {
4991 0 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
4992 0 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
4993 0 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
4994 0 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
4995 0 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
4996 :
4997 0 : GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
4998 0 : GUIntBig *panHistogramTemp = nullptr;
4999 0 : CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
5000 : &panHistogramTemp, bForce,
5001 0 : pfnProgress, pProgressData);
5002 0 : if (eErr == CE_None)
5003 : {
5004 0 : const int nBuckets = *pnBuckets;
5005 0 : *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
5006 0 : if (*ppanHistogram == nullptr)
5007 : {
5008 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
5009 : "Out of memory in GDALGetDefaultHistogram().");
5010 0 : VSIFree(panHistogramTemp);
5011 0 : return CE_Failure;
5012 : }
5013 :
5014 0 : for (int i = 0; i < nBuckets; ++i)
5015 : {
5016 0 : if (panHistogramTemp[i] > INT_MAX)
5017 : {
5018 0 : CPLError(CE_Warning, CPLE_AppDefined,
5019 : "Count for bucket %d, which is " CPL_FRMT_GUIB
5020 : " exceeds maximum 32 bit value",
5021 0 : i, panHistogramTemp[i]);
5022 0 : (*ppanHistogram)[i] = INT_MAX;
5023 : }
5024 : else
5025 : {
5026 0 : (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
5027 : }
5028 : }
5029 :
5030 0 : CPLFree(panHistogramTemp);
5031 : }
5032 : else
5033 : {
5034 0 : *ppanHistogram = nullptr;
5035 : }
5036 :
5037 0 : return eErr;
5038 : }
5039 :
5040 : /************************************************************************/
5041 : /* GDALGetDefaultHistogramEx() */
5042 : /************************************************************************/
5043 :
5044 : /**
5045 : * \brief Fetch default raster histogram.
5046 : *
5047 : * @see GDALRasterBand::GetDefaultHistogram()
5048 : *
5049 : * @since GDAL 2.0
5050 : */
5051 :
5052 : CPLErr CPL_STDCALL
5053 30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
5054 : int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
5055 : GDALProgressFunc pfnProgress, void *pProgressData)
5056 :
5057 : {
5058 30 : VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
5059 30 : VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
5060 30 : VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
5061 30 : VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
5062 30 : VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
5063 :
5064 30 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5065 30 : return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
5066 30 : bForce, pfnProgress, pProgressData);
5067 : }
5068 :
5069 : /************************************************************************/
5070 : /* AdviseRead() */
5071 : /************************************************************************/
5072 :
5073 : /**
5074 : * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
5075 : * \brief Advise driver of upcoming read requests.
5076 : *
5077 : * Some GDAL drivers operate more efficiently if they know in advance what
5078 : * set of upcoming read requests will be made. The AdviseRead() method allows
5079 : * an application to notify the driver of the region of interest,
5080 : * and at what resolution the region will be read.
5081 : *
5082 : * Many drivers just ignore the AdviseRead() call, but it can dramatically
5083 : * accelerate access via some drivers.
5084 : *
5085 : * Depending on call paths, drivers might receive several calls to
5086 : * AdviseRead() with the same parameters.
5087 : *
5088 : * @param nXOff The pixel offset to the top left corner of the region
5089 : * of the band to be accessed. This would be zero to start from the left side.
5090 : *
5091 : * @param nYOff The line offset to the top left corner of the region
5092 : * of the band to be accessed. This would be zero to start from the top.
5093 : *
5094 : * @param nXSize The width of the region of the band to be accessed in pixels.
5095 : *
5096 : * @param nYSize The height of the region of the band to be accessed in lines.
5097 : *
5098 : * @param nBufXSize the width of the buffer image into which the desired region
5099 : * is to be read, or from which it is to be written.
5100 : *
5101 : * @param nBufYSize the height of the buffer image into which the desired
5102 : * region is to be read, or from which it is to be written.
5103 : *
5104 : * @param eBufType the type of the pixel values in the pData data buffer. The
5105 : * pixel values will automatically be translated to/from the GDALRasterBand
5106 : * data type as needed.
5107 : *
5108 : * @param papszOptions a list of name=value strings with special control
5109 : * options. Normally this is NULL.
5110 : *
5111 : * @return CE_Failure if the request is invalid and CE_None if it works or
5112 : * is ignored.
5113 : */
5114 :
5115 : /**/
5116 : /**/
5117 :
5118 113664 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
5119 : int /*nYSize*/, int /*nBufXSize*/,
5120 : int /*nBufYSize*/, GDALDataType /*eBufType*/,
5121 : char ** /*papszOptions*/)
5122 : {
5123 113664 : return CE_None;
5124 : }
5125 :
5126 : /************************************************************************/
5127 : /* GDALRasterAdviseRead() */
5128 : /************************************************************************/
5129 :
5130 : /**
5131 : * \brief Advise driver of upcoming read requests.
5132 : *
5133 : * @see GDALRasterBand::AdviseRead()
5134 : */
5135 :
5136 2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
5137 : int nYOff, int nXSize, int nYSize,
5138 : int nBufXSize, int nBufYSize,
5139 : GDALDataType eDT,
5140 : CSLConstList papszOptions)
5141 :
5142 : {
5143 2 : VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
5144 :
5145 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5146 2 : return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
5147 : nBufYSize, eDT,
5148 2 : const_cast<char **>(papszOptions));
5149 : }
5150 :
5151 : /************************************************************************/
5152 : /* GetStatistics() */
5153 : /************************************************************************/
5154 :
5155 : /**
5156 : * \brief Fetch image statistics.
5157 : *
5158 : * Returns the minimum, maximum, mean and standard deviation of all
5159 : * pixel values in this band. If approximate statistics are sufficient,
5160 : * the bApproxOK flag can be set to true in which case overviews, or a
5161 : * subset of image tiles may be used in computing the statistics.
5162 : *
5163 : * If bForce is FALSE results will only be returned if it can be done
5164 : * quickly (i.e. without scanning the image, typically by using pre-existing
5165 : * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
5166 : * returned efficiently, the method will return CE_Warning but no warning will
5167 : * be issued. This is a non-standard use of the CE_Warning return value
5168 : * to indicate "nothing done".
5169 : *
5170 : * If bForce is TRUE, and results are quickly available without scanning the
5171 : * image, they will be used. If bForce is TRUE and results are not quickly
5172 : * available, GetStatistics() forwards the computation to ComputeStatistics(),
5173 : * which will scan the image.
5174 : *
5175 : * To always force recomputation of statistics, use ComputeStatistics() instead
5176 : * of this method.
5177 : *
5178 : * Note that file formats using PAM (Persistent Auxiliary Metadata) services
5179 : * will generally cache statistics in the .pam file allowing fast fetch
5180 : * after the first request.
5181 : *
5182 : * This method is the same as the C function GDALGetRasterStatistics().
5183 : *
5184 : * @param bApproxOK If TRUE statistics may be computed based on overviews
5185 : * or a subset of all tiles.
5186 : *
5187 : * @param bForce If FALSE statistics will only be returned if it can
5188 : * be done without rescanning the image. If TRUE, statistics computation will
5189 : * be forced if pre-existing values are not quickly available.
5190 : *
5191 : * @param pdfMin Location into which to load image minimum (may be NULL).
5192 : *
5193 : * @param pdfMax Location into which to load image maximum (may be NULL).-
5194 : *
5195 : * @param pdfMean Location into which to load image mean (may be NULL).
5196 : *
5197 : * @param pdfStdDev Location into which to load image standard deviation
5198 : * (may be NULL).
5199 : *
5200 : * @return CE_None on success, CE_Warning if no values returned,
5201 : * CE_Failure if an error occurs.
5202 : */
5203 :
5204 628 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
5205 : double *pdfMax, double *pdfMean,
5206 : double *pdfStdDev)
5207 :
5208 : {
5209 : /* -------------------------------------------------------------------- */
5210 : /* Do we already have metadata items for the requested values? */
5211 : /* -------------------------------------------------------------------- */
5212 1256 : if ((pdfMin == nullptr ||
5213 628 : GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
5214 203 : (pdfMax == nullptr ||
5215 203 : GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
5216 1459 : (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
5217 203 : (pdfStdDev == nullptr ||
5218 203 : GetMetadataItem("STATISTICS_STDDEV") != nullptr))
5219 : {
5220 203 : if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
5221 : {
5222 196 : if (pdfMin != nullptr)
5223 196 : *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
5224 196 : if (pdfMax != nullptr)
5225 196 : *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
5226 196 : if (pdfMean != nullptr)
5227 196 : *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
5228 196 : if (pdfStdDev != nullptr)
5229 196 : *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
5230 :
5231 196 : return CE_None;
5232 : }
5233 : }
5234 :
5235 : /* -------------------------------------------------------------------- */
5236 : /* Does the driver already know the min/max? */
5237 : /* -------------------------------------------------------------------- */
5238 432 : if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
5239 : {
5240 1 : int bSuccessMin = FALSE;
5241 1 : int bSuccessMax = FALSE;
5242 :
5243 1 : const double dfMin = GetMinimum(&bSuccessMin);
5244 1 : const double dfMax = GetMaximum(&bSuccessMax);
5245 :
5246 1 : if (bSuccessMin && bSuccessMax)
5247 : {
5248 0 : if (pdfMin != nullptr)
5249 0 : *pdfMin = dfMin;
5250 0 : if (pdfMax != nullptr)
5251 0 : *pdfMax = dfMax;
5252 0 : return CE_None;
5253 : }
5254 : }
5255 :
5256 : /* -------------------------------------------------------------------- */
5257 : /* Either return without results, or force computation. */
5258 : /* -------------------------------------------------------------------- */
5259 432 : if (!bForce)
5260 176 : return CE_Warning;
5261 : else
5262 256 : return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
5263 256 : GDALDummyProgress, nullptr);
5264 : }
5265 :
5266 : /************************************************************************/
5267 : /* GDALGetRasterStatistics() */
5268 : /************************************************************************/
5269 :
5270 : /**
5271 : * \brief Fetch image statistics.
5272 : *
5273 : * @see GDALRasterBand::GetStatistics()
5274 : */
5275 :
5276 276 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
5277 : int bForce, double *pdfMin,
5278 : double *pdfMax, double *pdfMean,
5279 : double *pdfStdDev)
5280 :
5281 : {
5282 276 : VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
5283 :
5284 276 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
5285 276 : return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
5286 276 : pdfStdDev);
5287 : }
5288 :
5289 : /************************************************************************/
5290 : /* GDALUInt128 */
5291 : /************************************************************************/
5292 :
5293 : #ifdef HAVE_UINT128_T
5294 : class GDALUInt128
5295 : {
5296 : __uint128_t val;
5297 :
5298 645 : explicit GDALUInt128(__uint128_t valIn) : val(valIn)
5299 : {
5300 645 : }
5301 :
5302 : public:
5303 430 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5304 : {
5305 : // Evaluates to just a single mul on x86_64
5306 430 : return GDALUInt128(static_cast<__uint128_t>(first) * second);
5307 : }
5308 :
5309 215 : GDALUInt128 operator-(const GDALUInt128 &other) const
5310 : {
5311 215 : return GDALUInt128(val - other.val);
5312 : }
5313 :
5314 206 : operator double() const
5315 : {
5316 206 : return static_cast<double>(val);
5317 : }
5318 : };
5319 : #else
5320 :
5321 : #if defined(_MSC_VER) && defined(_M_X64)
5322 : #include <intrin.h>
5323 : #endif
5324 :
5325 : class GDALUInt128
5326 : {
5327 : GUIntBig low, high;
5328 :
5329 : GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
5330 : {
5331 : }
5332 :
5333 : public:
5334 : static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
5335 : {
5336 : #if defined(_MSC_VER) && defined(_M_X64)
5337 : GUIntBig highRes;
5338 : GUIntBig lowRes = _umul128(first, second, &highRes);
5339 : return GDALUInt128(lowRes, highRes);
5340 : #else
5341 : const GUInt32 firstLow = static_cast<GUInt32>(first);
5342 : const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
5343 : const GUInt32 secondLow = static_cast<GUInt32>(second);
5344 : const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
5345 : GUIntBig highRes = 0;
5346 : const GUIntBig firstLowSecondHigh =
5347 : static_cast<GUIntBig>(firstLow) * secondHigh;
5348 : const GUIntBig firstHighSecondLow =
5349 : static_cast<GUIntBig>(firstHigh) * secondLow;
5350 : const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
5351 : if (middleTerm < firstLowSecondHigh) // check for overflow
5352 : highRes += static_cast<GUIntBig>(1) << 32;
5353 : const GUIntBig firstLowSecondLow =
5354 : static_cast<GUIntBig>(firstLow) * secondLow;
5355 : GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
5356 : if (lowRes < firstLowSecondLow) // check for overflow
5357 : highRes++;
5358 : highRes +=
5359 : (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
5360 : return GDALUInt128(lowRes, highRes);
5361 : #endif
5362 : }
5363 :
5364 : GDALUInt128 operator-(const GDALUInt128 &other) const
5365 : {
5366 : GUIntBig highRes = high - other.high;
5367 : GUIntBig lowRes = low - other.low;
5368 : if (lowRes > low) // check for underflow
5369 : --highRes;
5370 : return GDALUInt128(lowRes, highRes);
5371 : }
5372 :
5373 : operator double() const
5374 : {
5375 : const double twoPow64 = 18446744073709551616.0;
5376 : return high * twoPow64 + low;
5377 : }
5378 : };
5379 : #endif
5380 :
5381 : /************************************************************************/
5382 : /* ComputeStatisticsInternal() */
5383 : /************************************************************************/
5384 :
5385 : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
5386 : // not needed.
5387 : #define static_cast_for_coverity_scan static_cast
5388 :
5389 : // The rationale for below optimizations is detailed in statistics.txt
5390 :
5391 : // Use with T = GByte or GUInt16 only !
5392 : template <class T, bool COMPUTE_OTHER_STATS>
5393 : struct ComputeStatisticsInternalGeneric
5394 : {
5395 208 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5396 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5397 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5398 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5399 : {
5400 : static_assert(std::is_same<T, GByte>::value ||
5401 : std::is_same<T, GUInt16>::value,
5402 : "bad type for T");
5403 208 : if (bHasNoData)
5404 : {
5405 : // General case
5406 386 : for (int iY = 0; iY < nYCheck; iY++)
5407 : {
5408 81751 : for (int iX = 0; iX < nXCheck; iX++)
5409 : {
5410 81468 : const GPtrDiff_t iOffset =
5411 81468 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5412 81468 : const GUInt32 nValue = pData[iOffset];
5413 81468 : if (nValue == nNoDataValue)
5414 175 : continue;
5415 81293 : if (nValue < nMin)
5416 26 : nMin = nValue;
5417 81293 : if (nValue > nMax)
5418 57 : nMax = nValue;
5419 : if constexpr (COMPUTE_OTHER_STATS)
5420 : {
5421 79657 : nValidCount++;
5422 79657 : nSum += nValue;
5423 79657 : nSumSquare +=
5424 79657 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5425 79657 : nValue;
5426 : }
5427 : }
5428 : }
5429 : if constexpr (COMPUTE_OTHER_STATS)
5430 : {
5431 20 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5432 : }
5433 : }
5434 115 : else if (nMin == std::numeric_limits<T>::lowest() &&
5435 10 : nMax == std::numeric_limits<T>::max())
5436 : {
5437 : if constexpr (COMPUTE_OTHER_STATS)
5438 : {
5439 : // Optimization when there is no nodata and we know we have already
5440 : // reached the min and max
5441 208 : for (int iY = 0; iY < nYCheck; iY++)
5442 : {
5443 : int iX;
5444 1002 : for (iX = 0; iX + 3 < nXCheck; iX += 4)
5445 : {
5446 800 : const GPtrDiff_t iOffset =
5447 800 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5448 800 : const GUIntBig nValue = pData[iOffset];
5449 800 : const GUIntBig nValue2 = pData[iOffset + 1];
5450 800 : const GUIntBig nValue3 = pData[iOffset + 2];
5451 800 : const GUIntBig nValue4 = pData[iOffset + 3];
5452 800 : nSum += nValue;
5453 800 : nSumSquare += nValue * nValue;
5454 800 : nSum += nValue2;
5455 800 : nSumSquare += nValue2 * nValue2;
5456 800 : nSum += nValue3;
5457 800 : nSumSquare += nValue3 * nValue3;
5458 800 : nSum += nValue4;
5459 800 : nSumSquare += nValue4 * nValue4;
5460 : }
5461 207 : for (; iX < nXCheck; ++iX)
5462 : {
5463 5 : const GPtrDiff_t iOffset =
5464 5 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5465 5 : const GUIntBig nValue = pData[iOffset];
5466 5 : nSum += nValue;
5467 5 : nSumSquare += nValue * nValue;
5468 : }
5469 : }
5470 6 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5471 6 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5472 : }
5473 : }
5474 : else
5475 : {
5476 3434 : for (int iY = 0; iY < nYCheck; iY++)
5477 : {
5478 : int iX;
5479 643297 : for (iX = 0; iX + 1 < nXCheck; iX += 2)
5480 : {
5481 639962 : const GPtrDiff_t iOffset =
5482 639962 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5483 639962 : const GUInt32 nValue = pData[iOffset];
5484 639962 : const GUInt32 nValue2 = pData[iOffset + 1];
5485 639962 : if (nValue < nValue2)
5486 : {
5487 2320 : if (nValue < nMin)
5488 48 : nMin = nValue;
5489 2320 : if (nValue2 > nMax)
5490 116 : nMax = nValue2;
5491 : }
5492 : else
5493 : {
5494 637642 : if (nValue2 < nMin)
5495 66 : nMin = nValue2;
5496 637642 : if (nValue > nMax)
5497 215 : nMax = nValue;
5498 : }
5499 : if constexpr (COMPUTE_OTHER_STATS)
5500 : {
5501 632911 : nSum += nValue;
5502 632911 : nSumSquare +=
5503 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5504 632911 : nValue;
5505 632911 : nSum += nValue2;
5506 632911 : nSumSquare +=
5507 632911 : static_cast_for_coverity_scan<GUIntBig>(nValue2) *
5508 632911 : nValue2;
5509 : }
5510 : }
5511 3335 : if (iX < nXCheck)
5512 : {
5513 18 : const GPtrDiff_t iOffset =
5514 18 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5515 18 : const GUInt32 nValue = pData[iOffset];
5516 18 : if (nValue < nMin)
5517 13 : nMin = nValue;
5518 18 : if (nValue > nMax)
5519 14 : nMax = nValue;
5520 : if (COMPUTE_OTHER_STATS)
5521 : {
5522 9 : nSum += nValue;
5523 9 : nSumSquare +=
5524 9 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5525 9 : nValue;
5526 : }
5527 : }
5528 : }
5529 : if constexpr (COMPUTE_OTHER_STATS)
5530 : {
5531 44 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5532 44 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5533 : }
5534 : }
5535 208 : }
5536 : };
5537 :
5538 : // Specialization for Byte that is mostly 32 bit friendly as it avoids
5539 : // using 64bit accumulators in internal loops. This also slightly helps in
5540 : // 64bit mode.
5541 : template <bool COMPUTE_OTHER_STATS>
5542 : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
5543 : {
5544 13715 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
5545 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5546 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5547 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5548 : {
5549 13715 : int nOuterLoops = nXCheck / 65536;
5550 13715 : if (nXCheck % 65536)
5551 13717 : nOuterLoops++;
5552 :
5553 13715 : if (bHasNoData)
5554 : {
5555 : // General case
5556 23475 : for (int iY = 0; iY < nYCheck; iY++)
5557 : {
5558 12901 : int iX = 0;
5559 25802 : for (int k = 0; k < nOuterLoops; k++)
5560 : {
5561 12901 : int iMax = iX + 65536;
5562 12901 : if (iMax > nXCheck)
5563 12901 : iMax = nXCheck;
5564 12901 : GUInt32 nSum32bit = 0;
5565 12901 : GUInt32 nSumSquare32bit = 0;
5566 12901 : GUInt32 nValidCount32bit = 0;
5567 12901 : GUInt32 nSampleCount32bit = 0;
5568 20707175 : for (; iX < iMax; iX++)
5569 : {
5570 20694323 : const GPtrDiff_t iOffset =
5571 20694323 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5572 20694323 : const GUInt32 nValue = pData[iOffset];
5573 :
5574 20694323 : nSampleCount32bit++;
5575 20694323 : if (nValue == nNoDataValue)
5576 20353454 : continue;
5577 340814 : if (nValue < nMin)
5578 357 : nMin = nValue;
5579 340814 : if (nValue > nMax)
5580 813 : nMax = nValue;
5581 : if constexpr (COMPUTE_OTHER_STATS)
5582 : {
5583 17069 : nValidCount32bit++;
5584 17069 : nSum32bit += nValue;
5585 17069 : nSumSquare32bit += nValue * nValue;
5586 : }
5587 : }
5588 : if constexpr (COMPUTE_OTHER_STATS)
5589 : {
5590 652 : nSampleCount += nSampleCount32bit;
5591 652 : nValidCount += nValidCount32bit;
5592 652 : nSum += nSum32bit;
5593 652 : nSumSquare += nSumSquare32bit;
5594 : }
5595 : }
5596 : }
5597 : }
5598 3141 : else if (nMin == 0 && nMax == 255)
5599 : {
5600 : if constexpr (COMPUTE_OTHER_STATS)
5601 : {
5602 : // Optimization when there is no nodata and we know we have already
5603 : // reached the min and max
5604 2644 : for (int iY = 0; iY < nYCheck; iY++)
5605 : {
5606 2617 : int iX = 0;
5607 5234 : for (int k = 0; k < nOuterLoops; k++)
5608 : {
5609 2617 : int iMax = iX + 65536;
5610 2617 : if (iMax > nXCheck)
5611 2617 : iMax = nXCheck;
5612 2617 : GUInt32 nSum32bit = 0;
5613 2617 : GUInt32 nSumSquare32bit = 0;
5614 176297 : for (; iX + 3 < iMax; iX += 4)
5615 : {
5616 173680 : const GPtrDiff_t iOffset =
5617 173680 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5618 173680 : const GUInt32 nValue = pData[iOffset];
5619 173680 : const GUInt32 nValue2 = pData[iOffset + 1];
5620 173680 : const GUInt32 nValue3 = pData[iOffset + 2];
5621 173680 : const GUInt32 nValue4 = pData[iOffset + 3];
5622 173680 : nSum32bit += nValue;
5623 173680 : nSumSquare32bit += nValue * nValue;
5624 173680 : nSum32bit += nValue2;
5625 173680 : nSumSquare32bit += nValue2 * nValue2;
5626 173680 : nSum32bit += nValue3;
5627 173680 : nSumSquare32bit += nValue3 * nValue3;
5628 173680 : nSum32bit += nValue4;
5629 173680 : nSumSquare32bit += nValue4 * nValue4;
5630 : }
5631 2617 : nSum += nSum32bit;
5632 2617 : nSumSquare += nSumSquare32bit;
5633 : }
5634 2620 : for (; iX < nXCheck; ++iX)
5635 : {
5636 3 : const GPtrDiff_t iOffset =
5637 3 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5638 3 : const GUIntBig nValue = pData[iOffset];
5639 3 : nSum += nValue;
5640 3 : nSumSquare += nValue * nValue;
5641 : }
5642 : }
5643 27 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5644 27 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5645 27 : }
5646 : }
5647 : else
5648 : {
5649 7921 : for (int iY = 0; iY < nYCheck; iY++)
5650 : {
5651 4807 : int iX = 0;
5652 9614 : for (int k = 0; k < nOuterLoops; k++)
5653 : {
5654 4807 : int iMax = iX + 65536;
5655 4807 : if (iMax > nXCheck)
5656 4807 : iMax = nXCheck;
5657 4807 : GUInt32 nSum32bit = 0;
5658 4807 : GUInt32 nSumSquare32bit = 0;
5659 159552 : for (; iX + 1 < iMax; iX += 2)
5660 : {
5661 154745 : const GPtrDiff_t iOffset =
5662 154745 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5663 154745 : const GUInt32 nValue = pData[iOffset];
5664 154745 : const GUInt32 nValue2 = pData[iOffset + 1];
5665 154745 : if (nValue < nValue2)
5666 : {
5667 8100 : if (nValue < nMin)
5668 232 : nMin = nValue;
5669 8100 : if (nValue2 > nMax)
5670 219 : nMax = nValue2;
5671 : }
5672 : else
5673 : {
5674 146645 : if (nValue2 < nMin)
5675 362 : nMin = nValue2;
5676 146645 : if (nValue > nMax)
5677 832 : nMax = nValue;
5678 : }
5679 : if constexpr (COMPUTE_OTHER_STATS)
5680 : {
5681 132608 : nSum32bit += nValue;
5682 132608 : nSumSquare32bit += nValue * nValue;
5683 132608 : nSum32bit += nValue2;
5684 132608 : nSumSquare32bit += nValue2 * nValue2;
5685 : }
5686 : }
5687 : if constexpr (COMPUTE_OTHER_STATS)
5688 : {
5689 1630 : nSum += nSum32bit;
5690 1630 : nSumSquare += nSumSquare32bit;
5691 : }
5692 : }
5693 4807 : if (iX < nXCheck)
5694 : {
5695 1515 : const GPtrDiff_t iOffset =
5696 1515 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
5697 1515 : const GUInt32 nValue = pData[iOffset];
5698 1515 : if (nValue < nMin)
5699 108 : nMin = nValue;
5700 1515 : if (nValue > nMax)
5701 95 : nMax = nValue;
5702 : if constexpr (COMPUTE_OTHER_STATS)
5703 : {
5704 313 : nSum += nValue;
5705 313 : nSumSquare +=
5706 313 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
5707 313 : nValue;
5708 : }
5709 : }
5710 : }
5711 : if constexpr (COMPUTE_OTHER_STATS)
5712 : {
5713 927 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5714 927 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
5715 : }
5716 : }
5717 13715 : }
5718 : };
5719 :
5720 : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
5721 : {
5722 : static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
5723 : bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
5724 : GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
5725 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5726 : {
5727 : ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
5728 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
5729 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
5730 : }
5731 : };
5732 :
5733 : #if (defined(__x86_64__) || defined(_M_X64)) && \
5734 : (defined(__GNUC__) || defined(_MSC_VER))
5735 :
5736 : #include "gdal_avx2_emulation.hpp"
5737 :
5738 : #define ZERO256 GDALmm256_setzero_si256()
5739 :
5740 : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
5741 : static void
5742 21318 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
5743 : // assumed to be aligned on 256 bits
5744 : const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
5745 : GUIntBig &nSum, GUIntBig &nSumSquare,
5746 : GUIntBig &nSampleCount, GUIntBig &nValidCount)
5747 : {
5748 : // 32-byte alignment may not be enforced by linker, so do it at hand
5749 : GByte
5750 : aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
5751 21318 : GByte *paby32ByteAligned =
5752 : aby32ByteUnaligned +
5753 21318 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5754 21318 : GByte *pabyMin = paby32ByteAligned;
5755 21318 : GByte *pabyMax = paby32ByteAligned + 32;
5756 21318 : GUInt32 *panSum =
5757 : COMPUTE_OTHER_STATS
5758 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
5759 : : nullptr;
5760 21318 : GUInt32 *panSumSquare =
5761 : COMPUTE_OTHER_STATS
5762 : ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
5763 : : nullptr;
5764 :
5765 21318 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5766 :
5767 21318 : GPtrDiff_t i = 0;
5768 : // Make sure that sumSquare can fit on uint32
5769 : // * 8 since we can hold 8 sums per vector register
5770 21318 : const int nMaxIterationsPerInnerLoop =
5771 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5772 21318 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5773 21318 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5774 21318 : nOuterLoops++;
5775 :
5776 : GDALm256i ymm_min =
5777 21318 : GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
5778 21318 : GDALm256i ymm_max = ymm_min;
5779 21318 : [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
5780 :
5781 42636 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5782 : {
5783 21318 : const auto iMax =
5784 21318 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5785 :
5786 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5787 21318 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5788 : [[maybe_unused]] GDALm256i ymm_sumsquare =
5789 21318 : ZERO256; // holds 8 uint32 sums
5790 714085 : for (; i + 31 < iMax; i += 32)
5791 : {
5792 692767 : const GDALm256i ymm = GDALmm256_load_si256(
5793 692767 : reinterpret_cast<const GDALm256i *>(pData + i));
5794 : if (COMPUTE_MIN)
5795 : {
5796 234930 : ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
5797 : }
5798 : if (COMPUTE_MAX)
5799 : {
5800 603612 : ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
5801 : }
5802 :
5803 : if constexpr (COMPUTE_OTHER_STATS)
5804 : {
5805 : // Extract even-8bit values
5806 : const GDALm256i ymm_even =
5807 493495 : GDALmm256_and_si256(ymm, ymm_mask_8bits);
5808 : // Compute square of those 16 values as 32 bit result
5809 : // and add adjacent pairs
5810 : const GDALm256i ymm_even_square =
5811 493495 : GDALmm256_madd_epi16(ymm_even, ymm_even);
5812 : // Add to the sumsquare accumulator
5813 : ymm_sumsquare =
5814 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
5815 :
5816 : // Extract odd-8bit values
5817 493495 : const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
5818 : const GDALm256i ymm_odd_square =
5819 493495 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
5820 : ymm_sumsquare =
5821 493495 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
5822 :
5823 : // Now compute the sums
5824 493495 : ymm_sum = GDALmm256_add_epi32(ymm_sum,
5825 : GDALmm256_sad_epu8(ymm, ZERO256));
5826 : }
5827 : }
5828 :
5829 : if constexpr (COMPUTE_OTHER_STATS)
5830 : {
5831 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
5832 : ymm_sum);
5833 10649 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
5834 : ymm_sumsquare);
5835 :
5836 10649 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
5837 10649 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
5838 10649 : panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
5839 10649 : panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
5840 : panSumSquare[7];
5841 : }
5842 : }
5843 :
5844 : if constexpr (COMPUTE_MIN)
5845 : {
5846 8444 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
5847 : }
5848 : if constexpr (COMPUTE_MAX)
5849 : {
5850 17328 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
5851 : }
5852 : if constexpr (COMPUTE_MIN || COMPUTE_MAX)
5853 : {
5854 589083 : for (int j = 0; j < 32; j++)
5855 : {
5856 : if constexpr (COMPUTE_MIN)
5857 : {
5858 270208 : if (pabyMin[j] < nMin)
5859 1231 : nMin = pabyMin[j];
5860 : }
5861 : if constexpr (COMPUTE_MAX)
5862 : {
5863 554496 : if (pabyMax[j] > nMax)
5864 1788 : nMax = pabyMax[j];
5865 : }
5866 : }
5867 : }
5868 :
5869 234312 : for (; i < nBlockPixels; i++)
5870 : {
5871 212994 : const GUInt32 nValue = pData[i];
5872 : if constexpr (COMPUTE_MIN)
5873 : {
5874 88318 : if (nValue < nMin)
5875 1 : nMin = nValue;
5876 : }
5877 : if constexpr (COMPUTE_MAX)
5878 : {
5879 210219 : if (nValue > nMax)
5880 1149 : nMax = nValue;
5881 : }
5882 : if constexpr (COMPUTE_OTHER_STATS)
5883 : {
5884 77195 : nSum += nValue;
5885 77195 : nSumSquare +=
5886 77195 : static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
5887 : }
5888 : }
5889 :
5890 : if constexpr (COMPUTE_OTHER_STATS)
5891 : {
5892 10649 : nSampleCount += static_cast<GUIntBig>(nBlockPixels);
5893 10649 : nValidCount += static_cast<GUIntBig>(nBlockPixels);
5894 : }
5895 21318 : }
5896 :
5897 : // SSE2/AVX2 optimization for GByte case
5898 : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
5899 : // penaly in using the emulation, because, given the mm256 intrinsics used here,
5900 : // there are strictly equivalent to 2 parallel SSE2 streams.
5901 : template <bool COMPUTE_OTHER_STATS>
5902 : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
5903 : {
5904 30170 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
5905 : // assumed to be aligned on 256 bits
5906 : const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
5907 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
5908 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
5909 : GUIntBig &nValidCount)
5910 : {
5911 30170 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
5912 30170 : if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
5913 11574 : nMin <= nMax)
5914 : {
5915 : // 32-byte alignment may not be enforced by linker, so do it at hand
5916 : GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
5917 1459 : GByte *paby32ByteAligned =
5918 : aby32ByteUnaligned +
5919 1459 : (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
5920 1459 : GByte *pabyMin = paby32ByteAligned;
5921 1459 : GByte *pabyMax = paby32ByteAligned + 32;
5922 1459 : GUInt32 *panSum =
5923 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
5924 1459 : GUInt32 *panSumSquare =
5925 : reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
5926 :
5927 1459 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
5928 :
5929 1459 : GPtrDiff_t i = 0;
5930 : // Make sure that sumSquare can fit on uint32
5931 : // * 8 since we can hold 8 sums per vector register
5932 1459 : const int nMaxIterationsPerInnerLoop =
5933 : 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
5934 1459 : auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
5935 1459 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
5936 1459 : nOuterLoops++;
5937 :
5938 : const GDALm256i ymm_nodata =
5939 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
5940 : // any non noData value in [min,max] would do.
5941 : const GDALm256i ymm_neutral =
5942 1459 : GDALmm256_set1_epi8(static_cast<GByte>(nMin));
5943 1459 : GDALm256i ymm_min = ymm_neutral;
5944 1459 : GDALm256i ymm_max = ymm_neutral;
5945 : [[maybe_unused]] const auto ymm_mask_8bits =
5946 1459 : GDALmm256_set1_epi16(0xFF);
5947 :
5948 1459 : const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
5949 1459 : const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
5950 1459 : const bool bComputeMinMax =
5951 1459 : nMin > nMinThreshold || nMax < nMaxThreshold;
5952 :
5953 2918 : for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
5954 : {
5955 1459 : const auto iMax =
5956 1459 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
5957 :
5958 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5959 1459 : [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
5960 : // holds 8 uint32 sums
5961 1459 : [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
5962 : // holds 4 uint32 sums in [0], [2], [4] and [6]
5963 1459 : [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
5964 1459 : const auto iInit = i;
5965 14435 : for (; i + 31 < iMax; i += 32)
5966 : {
5967 12976 : const GDALm256i ymm = GDALmm256_load_si256(
5968 12976 : reinterpret_cast<const GDALm256i *>(pData + i));
5969 :
5970 : // Check which values are nodata
5971 : const GDALm256i ymm_eq_nodata =
5972 12976 : GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
5973 : if constexpr (COMPUTE_OTHER_STATS)
5974 : {
5975 : // Count how many values are nodata (due to cmpeq
5976 : // putting 255 when condition is met, this will actually
5977 : // be 255 times the number of nodata value, spread in 4
5978 : // 64 bits words). We can use add_epi32 as the counter
5979 : // will not overflow uint32
5980 4634 : ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
5981 : ymm_count_nodata_mul_255,
5982 : GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
5983 : }
5984 : // Replace all nodata values by zero for the purpose of sum
5985 : // and sumquare.
5986 : const GDALm256i ymm_nodata_by_zero =
5987 12976 : GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
5988 12976 : if (bComputeMinMax)
5989 : {
5990 : // Replace all nodata values by a neutral value for the
5991 : // purpose of min and max.
5992 : const GDALm256i ymm_nodata_by_neutral =
5993 8591 : GDALmm256_or_si256(
5994 : GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
5995 : ymm_nodata_by_zero);
5996 :
5997 : ymm_min =
5998 8591 : GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
5999 : ymm_max =
6000 8591 : GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
6001 : }
6002 :
6003 : if constexpr (COMPUTE_OTHER_STATS)
6004 : {
6005 : // Extract even-8bit values
6006 4634 : const GDALm256i ymm_even = GDALmm256_and_si256(
6007 : ymm_nodata_by_zero, ymm_mask_8bits);
6008 : // Compute square of those 16 values as 32 bit result
6009 : // and add adjacent pairs
6010 : const GDALm256i ymm_even_square =
6011 4634 : GDALmm256_madd_epi16(ymm_even, ymm_even);
6012 : // Add to the sumsquare accumulator
6013 : ymm_sumsquare =
6014 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
6015 :
6016 : // Extract odd-8bit values
6017 : const GDALm256i ymm_odd =
6018 4634 : GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
6019 : const GDALm256i ymm_odd_square =
6020 4634 : GDALmm256_madd_epi16(ymm_odd, ymm_odd);
6021 : ymm_sumsquare =
6022 4634 : GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
6023 :
6024 : // Now compute the sums
6025 4634 : ymm_sum = GDALmm256_add_epi32(
6026 : ymm_sum,
6027 : GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
6028 : }
6029 : }
6030 :
6031 : if constexpr (COMPUTE_OTHER_STATS)
6032 : {
6033 153 : GUInt32 *panCoutNoDataMul255 = panSum;
6034 153 : GDALmm256_store_si256(
6035 : reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
6036 : ymm_count_nodata_mul_255);
6037 :
6038 153 : nSampleCount += (i - iInit);
6039 :
6040 153 : nValidCount +=
6041 153 : (i - iInit) -
6042 153 : (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
6043 153 : panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
6044 : 255;
6045 :
6046 153 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
6047 : ymm_sum);
6048 153 : GDALmm256_store_si256(
6049 : reinterpret_cast<GDALm256i *>(panSumSquare),
6050 : ymm_sumsquare);
6051 153 : nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
6052 153 : nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
6053 153 : panSumSquare[1] + panSumSquare[2] +
6054 153 : panSumSquare[3] + panSumSquare[4] +
6055 153 : panSumSquare[5] + panSumSquare[6] +
6056 : panSumSquare[7];
6057 : }
6058 : }
6059 :
6060 1459 : if (bComputeMinMax)
6061 : {
6062 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
6063 : ymm_min);
6064 1428 : GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
6065 : ymm_max);
6066 47124 : for (int j = 0; j < 32; j++)
6067 : {
6068 45696 : if (pabyMin[j] < nMin)
6069 40 : nMin = pabyMin[j];
6070 45696 : if (pabyMax[j] > nMax)
6071 159 : nMax = pabyMax[j];
6072 : }
6073 : }
6074 :
6075 : if constexpr (COMPUTE_OTHER_STATS)
6076 : {
6077 153 : nSampleCount += nBlockPixels - i;
6078 : }
6079 33905 : for (; i < nBlockPixels; i++)
6080 : {
6081 32446 : const GUInt32 nValue = pData[i];
6082 32446 : if (nValue == nNoDataValue)
6083 24923 : continue;
6084 7523 : if (nValue < nMin)
6085 1 : nMin = nValue;
6086 7523 : if (nValue > nMax)
6087 13 : nMax = nValue;
6088 : if constexpr (COMPUTE_OTHER_STATS)
6089 : {
6090 3590 : nValidCount++;
6091 3590 : nSum += nValue;
6092 3590 : nSumSquare +=
6093 3590 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6094 3590 : nValue;
6095 : }
6096 1459 : }
6097 : }
6098 28711 : else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
6099 : {
6100 14962 : if (nMin > 0)
6101 : {
6102 2088 : if (nMax < 255)
6103 : {
6104 : ComputeStatisticsByteNoNodata<true, true,
6105 1565 : COMPUTE_OTHER_STATS>(
6106 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6107 : nSampleCount, nValidCount);
6108 : }
6109 : else
6110 : {
6111 : ComputeStatisticsByteNoNodata<true, false,
6112 523 : COMPUTE_OTHER_STATS>(
6113 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6114 : nSampleCount, nValidCount);
6115 : }
6116 : }
6117 : else
6118 : {
6119 12874 : if (nMax < 255)
6120 : {
6121 : ComputeStatisticsByteNoNodata<false, true,
6122 9407 : COMPUTE_OTHER_STATS>(
6123 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6124 : nSampleCount, nValidCount);
6125 : }
6126 : else
6127 : {
6128 : ComputeStatisticsByteNoNodata<false, false,
6129 3467 : COMPUTE_OTHER_STATS>(
6130 : nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
6131 : nSampleCount, nValidCount);
6132 : }
6133 : }
6134 : }
6135 12475 : else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
6136 33 : (nBlockXSize % 32) == 0)
6137 : {
6138 6389 : for (int iY = 0; iY < nYCheck; iY++)
6139 : {
6140 6356 : ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
6141 6356 : nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
6142 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6143 33 : }
6144 : }
6145 : else
6146 : {
6147 13716 : ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
6148 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6149 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6150 : }
6151 30171 : }
6152 : };
6153 :
6154 : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
6155 400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
6156 : GUIntBig i)
6157 : {
6158 400 : nSumSquare += 32768 * (2 * nSumThis - i * 32768);
6159 400 : }
6160 :
6161 : // AVX2/SSE2 optimization for GUInt16 case
6162 : template <bool COMPUTE_OTHER_STATS>
6163 : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
6164 : {
6165 1882 : static void f(int nXCheck, int nBlockXSize, int nYCheck,
6166 : // assumed to be aligned on 128 bits
6167 : const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
6168 : GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
6169 : GUIntBig &nSumSquare, GUIntBig &nSampleCount,
6170 : GUIntBig &nValidCount)
6171 : {
6172 1882 : const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
6173 1882 : if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
6174 : {
6175 1674 : CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
6176 :
6177 1674 : GPtrDiff_t i = 0;
6178 : // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
6179 : // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
6180 : // Furthermore the shift is also needed to use madd_epi16
6181 1674 : const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
6182 1674 : GDALm256i ymm_min = GDALmm256_load_si256(
6183 1674 : reinterpret_cast<const GDALm256i *>(pData + i));
6184 1674 : ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
6185 1674 : GDALm256i ymm_max = ymm_min;
6186 : [[maybe_unused]] GDALm256i ymm_sumsquare =
6187 1674 : ZERO256; // holds 4 uint64 sums
6188 :
6189 : // Make sure that sum can fit on uint32
6190 : // * 8 since we can hold 8 sums per vector register
6191 1674 : const int nMaxIterationsPerInnerLoop =
6192 : 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
6193 1674 : GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
6194 1674 : if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
6195 1674 : nOuterLoops++;
6196 :
6197 1674 : const bool bComputeMinMax = nMin > 0 || nMax < 65535;
6198 : [[maybe_unused]] const auto ymm_mask_16bits =
6199 1674 : GDALmm256_set1_epi32(0xFFFF);
6200 : [[maybe_unused]] const auto ymm_mask_32bits =
6201 1674 : GDALmm256_set1_epi64x(0xFFFFFFFF);
6202 :
6203 1674 : GUIntBig nSumThis = 0;
6204 3372 : for (int k = 0; k < nOuterLoops; k++)
6205 : {
6206 1698 : const auto iMax =
6207 1698 : std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
6208 :
6209 : [[maybe_unused]] GDALm256i ymm_sum =
6210 1698 : ZERO256; // holds 8 uint32 sums
6211 964126 : for (; i + 15 < iMax; i += 16)
6212 : {
6213 962428 : const GDALm256i ymm = GDALmm256_load_si256(
6214 962428 : reinterpret_cast<const GDALm256i *>(pData + i));
6215 : const GDALm256i ymm_shifted =
6216 962428 : GDALmm256_add_epi16(ymm, ymm_m32768);
6217 962428 : if (bComputeMinMax)
6218 : {
6219 953409 : ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
6220 953409 : ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
6221 : }
6222 :
6223 : if constexpr (COMPUTE_OTHER_STATS)
6224 : {
6225 : // Note: the int32 range can overflow for (0-32768)^2 +
6226 : // (0-32768)^2 = 0x80000000, but as we know the result
6227 : // is positive, this is OK as we interpret is a uint32.
6228 : const GDALm256i ymm_square =
6229 95410 : GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
6230 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6231 : ymm_sumsquare,
6232 : GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
6233 95410 : ymm_sumsquare = GDALmm256_add_epi64(
6234 : ymm_sumsquare,
6235 : GDALmm256_srli_epi64(ymm_square, 32));
6236 :
6237 : // Now compute the sums
6238 95410 : ymm_sum = GDALmm256_add_epi32(
6239 : ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
6240 95410 : ymm_sum = GDALmm256_add_epi32(
6241 : ymm_sum, GDALmm256_srli_epi32(ymm, 16));
6242 : }
6243 : }
6244 :
6245 : if constexpr (COMPUTE_OTHER_STATS)
6246 : {
6247 : GUInt32 anSum[8];
6248 400 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
6249 : ymm_sum);
6250 400 : nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
6251 400 : anSum[2] + anSum[3] + anSum[4] + anSum[5] +
6252 400 : anSum[6] + anSum[7];
6253 : }
6254 : }
6255 :
6256 1674 : if (bComputeMinMax)
6257 : {
6258 : GUInt16 anMin[16];
6259 : GUInt16 anMax[16];
6260 :
6261 : // Unshift the result
6262 1633 : ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
6263 1633 : ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
6264 1633 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
6265 : ymm_min);
6266 1633 : GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
6267 : ymm_max);
6268 27761 : for (int j = 0; j < 16; j++)
6269 : {
6270 26128 : if (anMin[j] < nMin)
6271 342 : nMin = anMin[j];
6272 26128 : if (anMax[j] > nMax)
6273 482 : nMax = anMax[j];
6274 : }
6275 : }
6276 :
6277 : if constexpr (COMPUTE_OTHER_STATS)
6278 : {
6279 : GUIntBig anSumSquare[4];
6280 400 : GDALmm256_storeu_si256(
6281 : reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
6282 400 : nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
6283 : anSumSquare[3];
6284 :
6285 : // Unshift the sum of squares
6286 400 : UnshiftSumSquare(nSumSquare, nSumThis,
6287 : static_cast<GUIntBig>(i));
6288 :
6289 400 : nSum += nSumThis;
6290 :
6291 722 : for (; i < nBlockPixels; i++)
6292 : {
6293 322 : const GUInt32 nValue = pData[i];
6294 322 : if (nValue < nMin)
6295 1 : nMin = nValue;
6296 322 : if (nValue > nMax)
6297 1 : nMax = nValue;
6298 322 : nSum += nValue;
6299 322 : nSumSquare +=
6300 322 : static_cast_for_coverity_scan<GUIntBig>(nValue) *
6301 322 : nValue;
6302 : }
6303 :
6304 400 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6305 400 : nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6306 1674 : }
6307 : }
6308 : else
6309 : {
6310 208 : ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
6311 : nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
6312 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6313 : }
6314 1882 : }
6315 : };
6316 :
6317 : #endif
6318 : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
6319 : // defined(_MSC_VER))
6320 :
6321 : /************************************************************************/
6322 : /* GetPixelValue() */
6323 : /************************************************************************/
6324 :
6325 23806300 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
6326 : const void *pData, GPtrDiff_t iOffset,
6327 : const GDALNoDataValues &sNoDataValues,
6328 : bool &bValid)
6329 : {
6330 23806300 : bValid = true;
6331 23806300 : double dfValue = 0;
6332 23806300 : switch (eDataType)
6333 : {
6334 1400770 : case GDT_Byte:
6335 : {
6336 1400770 : if (bSignedByte)
6337 192 : dfValue = static_cast<const signed char *>(pData)[iOffset];
6338 : else
6339 1400580 : dfValue = static_cast<const GByte *>(pData)[iOffset];
6340 1400770 : break;
6341 : }
6342 10409 : case GDT_Int8:
6343 10409 : dfValue = static_cast<const GInt8 *>(pData)[iOffset];
6344 10409 : break;
6345 200608 : case GDT_UInt16:
6346 200608 : dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
6347 200608 : break;
6348 60193 : case GDT_Int16:
6349 60193 : dfValue = static_cast<const GInt16 *>(pData)[iOffset];
6350 60193 : break;
6351 27600 : case GDT_UInt32:
6352 27600 : dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
6353 27600 : break;
6354 456810 : case GDT_Int32:
6355 456810 : dfValue = static_cast<const GInt32 *>(pData)[iOffset];
6356 456810 : break;
6357 2604 : case GDT_UInt64:
6358 2604 : dfValue = static_cast<double>(
6359 2604 : static_cast<const std::uint64_t *>(pData)[iOffset]);
6360 2604 : break;
6361 7404 : case GDT_Int64:
6362 7404 : dfValue = static_cast<double>(
6363 7404 : static_cast<const std::int64_t *>(pData)[iOffset]);
6364 7404 : break;
6365 0 : case GDT_Float16:
6366 : {
6367 : using namespace std;
6368 0 : const GFloat16 hfValue =
6369 0 : static_cast<const GFloat16 *>(pData)[iOffset];
6370 0 : if (isnan(hfValue) ||
6371 0 : (sNoDataValues.bGotFloat16NoDataValue &&
6372 0 : ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
6373 : {
6374 0 : bValid = false;
6375 0 : return 0.0;
6376 : }
6377 0 : dfValue = hfValue;
6378 0 : return dfValue;
6379 : }
6380 17933900 : case GDT_Float32:
6381 : {
6382 17933900 : const float fValue = static_cast<const float *>(pData)[iOffset];
6383 35841000 : if (std::isnan(fValue) ||
6384 31043800 : (sNoDataValues.bGotFloatNoDataValue &&
6385 13136700 : ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
6386 : {
6387 26881 : bValid = false;
6388 26881 : return 0.0;
6389 : }
6390 17907100 : dfValue = double(fValue);
6391 17907100 : return dfValue;
6392 : }
6393 3688930 : case GDT_Float64:
6394 3688930 : dfValue = static_cast<const double *>(pData)[iOffset];
6395 3688930 : if (std::isnan(dfValue))
6396 : {
6397 52 : bValid = false;
6398 52 : return 0.0;
6399 : }
6400 3688880 : break;
6401 2692 : case GDT_CInt16:
6402 2692 : dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
6403 2692 : break;
6404 2692 : case GDT_CInt32:
6405 2692 : dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
6406 2692 : break;
6407 0 : case GDT_CFloat16:
6408 0 : dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
6409 0 : if (std::isnan(dfValue))
6410 : {
6411 0 : bValid = false;
6412 0 : return 0.0;
6413 : }
6414 0 : break;
6415 5812 : case GDT_CFloat32:
6416 5812 : dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
6417 5812 : if (std::isnan(dfValue))
6418 : {
6419 0 : bValid = false;
6420 0 : return 0.0;
6421 : }
6422 5812 : break;
6423 5892 : case GDT_CFloat64:
6424 5892 : dfValue = static_cast<const double *>(pData)[iOffset * 2];
6425 5892 : if (std::isnan(dfValue))
6426 : {
6427 0 : bValid = false;
6428 0 : return 0.0;
6429 : }
6430 5892 : break;
6431 0 : case GDT_Unknown:
6432 : case GDT_TypeCount:
6433 0 : CPLAssert(false);
6434 : break;
6435 : }
6436 :
6437 9613360 : if (sNoDataValues.bGotNoDataValue &&
6438 3740990 : ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
6439 : {
6440 3346220 : bValid = false;
6441 3346220 : return 0.0;
6442 : }
6443 2526140 : return dfValue;
6444 : }
6445 :
6446 : /************************************************************************/
6447 : /* SetValidPercent() */
6448 : /************************************************************************/
6449 :
6450 : //! @cond Doxygen_Suppress
6451 : /**
6452 : * \brief Set percentage of valid (not nodata) pixels.
6453 : *
6454 : * Stores the percentage of valid pixels in the metadata item
6455 : * STATISTICS_VALID_PERCENT
6456 : *
6457 : * @param nSampleCount Number of sampled pixels.
6458 : *
6459 : * @param nValidCount Number of valid pixels.
6460 : */
6461 :
6462 495 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
6463 : GUIntBig nValidCount)
6464 : {
6465 495 : if (nValidCount == 0)
6466 : {
6467 12 : SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
6468 : }
6469 483 : else if (nValidCount == nSampleCount)
6470 : {
6471 436 : SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
6472 : }
6473 : else /* nValidCount < nSampleCount */
6474 : {
6475 47 : char szValue[128] = {0};
6476 :
6477 : /* percentage is only an indicator: limit precision */
6478 47 : CPLsnprintf(szValue, sizeof(szValue), "%.4g",
6479 47 : 100. * static_cast<double>(nValidCount) / nSampleCount);
6480 :
6481 47 : if (EQUAL(szValue, "100"))
6482 : {
6483 : /* don't set 100 percent valid
6484 : * because some of the sampled pixels were nodata */
6485 0 : SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
6486 : }
6487 : else
6488 : {
6489 47 : SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
6490 : }
6491 : }
6492 495 : }
6493 :
6494 : //! @endcond
6495 :
6496 : /************************************************************************/
6497 : /* ComputeStatistics() */
6498 : /************************************************************************/
6499 :
6500 : /**
6501 : * \brief Compute image statistics.
6502 : *
6503 : * Returns the minimum, maximum, mean and standard deviation of all
6504 : * pixel values in this band. If approximate statistics are sufficient,
6505 : * the bApproxOK flag can be set to true in which case overviews, or a
6506 : * subset of image tiles may be used in computing the statistics.
6507 : *
6508 : * Once computed, the statistics will generally be "set" back on the
6509 : * raster band using SetStatistics().
6510 : *
6511 : * Cached statistics can be cleared with GDALDataset::ClearStatistics().
6512 : *
6513 : * This method is the same as the C function GDALComputeRasterStatistics().
6514 : *
6515 : * @param bApproxOK If TRUE statistics may be computed based on overviews
6516 : * or a subset of all tiles.
6517 : *
6518 : * @param pdfMin Location into which to load image minimum (may be NULL).
6519 : *
6520 : * @param pdfMax Location into which to load image maximum (may be NULL).-
6521 : *
6522 : * @param pdfMean Location into which to load image mean (may be NULL).
6523 : *
6524 : * @param pdfStdDev Location into which to load image standard deviation
6525 : * (may be NULL).
6526 : *
6527 : * @param pfnProgress a function to call to report progress, or NULL.
6528 : *
6529 : * @param pProgressData application data to pass to the progress function.
6530 : *
6531 : * @return CE_None on success, or CE_Failure if an error occurs or processing
6532 : * is terminated by the user.
6533 : */
6534 :
6535 473 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
6536 : double *pdfMax, double *pdfMean,
6537 : double *pdfStdDev,
6538 : GDALProgressFunc pfnProgress,
6539 : void *pProgressData)
6540 :
6541 : {
6542 473 : if (pfnProgress == nullptr)
6543 170 : pfnProgress = GDALDummyProgress;
6544 :
6545 : /* -------------------------------------------------------------------- */
6546 : /* If we have overview bands, use them for statistics. */
6547 : /* -------------------------------------------------------------------- */
6548 473 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
6549 : {
6550 : GDALRasterBand *poBand =
6551 3 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
6552 :
6553 3 : if (poBand != this)
6554 : {
6555 6 : CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
6556 : pdfMean, pdfStdDev,
6557 3 : pfnProgress, pProgressData);
6558 3 : if (eErr == CE_None)
6559 : {
6560 3 : if (pdfMin && pdfMax && pdfMean && pdfStdDev)
6561 : {
6562 3 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6563 3 : SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
6564 : }
6565 :
6566 : /* transfer metadata from overview band to this */
6567 : const char *pszPercentValid =
6568 3 : poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
6569 :
6570 3 : if (pszPercentValid != nullptr)
6571 : {
6572 3 : SetMetadataItem("STATISTICS_VALID_PERCENT",
6573 3 : pszPercentValid);
6574 : }
6575 : }
6576 3 : return eErr;
6577 : }
6578 : }
6579 :
6580 470 : if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
6581 : {
6582 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6583 0 : return CE_Failure;
6584 : }
6585 :
6586 : /* -------------------------------------------------------------------- */
6587 : /* Read actual data and compute statistics. */
6588 : /* -------------------------------------------------------------------- */
6589 : // Using Welford algorithm:
6590 : // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
6591 : // to compute standard deviation in a more numerically robust way than
6592 : // the difference of the sum of square values with the square of the sum.
6593 : // dfMean and dfM2 are updated at each sample.
6594 : // dfM2 is the sum of square of differences to the current mean.
6595 470 : double dfMin = std::numeric_limits<double>::infinity();
6596 470 : double dfMax = -std::numeric_limits<double>::infinity();
6597 470 : double dfMean = 0.0;
6598 470 : double dfM2 = 0.0;
6599 :
6600 : GDALRasterIOExtraArg sExtraArg;
6601 470 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
6602 :
6603 470 : GDALNoDataValues sNoDataValues(this, eDataType);
6604 470 : GDALRasterBand *poMaskBand = nullptr;
6605 470 : if (!sNoDataValues.bGotNoDataValue)
6606 : {
6607 443 : const int l_nMaskFlags = GetMaskFlags();
6608 487 : if (l_nMaskFlags != GMF_ALL_VALID &&
6609 44 : GetColorInterpretation() != GCI_AlphaBand)
6610 : {
6611 44 : poMaskBand = GetMaskBand();
6612 : }
6613 : }
6614 :
6615 470 : bool bSignedByte = false;
6616 470 : if (eDataType == GDT_Byte)
6617 : {
6618 203 : EnablePixelTypeSignedByteWarning(false);
6619 : const char *pszPixelType =
6620 203 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
6621 203 : EnablePixelTypeSignedByteWarning(true);
6622 203 : bSignedByte =
6623 203 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
6624 : }
6625 :
6626 470 : GUIntBig nSampleCount = 0;
6627 470 : GUIntBig nValidCount = 0;
6628 :
6629 470 : if (bApproxOK && HasArbitraryOverviews())
6630 : {
6631 : /* --------------------------------------------------------------------
6632 : */
6633 : /* Figure out how much the image should be reduced to get an */
6634 : /* approximate value. */
6635 : /* --------------------------------------------------------------------
6636 : */
6637 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
6638 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
6639 :
6640 0 : int nXReduced = nRasterXSize;
6641 0 : int nYReduced = nRasterYSize;
6642 0 : if (dfReduction > 1.0)
6643 : {
6644 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
6645 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
6646 :
6647 : // Catch the case of huge resizing ratios here
6648 0 : if (nXReduced == 0)
6649 0 : nXReduced = 1;
6650 0 : if (nYReduced == 0)
6651 0 : nYReduced = 1;
6652 : }
6653 :
6654 0 : void *pData = CPLMalloc(cpl::fits_on<int>(
6655 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
6656 :
6657 : const CPLErr eErr =
6658 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
6659 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
6660 0 : if (eErr != CE_None)
6661 : {
6662 0 : CPLFree(pData);
6663 0 : return eErr;
6664 : }
6665 :
6666 0 : GByte *pabyMaskData = nullptr;
6667 0 : if (poMaskBand)
6668 : {
6669 : pabyMaskData =
6670 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
6671 0 : if (!pabyMaskData)
6672 : {
6673 0 : CPLFree(pData);
6674 0 : return CE_Failure;
6675 : }
6676 :
6677 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
6678 : pabyMaskData, nXReduced, nYReduced,
6679 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
6680 : {
6681 0 : CPLFree(pData);
6682 0 : CPLFree(pabyMaskData);
6683 0 : return CE_Failure;
6684 : }
6685 : }
6686 :
6687 : /* this isn't the fastest way to do this, but is easier for now */
6688 0 : for (int iY = 0; iY < nYReduced; iY++)
6689 : {
6690 0 : for (int iX = 0; iX < nXReduced; iX++)
6691 : {
6692 0 : const int iOffset = iX + iY * nXReduced;
6693 0 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6694 0 : continue;
6695 :
6696 0 : bool bValid = true;
6697 0 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
6698 0 : iOffset, sNoDataValues, bValid);
6699 0 : if (!bValid)
6700 0 : continue;
6701 :
6702 0 : dfMin = std::min(dfMin, dfValue);
6703 0 : dfMax = std::max(dfMax, dfValue);
6704 :
6705 0 : nValidCount++;
6706 0 : if (dfMin == dfMax)
6707 : {
6708 0 : if (nValidCount == 1)
6709 0 : dfMean = dfMin;
6710 : }
6711 : else
6712 : {
6713 0 : const double dfDelta = dfValue - dfMean;
6714 0 : dfMean += dfDelta / nValidCount;
6715 0 : dfM2 += dfDelta * (dfValue - dfMean);
6716 : }
6717 : }
6718 : }
6719 :
6720 0 : nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
6721 :
6722 0 : CPLFree(pData);
6723 0 : CPLFree(pabyMaskData);
6724 : }
6725 :
6726 : else // No arbitrary overviews.
6727 : {
6728 470 : if (!InitBlockInfo())
6729 0 : return CE_Failure;
6730 :
6731 : /* --------------------------------------------------------------------
6732 : */
6733 : /* Figure out the ratio of blocks we will read to get an */
6734 : /* approximate value. */
6735 : /* --------------------------------------------------------------------
6736 : */
6737 470 : int nSampleRate = 1;
6738 470 : if (bApproxOK)
6739 : {
6740 43 : nSampleRate = static_cast<int>(std::max(
6741 86 : 1.0,
6742 43 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
6743 : // We want to avoid probing only the first column of blocks for
6744 : // a square shaped raster, because it is not unlikely that it may
6745 : // be padding only (#6378)
6746 43 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
6747 1 : nSampleRate += 1;
6748 : }
6749 470 : if (nSampleRate == 1)
6750 436 : bApproxOK = false;
6751 :
6752 : // Particular case for GDT_Byte that only use integral types for all
6753 : // intermediate computations. Only possible if the number of pixels
6754 : // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
6755 : // can fit on a uint64. Should be 99.99999% of cases.
6756 : // For GUInt16, this limits to raster of 4 giga pixels
6757 470 : if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
6758 186 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6759 186 : nSampleRate <
6760 186 : GUINTBIG_MAX / (255U * 255U) /
6761 186 : (static_cast<GUInt64>(nBlockXSize) *
6762 186 : static_cast<GUInt64>(nBlockYSize))) ||
6763 284 : (eDataType == GDT_UInt16 &&
6764 29 : static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
6765 29 : nSampleRate <
6766 29 : GUINTBIG_MAX / (65535U * 65535U) /
6767 29 : (static_cast<GUInt64>(nBlockXSize) *
6768 29 : static_cast<GUInt64>(nBlockYSize))))
6769 : {
6770 215 : const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
6771 215 : GUInt32 nMin = nMaxValueType;
6772 215 : GUInt32 nMax = 0;
6773 215 : GUIntBig nSum = 0;
6774 215 : GUIntBig nSumSquare = 0;
6775 : // If no valid nodata, map to invalid value (256 for Byte)
6776 215 : const GUInt32 nNoDataValue =
6777 238 : (sNoDataValues.bGotNoDataValue &&
6778 23 : sNoDataValues.dfNoDataValue >= 0 &&
6779 23 : sNoDataValues.dfNoDataValue <= nMaxValueType &&
6780 23 : fabs(sNoDataValues.dfNoDataValue -
6781 23 : static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
6782 : 1e-10)) < 1e-10)
6783 238 : ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
6784 : : nMaxValueType + 1;
6785 :
6786 215 : for (GIntBig iSampleBlock = 0;
6787 12760 : iSampleBlock <
6788 12760 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6789 12545 : iSampleBlock += nSampleRate)
6790 : {
6791 12545 : const int iYBlock =
6792 12545 : static_cast<int>(iSampleBlock / nBlocksPerRow);
6793 12545 : const int iXBlock =
6794 12545 : static_cast<int>(iSampleBlock % nBlocksPerRow);
6795 :
6796 : GDALRasterBlock *const poBlock =
6797 12545 : GetLockedBlockRef(iXBlock, iYBlock);
6798 12546 : if (poBlock == nullptr)
6799 0 : return CE_Failure;
6800 :
6801 12546 : void *const pData = poBlock->GetDataRef();
6802 :
6803 12545 : int nXCheck = 0, nYCheck = 0;
6804 12545 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6805 :
6806 12546 : if (eDataType == GDT_Byte)
6807 : {
6808 : ComputeStatisticsInternal<
6809 : GByte, /* COMPUTE_OTHER_STATS = */ true>::
6810 12076 : f(nXCheck, nBlockXSize, nYCheck,
6811 : static_cast<const GByte *>(pData),
6812 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6813 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6814 : }
6815 : else
6816 : {
6817 : ComputeStatisticsInternal<
6818 : GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
6819 470 : f(nXCheck, nBlockXSize, nYCheck,
6820 : static_cast<const GUInt16 *>(pData),
6821 : nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
6822 : nMax, nSum, nSumSquare, nSampleCount, nValidCount);
6823 : }
6824 :
6825 12547 : poBlock->DropLock();
6826 :
6827 12545 : if (!pfnProgress(static_cast<double>(iSampleBlock) /
6828 12545 : (static_cast<double>(nBlocksPerRow) *
6829 12545 : nBlocksPerColumn),
6830 : "Compute Statistics", pProgressData))
6831 : {
6832 0 : ReportError(CE_Failure, CPLE_UserInterrupt,
6833 : "User terminated");
6834 0 : return CE_Failure;
6835 : }
6836 : }
6837 :
6838 215 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
6839 : {
6840 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6841 0 : return CE_Failure;
6842 : }
6843 :
6844 : /* --------------------------------------------------------------------
6845 : */
6846 : /* Save computed information. */
6847 : /* --------------------------------------------------------------------
6848 : */
6849 215 : if (nValidCount)
6850 206 : dfMean = static_cast<double>(nSum) / nValidCount;
6851 :
6852 : // To avoid potential precision issues when doing the difference,
6853 : // we need to do that computation on 128 bit rather than casting
6854 : // to double
6855 : const GDALUInt128 nTmpForStdDev(
6856 215 : GDALUInt128::Mul(nSumSquare, nValidCount) -
6857 430 : GDALUInt128::Mul(nSum, nSum));
6858 : const double dfStdDev =
6859 215 : nValidCount > 0
6860 215 : ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
6861 215 : : 0.0;
6862 :
6863 215 : if (nValidCount > 0)
6864 : {
6865 206 : if (bApproxOK)
6866 : {
6867 24 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
6868 : }
6869 182 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
6870 : {
6871 3 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
6872 : }
6873 206 : SetStatistics(nMin, nMax, dfMean, dfStdDev);
6874 : }
6875 :
6876 215 : SetValidPercent(nSampleCount, nValidCount);
6877 :
6878 : /* --------------------------------------------------------------------
6879 : */
6880 : /* Record results. */
6881 : /* --------------------------------------------------------------------
6882 : */
6883 215 : if (pdfMin != nullptr)
6884 212 : *pdfMin = nValidCount ? nMin : 0;
6885 215 : if (pdfMax != nullptr)
6886 212 : *pdfMax = nValidCount ? nMax : 0;
6887 :
6888 215 : if (pdfMean != nullptr)
6889 208 : *pdfMean = dfMean;
6890 :
6891 215 : if (pdfStdDev != nullptr)
6892 208 : *pdfStdDev = dfStdDev;
6893 :
6894 215 : if (nValidCount > 0)
6895 206 : return CE_None;
6896 :
6897 9 : ReportError(CE_Failure, CPLE_AppDefined,
6898 : "Failed to compute statistics, no valid pixels found "
6899 : "in sampling.");
6900 9 : return CE_Failure;
6901 : }
6902 :
6903 255 : GByte *pabyMaskData = nullptr;
6904 255 : if (poMaskBand)
6905 : {
6906 : pabyMaskData = static_cast<GByte *>(
6907 44 : VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
6908 44 : if (!pabyMaskData)
6909 : {
6910 0 : return CE_Failure;
6911 : }
6912 : }
6913 :
6914 255 : for (GIntBig iSampleBlock = 0;
6915 5870 : iSampleBlock <
6916 5870 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
6917 5615 : iSampleBlock += nSampleRate)
6918 : {
6919 5615 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
6920 5615 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
6921 :
6922 5615 : int nXCheck = 0, nYCheck = 0;
6923 5615 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
6924 :
6925 6180 : if (poMaskBand &&
6926 565 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
6927 565 : iYBlock * nBlockYSize, nXCheck, nYCheck,
6928 : pabyMaskData, nXCheck, nYCheck, GDT_Byte,
6929 565 : 0, nBlockXSize, nullptr) != CE_None)
6930 : {
6931 0 : CPLFree(pabyMaskData);
6932 0 : return CE_Failure;
6933 : }
6934 :
6935 : GDALRasterBlock *const poBlock =
6936 5615 : GetLockedBlockRef(iXBlock, iYBlock);
6937 5615 : if (poBlock == nullptr)
6938 : {
6939 0 : CPLFree(pabyMaskData);
6940 0 : return CE_Failure;
6941 : }
6942 :
6943 5615 : void *const pData = poBlock->GetDataRef();
6944 :
6945 : // This isn't the fastest way to do this, but is easier for now.
6946 13454 : for (int iY = 0; iY < nYCheck; iY++)
6947 : {
6948 4890780 : for (int iX = 0; iX < nXCheck; iX++)
6949 : {
6950 4882940 : const GPtrDiff_t iOffset =
6951 4882940 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
6952 4882940 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
6953 111829 : continue;
6954 :
6955 4778680 : bool bValid = true;
6956 : double dfValue =
6957 4778680 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
6958 4778680 : sNoDataValues, bValid);
6959 :
6960 4778680 : if (!bValid)
6961 7574 : continue;
6962 :
6963 4771110 : dfMin = std::min(dfMin, dfValue);
6964 4771110 : dfMax = std::max(dfMax, dfValue);
6965 :
6966 4771110 : nValidCount++;
6967 4771110 : if (dfMin == dfMax)
6968 : {
6969 2173320 : if (nValidCount == 1)
6970 254 : dfMean = dfMin;
6971 : }
6972 : else
6973 : {
6974 2597780 : const double dfDelta = dfValue - dfMean;
6975 2597780 : dfMean += dfDelta / nValidCount;
6976 2597780 : dfM2 += dfDelta * (dfValue - dfMean);
6977 : }
6978 : }
6979 : }
6980 :
6981 5615 : nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
6982 :
6983 5615 : poBlock->DropLock();
6984 :
6985 5615 : if (!pfnProgress(
6986 5615 : static_cast<double>(iSampleBlock) /
6987 5615 : (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
6988 : "Compute Statistics", pProgressData))
6989 : {
6990 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6991 0 : CPLFree(pabyMaskData);
6992 0 : return CE_Failure;
6993 : }
6994 : }
6995 :
6996 255 : CPLFree(pabyMaskData);
6997 : }
6998 :
6999 255 : if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
7000 : {
7001 0 : ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7002 0 : return CE_Failure;
7003 : }
7004 :
7005 : /* -------------------------------------------------------------------- */
7006 : /* Save computed information. */
7007 : /* -------------------------------------------------------------------- */
7008 255 : const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
7009 :
7010 255 : if (nValidCount > 0)
7011 : {
7012 254 : if (bApproxOK)
7013 : {
7014 8 : SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
7015 : }
7016 246 : else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
7017 : {
7018 2 : SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
7019 : }
7020 254 : SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7021 : }
7022 : else
7023 : {
7024 1 : dfMin = 0.0;
7025 1 : dfMax = 0.0;
7026 : }
7027 :
7028 255 : SetValidPercent(nSampleCount, nValidCount);
7029 :
7030 : /* -------------------------------------------------------------------- */
7031 : /* Record results. */
7032 : /* -------------------------------------------------------------------- */
7033 255 : if (pdfMin != nullptr)
7034 252 : *pdfMin = dfMin;
7035 255 : if (pdfMax != nullptr)
7036 252 : *pdfMax = dfMax;
7037 :
7038 255 : if (pdfMean != nullptr)
7039 249 : *pdfMean = dfMean;
7040 :
7041 255 : if (pdfStdDev != nullptr)
7042 249 : *pdfStdDev = dfStdDev;
7043 :
7044 255 : if (nValidCount > 0)
7045 254 : return CE_None;
7046 :
7047 1 : ReportError(
7048 : CE_Failure, CPLE_AppDefined,
7049 : "Failed to compute statistics, no valid pixels found in sampling.");
7050 1 : return CE_Failure;
7051 : }
7052 :
7053 : /************************************************************************/
7054 : /* GDALComputeRasterStatistics() */
7055 : /************************************************************************/
7056 :
7057 : /**
7058 : * \brief Compute image statistics.
7059 : *
7060 : * @see GDALRasterBand::ComputeStatistics()
7061 : */
7062 :
7063 156 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
7064 : int bApproxOK, double *pdfMin,
7065 : double *pdfMax, double *pdfMean,
7066 : double *pdfStdDev,
7067 : GDALProgressFunc pfnProgress,
7068 : void *pProgressData)
7069 :
7070 : {
7071 156 : VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
7072 :
7073 156 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7074 :
7075 156 : return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
7076 156 : pdfStdDev, pfnProgress, pProgressData);
7077 : }
7078 :
7079 : /************************************************************************/
7080 : /* SetStatistics() */
7081 : /************************************************************************/
7082 :
7083 : /**
7084 : * \brief Set statistics on band.
7085 : *
7086 : * This method can be used to store min/max/mean/standard deviation
7087 : * statistics on a raster band.
7088 : *
7089 : * The default implementation stores them as metadata, and will only work
7090 : * on formats that can save arbitrary metadata. This method cannot detect
7091 : * whether metadata will be properly saved and so may return CE_None even
7092 : * if the statistics will never be saved.
7093 : *
7094 : * This method is the same as the C function GDALSetRasterStatistics().
7095 : *
7096 : * @param dfMin minimum pixel value.
7097 : *
7098 : * @param dfMax maximum pixel value.
7099 : *
7100 : * @param dfMean mean (average) of all pixel values.
7101 : *
7102 : * @param dfStdDev Standard deviation of all pixel values.
7103 : *
7104 : * @return CE_None on success or CE_Failure on failure.
7105 : */
7106 :
7107 493 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
7108 : double dfStdDev)
7109 :
7110 : {
7111 493 : char szValue[128] = {0};
7112 :
7113 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
7114 493 : SetMetadataItem("STATISTICS_MINIMUM", szValue);
7115 :
7116 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
7117 493 : SetMetadataItem("STATISTICS_MAXIMUM", szValue);
7118 :
7119 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
7120 493 : SetMetadataItem("STATISTICS_MEAN", szValue);
7121 :
7122 493 : CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
7123 493 : SetMetadataItem("STATISTICS_STDDEV", szValue);
7124 :
7125 493 : return CE_None;
7126 : }
7127 :
7128 : /************************************************************************/
7129 : /* GDALSetRasterStatistics() */
7130 : /************************************************************************/
7131 :
7132 : /**
7133 : * \brief Set statistics on band.
7134 : *
7135 : * @see GDALRasterBand::SetStatistics()
7136 : */
7137 :
7138 2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
7139 : double dfMax, double dfMean,
7140 : double dfStdDev)
7141 :
7142 : {
7143 2 : VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
7144 :
7145 2 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7146 2 : return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
7147 : }
7148 :
7149 : /************************************************************************/
7150 : /* ComputeRasterMinMax() */
7151 : /************************************************************************/
7152 :
7153 : template <class T, bool HAS_NODATA>
7154 120995 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
7155 : T *pMax)
7156 : {
7157 120995 : T min0 = *pMin;
7158 120995 : T max0 = *pMax;
7159 120995 : T min1 = *pMin;
7160 120995 : T max1 = *pMax;
7161 : size_t i;
7162 215473 : for (i = 0; i + 1 < nElts; i += 2)
7163 : {
7164 81892 : if (!HAS_NODATA || buffer[i] != nodataValue)
7165 : {
7166 94478 : min0 = std::min(min0, buffer[i]);
7167 94478 : max0 = std::max(max0, buffer[i]);
7168 : }
7169 81892 : if (!HAS_NODATA || buffer[i + 1] != nodataValue)
7170 : {
7171 94478 : min1 = std::min(min1, buffer[i + 1]);
7172 94478 : max1 = std::max(max1, buffer[i + 1]);
7173 : }
7174 : }
7175 120995 : T min = std::min(min0, min1);
7176 120995 : T max = std::max(max0, max1);
7177 120995 : if (i < nElts)
7178 : {
7179 119260 : if (!HAS_NODATA || buffer[i] != nodataValue)
7180 : {
7181 119280 : min = std::min(min, buffer[i]);
7182 119280 : max = std::max(max, buffer[i]);
7183 : }
7184 : }
7185 120995 : *pMin = min;
7186 120995 : *pMax = max;
7187 120995 : }
7188 :
7189 : template <GDALDataType eDataType, bool bSignedByte>
7190 : static void
7191 12301 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
7192 : int nBlockXSize, const GDALNoDataValues &sNoDataValues,
7193 : const GByte *pabyMaskData, double &dfMin, double &dfMax)
7194 : {
7195 12301 : double dfLocalMin = dfMin;
7196 12301 : double dfLocalMax = dfMax;
7197 :
7198 44951 : for (int iY = 0; iY < nYCheck; iY++)
7199 : {
7200 19143299 : for (int iX = 0; iX < nXCheck; iX++)
7201 : {
7202 19110603 : const GPtrDiff_t iOffset =
7203 19110603 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7204 19110603 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7205 3448532 : continue;
7206 19027640 : bool bValid = true;
7207 19027640 : double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
7208 : iOffset, sNoDataValues, bValid);
7209 19027640 : if (!bValid)
7210 3365580 : continue;
7211 :
7212 15662033 : dfLocalMin = std::min(dfLocalMin, dfValue);
7213 15662033 : dfLocalMax = std::max(dfLocalMax, dfValue);
7214 : }
7215 : }
7216 :
7217 12301 : dfMin = dfLocalMin;
7218 12301 : dfMax = dfLocalMax;
7219 12301 : }
7220 :
7221 12301 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
7222 : bool bSignedByte, int nXCheck, int nYCheck,
7223 : int nBlockXSize,
7224 : const GDALNoDataValues &sNoDataValues,
7225 : const GByte *pabyMaskData, double &dfMin,
7226 : double &dfMax)
7227 : {
7228 12301 : switch (eDataType)
7229 : {
7230 0 : case GDT_Unknown:
7231 0 : CPLAssert(false);
7232 : break;
7233 659 : case GDT_Byte:
7234 659 : if (bSignedByte)
7235 : {
7236 3 : ComputeMinMaxGeneric<GDT_Byte, true>(
7237 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7238 : pabyMaskData, dfMin, dfMax);
7239 : }
7240 : else
7241 : {
7242 656 : ComputeMinMaxGeneric<GDT_Byte, false>(
7243 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7244 : pabyMaskData, dfMin, dfMax);
7245 : }
7246 659 : break;
7247 106 : case GDT_Int8:
7248 106 : ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
7249 : nBlockXSize, sNoDataValues,
7250 : pabyMaskData, dfMin, dfMax);
7251 106 : break;
7252 968 : case GDT_UInt16:
7253 968 : ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
7254 : nBlockXSize, sNoDataValues,
7255 : pabyMaskData, dfMin, dfMax);
7256 968 : break;
7257 1 : case GDT_Int16:
7258 1 : ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
7259 : nBlockXSize, sNoDataValues,
7260 : pabyMaskData, dfMin, dfMax);
7261 1 : break;
7262 201 : case GDT_UInt32:
7263 201 : ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
7264 : nBlockXSize, sNoDataValues,
7265 : pabyMaskData, dfMin, dfMax);
7266 201 : break;
7267 1089 : case GDT_Int32:
7268 1089 : ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
7269 : nBlockXSize, sNoDataValues,
7270 : pabyMaskData, dfMin, dfMax);
7271 1089 : break;
7272 17 : case GDT_UInt64:
7273 17 : ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
7274 : nBlockXSize, sNoDataValues,
7275 : pabyMaskData, dfMin, dfMax);
7276 17 : break;
7277 29 : case GDT_Int64:
7278 29 : ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
7279 : nBlockXSize, sNoDataValues,
7280 : pabyMaskData, dfMin, dfMax);
7281 29 : break;
7282 0 : case GDT_Float16:
7283 0 : ComputeMinMaxGeneric<GDT_Float16, false>(
7284 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7285 : pabyMaskData, dfMin, dfMax);
7286 0 : break;
7287 5634 : case GDT_Float32:
7288 5634 : ComputeMinMaxGeneric<GDT_Float32, false>(
7289 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7290 : pabyMaskData, dfMin, dfMax);
7291 5634 : break;
7292 3487 : case GDT_Float64:
7293 3487 : ComputeMinMaxGeneric<GDT_Float64, false>(
7294 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7295 : pabyMaskData, dfMin, dfMax);
7296 3487 : break;
7297 9 : case GDT_CInt16:
7298 9 : ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
7299 : nBlockXSize, sNoDataValues,
7300 : pabyMaskData, dfMin, dfMax);
7301 9 : break;
7302 9 : case GDT_CInt32:
7303 9 : ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
7304 : nBlockXSize, sNoDataValues,
7305 : pabyMaskData, dfMin, dfMax);
7306 9 : break;
7307 0 : case GDT_CFloat16:
7308 0 : ComputeMinMaxGeneric<GDT_CFloat16, false>(
7309 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7310 : pabyMaskData, dfMin, dfMax);
7311 0 : break;
7312 75 : case GDT_CFloat32:
7313 75 : ComputeMinMaxGeneric<GDT_CFloat32, false>(
7314 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7315 : pabyMaskData, dfMin, dfMax);
7316 75 : break;
7317 17 : case GDT_CFloat64:
7318 17 : ComputeMinMaxGeneric<GDT_CFloat64, false>(
7319 : pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
7320 : pabyMaskData, dfMin, dfMax);
7321 17 : break;
7322 0 : case GDT_TypeCount:
7323 0 : CPLAssert(false);
7324 : break;
7325 : }
7326 12301 : }
7327 :
7328 783 : static bool ComputeMinMaxGenericIterBlocks(
7329 : GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
7330 : GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
7331 : const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
7332 : double &dfMin, double &dfMax)
7333 :
7334 : {
7335 783 : GByte *pabyMaskData = nullptr;
7336 : int nBlockXSize, nBlockYSize;
7337 783 : poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
7338 :
7339 783 : if (poMaskBand)
7340 : {
7341 : pabyMaskData =
7342 112 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7343 112 : if (!pabyMaskData)
7344 : {
7345 0 : return false;
7346 : }
7347 : }
7348 :
7349 13084 : for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
7350 12301 : iSampleBlock += nSampleRate)
7351 : {
7352 12301 : const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
7353 12301 : const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
7354 :
7355 12301 : int nXCheck = 0, nYCheck = 0;
7356 12301 : poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7357 :
7358 18868 : if (poMaskBand &&
7359 6567 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7360 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7361 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7362 : nBlockXSize, nullptr) != CE_None)
7363 : {
7364 0 : CPLFree(pabyMaskData);
7365 0 : return false;
7366 : }
7367 :
7368 12301 : GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
7369 12301 : if (poBlock == nullptr)
7370 : {
7371 0 : CPLFree(pabyMaskData);
7372 0 : return false;
7373 : }
7374 :
7375 12301 : void *const pData = poBlock->GetDataRef();
7376 :
7377 12301 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
7378 : nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
7379 : dfMax);
7380 :
7381 12301 : poBlock->DropLock();
7382 : }
7383 :
7384 783 : CPLFree(pabyMaskData);
7385 783 : return true;
7386 : }
7387 :
7388 : /**
7389 : * \brief Compute the min/max values for a band.
7390 : *
7391 : * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
7392 : * be trusted. If it doesn't work, a subsample of blocks will be read to
7393 : * get an approximate min/max. If the band has a nodata value it will
7394 : * be excluded from the minimum and maximum.
7395 : *
7396 : * If bApprox is FALSE, then all pixels will be read and used to compute
7397 : * an exact range.
7398 : *
7399 : * This method is the same as the C function GDALComputeRasterMinMax().
7400 : *
7401 : * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
7402 : * FALSE.
7403 : * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
7404 : * maximum (adfMinMax[1]) are returned.
7405 : *
7406 : * @return CE_None on success or CE_Failure on failure.
7407 : */
7408 :
7409 1767 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
7410 : {
7411 : /* -------------------------------------------------------------------- */
7412 : /* Does the driver already know the min/max? */
7413 : /* -------------------------------------------------------------------- */
7414 1767 : if (bApproxOK)
7415 : {
7416 23 : int bSuccessMin = FALSE;
7417 23 : int bSuccessMax = FALSE;
7418 :
7419 23 : double dfMin = GetMinimum(&bSuccessMin);
7420 23 : double dfMax = GetMaximum(&bSuccessMax);
7421 :
7422 23 : if (bSuccessMin && bSuccessMax)
7423 : {
7424 1 : adfMinMax[0] = dfMin;
7425 1 : adfMinMax[1] = dfMax;
7426 1 : return CE_None;
7427 : }
7428 : }
7429 :
7430 : /* -------------------------------------------------------------------- */
7431 : /* If we have overview bands, use them for min/max. */
7432 : /* -------------------------------------------------------------------- */
7433 : // cppcheck-suppress knownConditionTrueFalse
7434 1766 : if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
7435 : {
7436 : GDALRasterBand *poBand =
7437 0 : GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
7438 :
7439 0 : if (poBand != this)
7440 0 : return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
7441 : }
7442 :
7443 : /* -------------------------------------------------------------------- */
7444 : /* Read actual data and compute minimum and maximum. */
7445 : /* -------------------------------------------------------------------- */
7446 1766 : GDALNoDataValues sNoDataValues(this, eDataType);
7447 1766 : GDALRasterBand *poMaskBand = nullptr;
7448 1766 : if (!sNoDataValues.bGotNoDataValue)
7449 : {
7450 1513 : const int l_nMaskFlags = GetMaskFlags();
7451 1625 : if (l_nMaskFlags != GMF_ALL_VALID &&
7452 112 : GetColorInterpretation() != GCI_AlphaBand)
7453 : {
7454 112 : poMaskBand = GetMaskBand();
7455 : }
7456 : }
7457 :
7458 1766 : bool bSignedByte = false;
7459 1766 : if (eDataType == GDT_Byte)
7460 : {
7461 768 : EnablePixelTypeSignedByteWarning(false);
7462 : const char *pszPixelType =
7463 768 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7464 768 : EnablePixelTypeSignedByteWarning(true);
7465 768 : bSignedByte =
7466 768 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7467 : }
7468 :
7469 : GDALRasterIOExtraArg sExtraArg;
7470 1766 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
7471 :
7472 3532 : GUInt32 nMin = (eDataType == GDT_Byte)
7473 1766 : ? 255
7474 : : 65535; // used for GByte & GUInt16 cases
7475 1766 : GUInt32 nMax = 0; // used for GByte & GUInt16 cases
7476 1766 : GInt16 nMinInt16 =
7477 : std::numeric_limits<GInt16>::max(); // used for GInt16 case
7478 1766 : GInt16 nMaxInt16 =
7479 : std::numeric_limits<GInt16>::lowest(); // used for GInt16 case
7480 1766 : double dfMin =
7481 : std::numeric_limits<double>::infinity(); // used for generic code path
7482 1766 : double dfMax =
7483 : -std::numeric_limits<double>::infinity(); // used for generic code path
7484 1766 : const bool bUseOptimizedPath =
7485 2682 : !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
7486 916 : eDataType == GDT_Int16 || eDataType == GDT_UInt16);
7487 :
7488 : const auto ComputeMinMaxForBlock =
7489 20935 : [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
7490 : &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
7491 243429 : int nYCheck)
7492 : {
7493 20935 : if (eDataType == GDT_Byte && !bSignedByte)
7494 : {
7495 : const bool bHasNoData =
7496 11561 : sNoDataValues.bGotNoDataValue &&
7497 29655 : GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
7498 11561 : static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
7499 11561 : sNoDataValues.dfNoDataValue;
7500 18094 : const GUInt32 nNoDataValue =
7501 18094 : bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
7502 : : 0;
7503 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7504 : ComputeStatisticsInternal<GByte,
7505 : /* COMPUTE_OTHER_STATS = */ false>::
7506 18094 : f(nXCheck, nBufferWidth, nYCheck,
7507 : static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
7508 18094 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7509 : }
7510 2841 : else if (eDataType == GDT_UInt16)
7511 : {
7512 : const bool bHasNoData =
7513 83 : sNoDataValues.bGotNoDataValue &&
7514 1495 : GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
7515 83 : static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
7516 83 : sNoDataValues.dfNoDataValue;
7517 1412 : const GUInt32 nNoDataValue =
7518 1412 : bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
7519 : : 0;
7520 : GUIntBig nSum, nSumSquare, nSampleCount, nValidCount; // unused
7521 : ComputeStatisticsInternal<GUInt16,
7522 : /* COMPUTE_OTHER_STATS = */ false>::
7523 1412 : f(nXCheck, nBufferWidth, nYCheck,
7524 : static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
7525 : nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
7526 : }
7527 1429 : else if (eDataType == GDT_Int16)
7528 : {
7529 : const bool bHasNoData =
7530 1254 : sNoDataValues.bGotNoDataValue &&
7531 2683 : GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
7532 1254 : static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
7533 1254 : sNoDataValues.dfNoDataValue;
7534 1429 : if (bHasNoData)
7535 : {
7536 1254 : const int16_t nNoDataValue =
7537 1254 : static_cast<int16_t>(sNoDataValues.dfNoDataValue);
7538 120957 : for (int iY = 0; iY < nYCheck; iY++)
7539 : {
7540 119703 : ComputeMinMax<int16_t, true>(
7541 119703 : static_cast<const int16_t *>(pData) +
7542 119703 : static_cast<size_t>(iY) * nBufferWidth,
7543 : nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
7544 : }
7545 : }
7546 : else
7547 : {
7548 1467 : for (int iY = 0; iY < nYCheck; iY++)
7549 : {
7550 1292 : ComputeMinMax<int16_t, false>(
7551 1292 : static_cast<const int16_t *>(pData) +
7552 1292 : static_cast<size_t>(iY) * nBufferWidth,
7553 : nXCheck, 0, &nMinInt16, &nMaxInt16);
7554 : }
7555 : }
7556 : }
7557 20935 : };
7558 :
7559 1766 : if (bApproxOK && HasArbitraryOverviews())
7560 : {
7561 : /* --------------------------------------------------------------------
7562 : */
7563 : /* Figure out how much the image should be reduced to get an */
7564 : /* approximate value. */
7565 : /* --------------------------------------------------------------------
7566 : */
7567 0 : double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
7568 0 : nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
7569 :
7570 0 : int nXReduced = nRasterXSize;
7571 0 : int nYReduced = nRasterYSize;
7572 0 : if (dfReduction > 1.0)
7573 : {
7574 0 : nXReduced = static_cast<int>(nRasterXSize / dfReduction);
7575 0 : nYReduced = static_cast<int>(nRasterYSize / dfReduction);
7576 :
7577 : // Catch the case of huge resizing ratios here
7578 0 : if (nXReduced == 0)
7579 0 : nXReduced = 1;
7580 0 : if (nYReduced == 0)
7581 0 : nYReduced = 1;
7582 : }
7583 :
7584 0 : void *const pData = CPLMalloc(cpl::fits_on<int>(
7585 0 : GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
7586 :
7587 : const CPLErr eErr =
7588 0 : IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
7589 0 : nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
7590 0 : if (eErr != CE_None)
7591 : {
7592 0 : CPLFree(pData);
7593 0 : return eErr;
7594 : }
7595 :
7596 0 : GByte *pabyMaskData = nullptr;
7597 0 : if (poMaskBand)
7598 : {
7599 : pabyMaskData =
7600 0 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
7601 0 : if (!pabyMaskData)
7602 : {
7603 0 : CPLFree(pData);
7604 0 : return CE_Failure;
7605 : }
7606 :
7607 0 : if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
7608 : pabyMaskData, nXReduced, nYReduced,
7609 0 : GDT_Byte, 0, 0, nullptr) != CE_None)
7610 : {
7611 0 : CPLFree(pData);
7612 0 : CPLFree(pabyMaskData);
7613 0 : return CE_Failure;
7614 : }
7615 : }
7616 :
7617 0 : if (bUseOptimizedPath)
7618 : {
7619 0 : ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
7620 : }
7621 : else
7622 : {
7623 0 : ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
7624 : nYReduced, nXReduced, sNoDataValues,
7625 : pabyMaskData, dfMin, dfMax);
7626 : }
7627 :
7628 0 : CPLFree(pData);
7629 0 : CPLFree(pabyMaskData);
7630 : }
7631 :
7632 : else // No arbitrary overviews
7633 : {
7634 1766 : if (!InitBlockInfo())
7635 0 : return CE_Failure;
7636 :
7637 : /* --------------------------------------------------------------------
7638 : */
7639 : /* Figure out the ratio of blocks we will read to get an */
7640 : /* approximate value. */
7641 : /* --------------------------------------------------------------------
7642 : */
7643 1766 : int nSampleRate = 1;
7644 :
7645 1766 : if (bApproxOK)
7646 : {
7647 22 : nSampleRate = static_cast<int>(std::max(
7648 44 : 1.0,
7649 22 : sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
7650 : // We want to avoid probing only the first column of blocks for
7651 : // a square shaped raster, because it is not unlikely that it may
7652 : // be padding only (#6378).
7653 22 : if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
7654 0 : nSampleRate += 1;
7655 : }
7656 :
7657 1766 : if (bUseOptimizedPath)
7658 : {
7659 983 : for (GIntBig iSampleBlock = 0;
7660 21844 : iSampleBlock <
7661 21844 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7662 20861 : iSampleBlock += nSampleRate)
7663 : {
7664 20936 : const int iYBlock =
7665 20936 : static_cast<int>(iSampleBlock / nBlocksPerRow);
7666 20936 : const int iXBlock =
7667 20936 : static_cast<int>(iSampleBlock % nBlocksPerRow);
7668 :
7669 20936 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7670 20936 : if (poBlock == nullptr)
7671 1 : return CE_Failure;
7672 :
7673 20935 : void *const pData = poBlock->GetDataRef();
7674 :
7675 20935 : int nXCheck = 0, nYCheck = 0;
7676 20935 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7677 :
7678 20935 : ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
7679 :
7680 20935 : poBlock->DropLock();
7681 :
7682 20935 : if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
7683 4104 : nMax == 255)
7684 74 : break;
7685 : }
7686 : }
7687 : else
7688 : {
7689 783 : const GIntBig nTotalBlocks =
7690 783 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7691 783 : if (!ComputeMinMaxGenericIterBlocks(
7692 : this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
7693 : nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
7694 : {
7695 0 : return CE_Failure;
7696 : }
7697 : }
7698 : }
7699 :
7700 1765 : if (bUseOptimizedPath)
7701 : {
7702 982 : if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
7703 : {
7704 877 : dfMin = nMin;
7705 877 : dfMax = nMax;
7706 : }
7707 105 : else if (eDataType == GDT_Int16)
7708 : {
7709 105 : dfMin = nMinInt16;
7710 105 : dfMax = nMaxInt16;
7711 : }
7712 : }
7713 :
7714 1765 : if (dfMin > dfMax)
7715 : {
7716 9 : adfMinMax[0] = 0;
7717 9 : adfMinMax[1] = 0;
7718 9 : ReportError(
7719 : CE_Failure, CPLE_AppDefined,
7720 : "Failed to compute min/max, no valid pixels found in sampling.");
7721 9 : return CE_Failure;
7722 : }
7723 :
7724 1756 : adfMinMax[0] = dfMin;
7725 1756 : adfMinMax[1] = dfMax;
7726 :
7727 1756 : return CE_None;
7728 : }
7729 :
7730 : /************************************************************************/
7731 : /* GDALComputeRasterMinMax() */
7732 : /************************************************************************/
7733 :
7734 : /**
7735 : * \brief Compute the min/max values for a band.
7736 : *
7737 : * @see GDALRasterBand::ComputeRasterMinMax()
7738 : *
7739 : * @note Prior to GDAL 3.6, this function returned void
7740 : */
7741 :
7742 1616 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
7743 : double adfMinMax[2])
7744 :
7745 : {
7746 1616 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
7747 :
7748 1616 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
7749 1616 : return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
7750 : }
7751 :
7752 : /************************************************************************/
7753 : /* ComputeRasterMinMaxLocation() */
7754 : /************************************************************************/
7755 :
7756 : /**
7757 : * \brief Compute the min/max values for a band, and their location.
7758 : *
7759 : * Pixels whose value matches the nodata value or are masked by the mask
7760 : * band are ignored.
7761 : *
7762 : * If the minimum or maximum value is hit in several locations, it is not
7763 : * specified which one will be returned.
7764 : *
7765 : * @param[out] pdfMin Pointer to the minimum value.
7766 : * @param[out] pdfMax Pointer to the maximum value.
7767 : * @param[out] pnMinX Pointer to the column where the minimum value is hit.
7768 : * @param[out] pnMinY Pointer to the line where the minimum value is hit.
7769 : * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
7770 : * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
7771 : *
7772 : * @return CE_None in case of success, CE_Warning if there are no valid values,
7773 : * CE_Failure in case of error.
7774 : *
7775 : * @since GDAL 3.11
7776 : */
7777 :
7778 8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
7779 : double *pdfMax, int *pnMinX,
7780 : int *pnMinY, int *pnMaxX,
7781 : int *pnMaxY)
7782 : {
7783 8 : int nMinX = -1;
7784 8 : int nMinY = -1;
7785 8 : int nMaxX = -1;
7786 8 : int nMaxY = -1;
7787 8 : double dfMin = std::numeric_limits<double>::infinity();
7788 8 : double dfMax = -std::numeric_limits<double>::infinity();
7789 8 : if (pdfMin)
7790 5 : *pdfMin = dfMin;
7791 8 : if (pdfMax)
7792 5 : *pdfMax = dfMax;
7793 8 : if (pnMinX)
7794 6 : *pnMinX = nMinX;
7795 8 : if (pnMinY)
7796 6 : *pnMinY = nMinY;
7797 8 : if (pnMaxX)
7798 6 : *pnMaxX = nMaxX;
7799 8 : if (pnMaxY)
7800 6 : *pnMaxY = nMaxY;
7801 :
7802 8 : if (GDALDataTypeIsComplex(eDataType))
7803 : {
7804 0 : CPLError(CE_Failure, CPLE_NotSupported,
7805 : "Complex data type not supported");
7806 0 : return CE_Failure;
7807 : }
7808 :
7809 8 : if (!InitBlockInfo())
7810 0 : return CE_Failure;
7811 :
7812 8 : GDALNoDataValues sNoDataValues(this, eDataType);
7813 8 : GDALRasterBand *poMaskBand = nullptr;
7814 8 : if (!sNoDataValues.bGotNoDataValue)
7815 : {
7816 8 : const int l_nMaskFlags = GetMaskFlags();
7817 9 : if (l_nMaskFlags != GMF_ALL_VALID &&
7818 1 : GetColorInterpretation() != GCI_AlphaBand)
7819 : {
7820 1 : poMaskBand = GetMaskBand();
7821 : }
7822 : }
7823 :
7824 8 : bool bSignedByte = false;
7825 8 : if (eDataType == GDT_Byte)
7826 : {
7827 7 : EnablePixelTypeSignedByteWarning(false);
7828 : const char *pszPixelType =
7829 7 : GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
7830 7 : EnablePixelTypeSignedByteWarning(true);
7831 7 : bSignedByte =
7832 7 : pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
7833 : }
7834 :
7835 8 : GByte *pabyMaskData = nullptr;
7836 8 : if (poMaskBand)
7837 : {
7838 : pabyMaskData =
7839 1 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
7840 1 : if (!pabyMaskData)
7841 : {
7842 0 : return CE_Failure;
7843 : }
7844 : }
7845 :
7846 8 : const GIntBig nTotalBlocks =
7847 8 : static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
7848 8 : bool bNeedsMin = pdfMin || pnMinX || pnMinY;
7849 8 : bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
7850 16 : for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
7851 : {
7852 11 : const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
7853 11 : const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
7854 :
7855 11 : int nXCheck = 0, nYCheck = 0;
7856 11 : GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
7857 :
7858 13 : if (poMaskBand &&
7859 2 : poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
7860 2 : iYBlock * nBlockYSize, nXCheck, nYCheck,
7861 : pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
7862 2 : nBlockXSize, nullptr) != CE_None)
7863 : {
7864 0 : CPLFree(pabyMaskData);
7865 0 : return CE_Failure;
7866 : }
7867 :
7868 11 : GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
7869 11 : if (poBlock == nullptr)
7870 : {
7871 0 : CPLFree(pabyMaskData);
7872 0 : return CE_Failure;
7873 : }
7874 :
7875 11 : void *const pData = poBlock->GetDataRef();
7876 :
7877 11 : if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
7878 : {
7879 4 : for (int iY = 0; iY < nYCheck; ++iY)
7880 : {
7881 6 : for (int iX = 0; iX < nXCheck; ++iX)
7882 : {
7883 4 : const GPtrDiff_t iOffset =
7884 4 : iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
7885 4 : if (pabyMaskData && pabyMaskData[iOffset] == 0)
7886 2 : continue;
7887 2 : bool bValid = true;
7888 : double dfValue =
7889 2 : GetPixelValue(eDataType, bSignedByte, pData, iOffset,
7890 : sNoDataValues, bValid);
7891 2 : if (!bValid)
7892 0 : continue;
7893 2 : if (dfValue < dfMin)
7894 : {
7895 2 : dfMin = dfValue;
7896 2 : nMinX = iXBlock * nBlockXSize + iX;
7897 2 : nMinY = iYBlock * nBlockYSize + iY;
7898 : }
7899 2 : if (dfValue > dfMax)
7900 : {
7901 1 : dfMax = dfValue;
7902 1 : nMaxX = iXBlock * nBlockXSize + iX;
7903 1 : nMaxY = iYBlock * nBlockYSize + iY;
7904 : }
7905 : }
7906 2 : }
7907 : }
7908 : else
7909 : {
7910 9 : size_t pos_min = 0;
7911 9 : size_t pos_max = 0;
7912 9 : const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
7913 9 : if (bNeedsMin && bNeedsMax)
7914 : {
7915 10 : std::tie(pos_min, pos_max) = gdal::minmax_element(
7916 5 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7917 5 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7918 10 : sNoDataValues.dfNoDataValue);
7919 : }
7920 4 : else if (bNeedsMin)
7921 : {
7922 1 : pos_min = gdal::min_element(
7923 1 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7924 1 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7925 : sNoDataValues.dfNoDataValue);
7926 : }
7927 3 : else if (bNeedsMax)
7928 : {
7929 2 : pos_max = gdal::max_element(
7930 2 : pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
7931 2 : eEffectiveDT, sNoDataValues.bGotNoDataValue,
7932 : sNoDataValues.dfNoDataValue);
7933 : }
7934 :
7935 9 : if (bNeedsMin)
7936 : {
7937 6 : const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
7938 6 : const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
7939 6 : bool bValid = true;
7940 : const double dfMinValueBlock =
7941 6 : GetPixelValue(eDataType, bSignedByte, pData, pos_min,
7942 : sNoDataValues, bValid);
7943 6 : if (bValid && dfMinValueBlock < dfMin)
7944 : {
7945 5 : dfMin = dfMinValueBlock;
7946 5 : nMinX = iXBlock * nBlockXSize + nMinXBlock;
7947 5 : nMinY = iYBlock * nBlockYSize + nMinYBlock;
7948 : }
7949 : }
7950 :
7951 9 : if (bNeedsMax)
7952 : {
7953 7 : const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
7954 7 : const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
7955 7 : bool bValid = true;
7956 : const double dfMaxValueBlock =
7957 7 : GetPixelValue(eDataType, bSignedByte, pData, pos_max,
7958 : sNoDataValues, bValid);
7959 7 : if (bValid && dfMaxValueBlock > dfMax)
7960 : {
7961 5 : dfMax = dfMaxValueBlock;
7962 5 : nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
7963 5 : nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
7964 : }
7965 : }
7966 : }
7967 :
7968 11 : poBlock->DropLock();
7969 :
7970 11 : if (eDataType == GDT_Byte)
7971 : {
7972 10 : if (bNeedsMin && dfMin == 0)
7973 : {
7974 1 : bNeedsMin = false;
7975 : }
7976 10 : if (bNeedsMax && dfMax == 255)
7977 : {
7978 4 : bNeedsMax = false;
7979 : }
7980 10 : if (!bNeedsMin && !bNeedsMax)
7981 : {
7982 3 : break;
7983 : }
7984 : }
7985 : }
7986 :
7987 8 : CPLFree(pabyMaskData);
7988 :
7989 8 : if (pdfMin)
7990 5 : *pdfMin = dfMin;
7991 8 : if (pdfMax)
7992 5 : *pdfMax = dfMax;
7993 8 : if (pnMinX)
7994 6 : *pnMinX = nMinX;
7995 8 : if (pnMinY)
7996 6 : *pnMinY = nMinY;
7997 8 : if (pnMaxX)
7998 6 : *pnMaxX = nMaxX;
7999 8 : if (pnMaxY)
8000 6 : *pnMaxY = nMaxY;
8001 8 : return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
8002 8 : : CE_None;
8003 : }
8004 :
8005 : /************************************************************************/
8006 : /* GDALComputeRasterMinMaxLocation() */
8007 : /************************************************************************/
8008 :
8009 : /**
8010 : * \brief Compute the min/max values for a band, and their location.
8011 : *
8012 : * @see GDALRasterBand::ComputeRasterMinMax()
8013 : * @since GDAL 3.11
8014 : */
8015 :
8016 6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
8017 : double *pdfMax, int *pnMinX, int *pnMinY,
8018 : int *pnMaxX, int *pnMaxY)
8019 :
8020 : {
8021 6 : VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
8022 :
8023 6 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8024 6 : return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
8025 6 : pnMaxX, pnMaxY);
8026 : }
8027 :
8028 : /************************************************************************/
8029 : /* SetDefaultHistogram() */
8030 : /************************************************************************/
8031 :
8032 : /* FIXME : add proper documentation */
8033 : /**
8034 : * \brief Set default histogram.
8035 : *
8036 : * This method is the same as the C function GDALSetDefaultHistogram() and
8037 : * GDALSetDefaultHistogramEx()
8038 : */
8039 0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
8040 : double /* dfMax */,
8041 : int /* nBuckets */,
8042 : GUIntBig * /* panHistogram */)
8043 :
8044 : {
8045 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8046 0 : ReportError(CE_Failure, CPLE_NotSupported,
8047 : "SetDefaultHistogram() not implemented for this format.");
8048 :
8049 0 : return CE_Failure;
8050 : }
8051 :
8052 : /************************************************************************/
8053 : /* GDALSetDefaultHistogram() */
8054 : /************************************************************************/
8055 :
8056 : /**
8057 : * \brief Set default histogram.
8058 : *
8059 : * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
8060 : * 2 billion.
8061 : *
8062 : * @see GDALRasterBand::SetDefaultHistogram()
8063 : * @see GDALSetRasterHistogramEx()
8064 : */
8065 :
8066 0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
8067 : double dfMax, int nBuckets,
8068 : int *panHistogram)
8069 :
8070 : {
8071 0 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
8072 :
8073 0 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8074 :
8075 : GUIntBig *panHistogramTemp =
8076 0 : static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
8077 0 : if (panHistogramTemp == nullptr)
8078 : {
8079 0 : poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
8080 : "Out of memory in GDALSetDefaultHistogram().");
8081 0 : return CE_Failure;
8082 : }
8083 :
8084 0 : for (int i = 0; i < nBuckets; ++i)
8085 : {
8086 0 : panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
8087 : }
8088 :
8089 : const CPLErr eErr =
8090 0 : poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
8091 :
8092 0 : CPLFree(panHistogramTemp);
8093 :
8094 0 : return eErr;
8095 : }
8096 :
8097 : /************************************************************************/
8098 : /* GDALSetDefaultHistogramEx() */
8099 : /************************************************************************/
8100 :
8101 : /**
8102 : * \brief Set default histogram.
8103 : *
8104 : * @see GDALRasterBand::SetDefaultHistogram()
8105 : *
8106 : * @since GDAL 2.0
8107 : */
8108 :
8109 5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
8110 : double dfMin, double dfMax,
8111 : int nBuckets,
8112 : GUIntBig *panHistogram)
8113 :
8114 : {
8115 5 : VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
8116 :
8117 5 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8118 5 : return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
8119 : }
8120 :
8121 : /************************************************************************/
8122 : /* GetDefaultRAT() */
8123 : /************************************************************************/
8124 :
8125 : /**
8126 : * \brief Fetch default Raster Attribute Table.
8127 : *
8128 : * A RAT will be returned if there is a default one associated with the
8129 : * band, otherwise NULL is returned. The returned RAT is owned by the
8130 : * band and should not be deleted by the application.
8131 : *
8132 : * This method is the same as the C function GDALGetDefaultRAT().
8133 : *
8134 : * @return NULL, or a pointer to an internal RAT owned by the band.
8135 : */
8136 :
8137 176 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
8138 :
8139 : {
8140 176 : return nullptr;
8141 : }
8142 :
8143 : /************************************************************************/
8144 : /* GDALGetDefaultRAT() */
8145 : /************************************************************************/
8146 :
8147 : /**
8148 : * \brief Fetch default Raster Attribute Table.
8149 : *
8150 : * @see GDALRasterBand::GetDefaultRAT()
8151 : */
8152 :
8153 1113 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
8154 :
8155 : {
8156 1113 : VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
8157 :
8158 1113 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8159 1113 : return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
8160 : }
8161 :
8162 : /************************************************************************/
8163 : /* SetDefaultRAT() */
8164 : /************************************************************************/
8165 :
8166 : /**
8167 : * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
8168 : * \brief Set default Raster Attribute Table.
8169 : *
8170 : * Associates a default RAT with the band. If not implemented for the
8171 : * format a CPLE_NotSupported error will be issued. If successful a copy
8172 : * of the RAT is made, the original remains owned by the caller.
8173 : *
8174 : * This method is the same as the C function GDALSetDefaultRAT().
8175 : *
8176 : * @param poRAT the RAT to assign to the band.
8177 : *
8178 : * @return CE_None on success or CE_Failure if unsupported or otherwise
8179 : * failing.
8180 : */
8181 :
8182 : /**/
8183 : /**/
8184 :
8185 : CPLErr
8186 0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
8187 : {
8188 0 : if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
8189 : {
8190 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
8191 0 : ReportError(CE_Failure, CPLE_NotSupported,
8192 : "SetDefaultRAT() not implemented for this format.");
8193 0 : CPLPopErrorHandler();
8194 : }
8195 0 : return CE_Failure;
8196 : }
8197 :
8198 : /************************************************************************/
8199 : /* GDALSetDefaultRAT() */
8200 : /************************************************************************/
8201 :
8202 : /**
8203 : * \brief Set default Raster Attribute Table.
8204 : *
8205 : * @see GDALRasterBand::GDALSetDefaultRAT()
8206 : */
8207 :
8208 18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
8209 : GDALRasterAttributeTableH hRAT)
8210 :
8211 : {
8212 18 : VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
8213 :
8214 18 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8215 :
8216 18 : return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
8217 : }
8218 :
8219 : /************************************************************************/
8220 : /* GetMaskBand() */
8221 : /************************************************************************/
8222 :
8223 : /**
8224 : * \brief Return the mask band associated with the band.
8225 : *
8226 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8227 : * that returns one of four default implementations :
8228 : * <ul>
8229 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8230 : * </li>
8231 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8232 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8233 : * GMF_NODATA | GMF_PER_DATASET.
8234 : * </li>
8235 : * <li>If the band has a nodata value set, an instance of the new
8236 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8237 : * GMF_NODATA.
8238 : * </li>
8239 : * <li>If there is no nodata value, but the dataset has an alpha band that seems
8240 : * to apply to this band (specific rules yet to be determined) and that is of
8241 : * type GDT_Byte then that alpha band will be returned, and the flags
8242 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8243 : * </li>
8244 : * <li>If neither of the above apply, an instance of the new
8245 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8246 : * pixels. The null flags will return GMF_ALL_VALID.
8247 : * </li>
8248 : * </ul>
8249 : *
8250 : * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
8251 : * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
8252 : *
8253 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8254 : * dataset, with the same name as the main dataset and suffixed with .msk,
8255 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8256 : * main dataset.
8257 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8258 : * level, where xx matches the band number of a band of the main dataset. The
8259 : * value of those items is a combination of the flags GMF_ALL_VALID,
8260 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8261 : * a band, then the other rules explained above will be used to generate a
8262 : * on-the-fly mask band.
8263 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8264 : *
8265 : * This method is the same as the C function GDALGetMaskBand().
8266 : *
8267 : * @return a valid mask band.
8268 : *
8269 : * @since GDAL 1.5.0
8270 : *
8271 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8272 : *
8273 : */
8274 741951 : GDALRasterBand *GDALRasterBand::GetMaskBand()
8275 :
8276 : {
8277 393818 : const auto HasNoData = [this]()
8278 : {
8279 130980 : int bHaveNoDataRaw = FALSE;
8280 130980 : bool bHaveNoData = false;
8281 130980 : if (eDataType == GDT_Int64)
8282 : {
8283 203 : CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
8284 203 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8285 : }
8286 130777 : else if (eDataType == GDT_UInt64)
8287 : {
8288 151 : CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
8289 151 : bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
8290 : }
8291 : else
8292 : {
8293 130626 : const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
8294 130630 : if (bHaveNoDataRaw &&
8295 130630 : GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
8296 : {
8297 1040 : bHaveNoData = true;
8298 : }
8299 : }
8300 130985 : return bHaveNoData;
8301 741951 : };
8302 :
8303 741951 : if (poMask != nullptr)
8304 : {
8305 621677 : if (poMask.IsOwned())
8306 : {
8307 312408 : if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
8308 : {
8309 33404 : if (HasNoData())
8310 : {
8311 9 : InvalidateMaskBand();
8312 : }
8313 : }
8314 287008 : else if (auto poNoDataMaskBand =
8315 281438 : dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
8316 : {
8317 392 : int bHaveNoDataRaw = FALSE;
8318 392 : bool bIsSame = false;
8319 392 : if (eDataType == GDT_Int64)
8320 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
8321 27 : GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
8322 10 : bHaveNoDataRaw;
8323 375 : else if (eDataType == GDT_UInt64)
8324 17 : bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
8325 27 : GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
8326 10 : bHaveNoDataRaw;
8327 : else
8328 : {
8329 : const double dfNoDataValue =
8330 358 : GetNoDataValue(&bHaveNoDataRaw);
8331 358 : if (bHaveNoDataRaw)
8332 : {
8333 355 : bIsSame =
8334 355 : std::isnan(dfNoDataValue)
8335 355 : ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
8336 320 : : poNoDataMaskBand->m_dfNoDataValue ==
8337 : dfNoDataValue;
8338 : }
8339 : }
8340 392 : if (!bIsSame)
8341 23 : InvalidateMaskBand();
8342 : }
8343 : }
8344 :
8345 668051 : if (poMask)
8346 674711 : return poMask.get();
8347 : }
8348 :
8349 : /* -------------------------------------------------------------------- */
8350 : /* Check for a mask in a .msk file. */
8351 : /* -------------------------------------------------------------------- */
8352 97694 : if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
8353 : {
8354 47 : poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
8355 47 : if (poMask != nullptr)
8356 : {
8357 45 : nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
8358 45 : return poMask.get();
8359 : }
8360 : }
8361 :
8362 : /* -------------------------------------------------------------------- */
8363 : /* Check for NODATA_VALUES metadata. */
8364 : /* -------------------------------------------------------------------- */
8365 97649 : if (poDS != nullptr)
8366 : {
8367 : const char *pszGDALNoDataValues =
8368 97634 : poDS->GetMetadataItem("NODATA_VALUES");
8369 97632 : if (pszGDALNoDataValues != nullptr)
8370 : {
8371 68 : char **papszGDALNoDataValues = CSLTokenizeStringComplex(
8372 : pszGDALNoDataValues, " ", FALSE, FALSE);
8373 :
8374 : // Make sure we have as many values as bands.
8375 136 : if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
8376 68 : poDS->GetRasterCount() != 0)
8377 : {
8378 : // Make sure that all bands have the same data type
8379 : // This is clearly not a fundamental condition, just a
8380 : // condition to make implementation easier.
8381 68 : GDALDataType eDT = GDT_Unknown;
8382 68 : int i = 0; // Used after for.
8383 270 : for (; i < poDS->GetRasterCount(); ++i)
8384 : {
8385 202 : if (i == 0)
8386 68 : eDT = poDS->GetRasterBand(1)->GetRasterDataType();
8387 134 : else if (eDT !=
8388 134 : poDS->GetRasterBand(i + 1)->GetRasterDataType())
8389 : {
8390 0 : break;
8391 : }
8392 : }
8393 68 : if (i == poDS->GetRasterCount())
8394 : {
8395 68 : nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
8396 : try
8397 : {
8398 68 : poMask.reset(
8399 136 : std::make_unique<GDALNoDataValuesMaskBand>(poDS));
8400 : }
8401 0 : catch (const std::bad_alloc &)
8402 : {
8403 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8404 0 : poMask.reset();
8405 : }
8406 68 : CSLDestroy(papszGDALNoDataValues);
8407 68 : return poMask.get();
8408 : }
8409 : else
8410 : {
8411 0 : ReportError(CE_Warning, CPLE_AppDefined,
8412 : "All bands should have the same type in "
8413 : "order the NODATA_VALUES metadata item "
8414 : "to be used as a mask.");
8415 : }
8416 : }
8417 : else
8418 : {
8419 0 : ReportError(
8420 : CE_Warning, CPLE_AppDefined,
8421 : "NODATA_VALUES metadata item doesn't have the same number "
8422 : "of values as the number of bands. "
8423 : "Ignoring it for mask.");
8424 : }
8425 :
8426 0 : CSLDestroy(papszGDALNoDataValues);
8427 : }
8428 : }
8429 :
8430 : /* -------------------------------------------------------------------- */
8431 : /* Check for nodata case. */
8432 : /* -------------------------------------------------------------------- */
8433 97579 : if (HasNoData())
8434 : {
8435 1066 : nMaskFlags = GMF_NODATA;
8436 : try
8437 : {
8438 1066 : poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
8439 : }
8440 0 : catch (const std::bad_alloc &)
8441 : {
8442 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8443 0 : poMask.reset();
8444 : }
8445 1066 : return poMask.get();
8446 : }
8447 :
8448 : /* -------------------------------------------------------------------- */
8449 : /* Check for alpha case. */
8450 : /* -------------------------------------------------------------------- */
8451 96499 : if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
8452 193602 : this == poDS->GetRasterBand(1) &&
8453 589 : poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
8454 : {
8455 223 : if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
8456 : {
8457 179 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8458 179 : poMask.resetNotOwned(poDS->GetRasterBand(2));
8459 179 : return poMask.get();
8460 : }
8461 44 : else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
8462 : {
8463 23 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8464 : try
8465 : {
8466 23 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8467 46 : poDS->GetRasterBand(2)));
8468 : }
8469 0 : catch (const std::bad_alloc &)
8470 : {
8471 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8472 0 : poMask.reset();
8473 : }
8474 23 : return poMask.get();
8475 : }
8476 : }
8477 :
8478 96298 : if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
8479 3032 : (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
8480 193334 : this == poDS->GetRasterBand(3)) &&
8481 2355 : poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
8482 : {
8483 1481 : if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
8484 : {
8485 1430 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8486 1430 : poMask.resetNotOwned(poDS->GetRasterBand(4));
8487 1431 : return poMask.get();
8488 : }
8489 50 : else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
8490 : {
8491 38 : nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
8492 : try
8493 : {
8494 38 : poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
8495 76 : poDS->GetRasterBand(4)));
8496 : }
8497 0 : catch (const std::bad_alloc &)
8498 : {
8499 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8500 0 : poMask.reset();
8501 : }
8502 38 : return poMask.get();
8503 : }
8504 : }
8505 :
8506 : /* -------------------------------------------------------------------- */
8507 : /* Fallback to all valid case. */
8508 : /* -------------------------------------------------------------------- */
8509 94843 : nMaskFlags = GMF_ALL_VALID;
8510 : try
8511 : {
8512 94843 : poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
8513 : }
8514 0 : catch (const std::bad_alloc &)
8515 : {
8516 0 : CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
8517 0 : poMask.reset();
8518 : }
8519 :
8520 94841 : return poMask.get();
8521 : }
8522 :
8523 : /************************************************************************/
8524 : /* GDALGetMaskBand() */
8525 : /************************************************************************/
8526 :
8527 : /**
8528 : * \brief Return the mask band associated with the band.
8529 : *
8530 : * @see GDALRasterBand::GetMaskBand()
8531 : */
8532 :
8533 11043 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
8534 :
8535 : {
8536 11043 : VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
8537 :
8538 11043 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8539 11043 : return poBand->GetMaskBand();
8540 : }
8541 :
8542 : /************************************************************************/
8543 : /* GetMaskFlags() */
8544 : /************************************************************************/
8545 :
8546 : /**
8547 : * \brief Return the status flags of the mask band associated with the band.
8548 : *
8549 : * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
8550 : * the following available definitions that may be extended in the future:
8551 : * <ul>
8552 : * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
8553 : * 255. When used this will normally be the only flag set.
8554 : * </li>
8555 : * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
8556 : * dataset.
8557 : * </li>
8558 : * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
8559 : * and may have values other than 0 and 255.
8560 : * </li>
8561 : * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
8562 : * nodata values. (mutually exclusive of GMF_ALPHA)
8563 : * </li>
8564 : * </ul>
8565 : *
8566 : * The GDALRasterBand class includes a default implementation of GetMaskBand()
8567 : * that returns one of four default implementations:
8568 : * <ul>
8569 : * <li>If a corresponding .msk file exists it will be used for the mask band.
8570 : * </li>
8571 : * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
8572 : * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
8573 : * GMF_NODATA | GMF_PER_DATASET.
8574 : * </li>
8575 : * <li>If the band has a nodata value set, an instance of the new
8576 : * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
8577 : * GMF_NODATA.
8578 : * </li>
8579 : * <li>If there is no nodata value, but the dataset has an alpha band that
8580 : * seems to apply to this band (specific rules yet to be determined) and that is
8581 : * of type GDT_Byte then that alpha band will be returned, and the flags
8582 : * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
8583 : * </li>
8584 : * <li>If neither of the above apply, an instance of the new
8585 : * GDALAllValidRasterBand class will be returned that has 255 values for all
8586 : * pixels. The null flags will return GMF_ALL_VALID.
8587 : * </li>
8588 : * </ul>
8589 : *
8590 : * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
8591 : * dataset, with the same name as the main dataset and suffixed with .msk,
8592 : * with either one band (in the GMF_PER_DATASET case), or as many bands as the
8593 : * main dataset.
8594 : * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8595 : * level, where xx matches the band number of a band of the main dataset. The
8596 : * value of those items is a combination of the flags GMF_ALL_VALID,
8597 : * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
8598 : * a band, then the other rules explained above will be used to generate a
8599 : * on-the-fly mask band.
8600 : * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
8601 : *
8602 : * This method is the same as the C function GDALGetMaskFlags().
8603 : *
8604 : * @since GDAL 1.5.0
8605 : *
8606 : * @return a valid mask band.
8607 : *
8608 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8609 : *
8610 : */
8611 154437 : int GDALRasterBand::GetMaskFlags()
8612 :
8613 : {
8614 : // If we don't have a band yet, force this now so that the masks value
8615 : // will be initialized.
8616 :
8617 154437 : if (poMask == nullptr)
8618 96156 : GetMaskBand();
8619 :
8620 154435 : return nMaskFlags;
8621 : }
8622 :
8623 : /************************************************************************/
8624 : /* GDALGetMaskFlags() */
8625 : /************************************************************************/
8626 :
8627 : /**
8628 : * \brief Return the status flags of the mask band associated with the band.
8629 : *
8630 : * @see GDALRasterBand::GetMaskFlags()
8631 : */
8632 :
8633 7077 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
8634 :
8635 : {
8636 7077 : VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
8637 :
8638 7077 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8639 7077 : return poBand->GetMaskFlags();
8640 : }
8641 :
8642 : /************************************************************************/
8643 : /* InvalidateMaskBand() */
8644 : /************************************************************************/
8645 :
8646 : //! @cond Doxygen_Suppress
8647 1917410 : void GDALRasterBand::InvalidateMaskBand()
8648 : {
8649 1917410 : poMask.reset();
8650 1917400 : nMaskFlags = 0;
8651 1917400 : }
8652 :
8653 : //! @endcond
8654 :
8655 : /************************************************************************/
8656 : /* CreateMaskBand() */
8657 : /************************************************************************/
8658 :
8659 : /**
8660 : * \brief Adds a mask band to the current band
8661 : *
8662 : * The default implementation of the CreateMaskBand() method is implemented
8663 : * based on similar rules to the .ovr handling implemented using the
8664 : * GDALDefaultOverviews object. A TIFF file with the extension .msk will
8665 : * be created with the same basename as the original file, and it will have
8666 : * as many bands as the original image (or just one for GMF_PER_DATASET).
8667 : * The mask images will be deflate compressed tiled images with the same
8668 : * block size as the original image if possible.
8669 : * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
8670 : * level, where xx matches the band number of a band of the main dataset. The
8671 : * value of those items will be the one of the nFlagsIn parameter.
8672 : *
8673 : * Note that if you got a mask band with a previous call to GetMaskBand(),
8674 : * it might be invalidated by CreateMaskBand(). So you have to call
8675 : * GetMaskBand() again.
8676 : *
8677 : * This method is the same as the C function GDALCreateMaskBand().
8678 : *
8679 : * @since GDAL 1.5.0
8680 : *
8681 : * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
8682 : *
8683 : * @return CE_None on success or CE_Failure on an error.
8684 : *
8685 : * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
8686 : * @see GDALDataset::CreateMaskBand()
8687 : *
8688 : */
8689 :
8690 10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
8691 :
8692 : {
8693 10 : if (poDS != nullptr && poDS->oOvManager.IsInitialized())
8694 : {
8695 10 : const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
8696 10 : if (eErr != CE_None)
8697 1 : return eErr;
8698 :
8699 9 : InvalidateMaskBand();
8700 :
8701 9 : return CE_None;
8702 : }
8703 :
8704 0 : ReportError(CE_Failure, CPLE_NotSupported,
8705 : "CreateMaskBand() not supported for this band.");
8706 :
8707 0 : return CE_Failure;
8708 : }
8709 :
8710 : /************************************************************************/
8711 : /* GDALCreateMaskBand() */
8712 : /************************************************************************/
8713 :
8714 : /**
8715 : * \brief Adds a mask band to the current band
8716 : *
8717 : * @see GDALRasterBand::CreateMaskBand()
8718 : */
8719 :
8720 33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
8721 :
8722 : {
8723 33 : VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
8724 :
8725 33 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8726 33 : return poBand->CreateMaskBand(nFlags);
8727 : }
8728 :
8729 : /************************************************************************/
8730 : /* IsMaskBand() */
8731 : /************************************************************************/
8732 :
8733 : /**
8734 : * \brief Returns whether a band is a mask band.
8735 : *
8736 : * Mask band must be understood in the broad term: it can be a per-dataset
8737 : * mask band, an alpha band, or an implicit mask band.
8738 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8739 : *
8740 : * This method is the same as the C function GDALIsMaskBand().
8741 : *
8742 : * @return true if the band is a mask band.
8743 : *
8744 : * @see GDALDataset::CreateMaskBand()
8745 : *
8746 : * @since GDAL 3.5.0
8747 : *
8748 : */
8749 :
8750 444 : bool GDALRasterBand::IsMaskBand() const
8751 : {
8752 : // The GeoTIFF driver, among others, override this method to
8753 : // also handle external .msk bands.
8754 444 : return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
8755 444 : GCI_AlphaBand;
8756 : }
8757 :
8758 : /************************************************************************/
8759 : /* GDALIsMaskBand() */
8760 : /************************************************************************/
8761 :
8762 : /**
8763 : * \brief Returns whether a band is a mask band.
8764 : *
8765 : * Mask band must be understood in the broad term: it can be a per-dataset
8766 : * mask band, an alpha band, or an implicit mask band.
8767 : * Typically the return of GetMaskBand()->IsMaskBand() should be true.
8768 : *
8769 : * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
8770 : *
8771 : * @return true if the band is a mask band.
8772 : *
8773 : * @see GDALRasterBand::IsMaskBand()
8774 : *
8775 : * @since GDAL 3.5.0
8776 : *
8777 : */
8778 :
8779 37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
8780 :
8781 : {
8782 37 : VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
8783 :
8784 37 : const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
8785 37 : return poBand->IsMaskBand();
8786 : }
8787 :
8788 : /************************************************************************/
8789 : /* GetMaskValueRange() */
8790 : /************************************************************************/
8791 :
8792 : /**
8793 : * \brief Returns the range of values that a mask band can take.
8794 : *
8795 : * @return the range of values that a mask band can take.
8796 : *
8797 : * @since GDAL 3.5.0
8798 : *
8799 : */
8800 :
8801 0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
8802 : {
8803 0 : return GMVR_UNKNOWN;
8804 : }
8805 :
8806 : /************************************************************************/
8807 : /* GetIndexColorTranslationTo() */
8808 : /************************************************************************/
8809 :
8810 : /**
8811 : * \brief Compute translation table for color tables.
8812 : *
8813 : * When the raster band has a palette index, it may be useful to compute
8814 : * the "translation" of this palette to the palette of another band.
8815 : * The translation tries to do exact matching first, and then approximate
8816 : * matching if no exact matching is possible.
8817 : * This method returns a table such that table[i] = j where i is an index
8818 : * of the 'this' rasterband and j the corresponding index for the reference
8819 : * rasterband.
8820 : *
8821 : * This method is thought as internal to GDAL and is used for drivers
8822 : * like RPFTOC.
8823 : *
8824 : * The implementation only supports 1-byte palette rasterbands.
8825 : *
8826 : * @param poReferenceBand the raster band
8827 : * @param pTranslationTable an already allocated translation table (at least 256
8828 : * bytes), or NULL to let the method allocate it
8829 : * @param pApproximateMatching a pointer to a flag that is set if the matching
8830 : * is approximate. May be NULL.
8831 : *
8832 : * @return a translation table if the two bands are palette index and that they
8833 : * do not match or NULL in other cases. The table must be freed with CPLFree if
8834 : * NULL was passed for pTranslationTable.
8835 : */
8836 :
8837 : unsigned char *
8838 4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
8839 : unsigned char *pTranslationTable,
8840 : int *pApproximateMatching)
8841 : {
8842 4 : if (poReferenceBand == nullptr)
8843 0 : return nullptr;
8844 :
8845 : // cppcheck-suppress knownConditionTrueFalse
8846 4 : if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
8847 : // cppcheck-suppress knownConditionTrueFalse
8848 4 : GetColorInterpretation() == GCI_PaletteIndex &&
8849 12 : poReferenceBand->GetRasterDataType() == GDT_Byte &&
8850 4 : GetRasterDataType() == GDT_Byte)
8851 : {
8852 4 : const GDALColorTable *srcColorTable = GetColorTable();
8853 4 : GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
8854 4 : if (srcColorTable != nullptr && destColorTable != nullptr)
8855 : {
8856 4 : const int nEntries = srcColorTable->GetColorEntryCount();
8857 4 : const int nRefEntries = destColorTable->GetColorEntryCount();
8858 :
8859 4 : int bHasNoDataValueSrc = FALSE;
8860 4 : double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
8861 4 : if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
8862 4 : dfNoDataValueSrc <= 255 &&
8863 4 : dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
8864 0 : bHasNoDataValueSrc = FALSE;
8865 4 : const int noDataValueSrc =
8866 4 : bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
8867 :
8868 4 : int bHasNoDataValueRef = FALSE;
8869 : const double dfNoDataValueRef =
8870 4 : poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
8871 4 : if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
8872 3 : dfNoDataValueRef <= 255 &&
8873 3 : dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
8874 1 : bHasNoDataValueRef = FALSE;
8875 4 : const int noDataValueRef =
8876 4 : bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
8877 :
8878 4 : bool samePalette = false;
8879 :
8880 4 : if (pApproximateMatching)
8881 3 : *pApproximateMatching = FALSE;
8882 :
8883 4 : if (nEntries == nRefEntries &&
8884 3 : bHasNoDataValueSrc == bHasNoDataValueRef &&
8885 3 : (bHasNoDataValueSrc == FALSE ||
8886 : noDataValueSrc == noDataValueRef))
8887 : {
8888 3 : samePalette = true;
8889 654 : for (int i = 0; i < nEntries; ++i)
8890 : {
8891 651 : if (noDataValueSrc == i)
8892 3 : continue;
8893 : const GDALColorEntry *entry =
8894 648 : srcColorTable->GetColorEntry(i);
8895 : const GDALColorEntry *entryRef =
8896 648 : destColorTable->GetColorEntry(i);
8897 648 : if (entry->c1 != entryRef->c1 ||
8898 648 : entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
8899 : {
8900 0 : samePalette = false;
8901 : }
8902 : }
8903 : }
8904 :
8905 4 : if (!samePalette)
8906 : {
8907 1 : if (pTranslationTable == nullptr)
8908 : {
8909 : pTranslationTable = static_cast<unsigned char *>(
8910 1 : VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
8911 1 : if (pTranslationTable == nullptr)
8912 1 : return nullptr;
8913 : }
8914 :
8915 : // Trying to remap the product palette on the subdataset
8916 : // palette.
8917 5 : for (int i = 0; i < nEntries; ++i)
8918 : {
8919 4 : if (bHasNoDataValueSrc && bHasNoDataValueRef &&
8920 : noDataValueSrc == i)
8921 0 : continue;
8922 : const GDALColorEntry *entry =
8923 4 : srcColorTable->GetColorEntry(i);
8924 4 : bool bMatchFound = false;
8925 13 : for (int j = 0; j < nRefEntries; ++j)
8926 : {
8927 10 : if (bHasNoDataValueRef && noDataValueRef == j)
8928 0 : continue;
8929 : const GDALColorEntry *entryRef =
8930 10 : destColorTable->GetColorEntry(j);
8931 10 : if (entry->c1 == entryRef->c1 &&
8932 2 : entry->c2 == entryRef->c2 &&
8933 2 : entry->c3 == entryRef->c3)
8934 : {
8935 1 : pTranslationTable[i] =
8936 : static_cast<unsigned char>(j);
8937 1 : bMatchFound = true;
8938 1 : break;
8939 : }
8940 : }
8941 4 : if (!bMatchFound)
8942 : {
8943 : // No exact match. Looking for closest color now.
8944 3 : int best_j = 0;
8945 3 : int best_distance = 0;
8946 3 : if (pApproximateMatching)
8947 0 : *pApproximateMatching = TRUE;
8948 12 : for (int j = 0; j < nRefEntries; ++j)
8949 : {
8950 : const GDALColorEntry *entryRef =
8951 9 : destColorTable->GetColorEntry(j);
8952 9 : int distance = (entry->c1 - entryRef->c1) *
8953 9 : (entry->c1 - entryRef->c1) +
8954 9 : (entry->c2 - entryRef->c2) *
8955 9 : (entry->c2 - entryRef->c2) +
8956 9 : (entry->c3 - entryRef->c3) *
8957 9 : (entry->c3 - entryRef->c3);
8958 9 : if (j == 0 || distance < best_distance)
8959 : {
8960 7 : best_j = j;
8961 7 : best_distance = distance;
8962 : }
8963 : }
8964 3 : pTranslationTable[i] =
8965 : static_cast<unsigned char>(best_j);
8966 : }
8967 : }
8968 1 : if (bHasNoDataValueRef && bHasNoDataValueSrc)
8969 0 : pTranslationTable[noDataValueSrc] =
8970 : static_cast<unsigned char>(noDataValueRef);
8971 :
8972 1 : return pTranslationTable;
8973 : }
8974 : }
8975 : }
8976 3 : return nullptr;
8977 : }
8978 :
8979 : /************************************************************************/
8980 : /* SetFlushBlockErr() */
8981 : /************************************************************************/
8982 :
8983 : /**
8984 : * \brief Store that an error occurred while writing a dirty block.
8985 : *
8986 : * This function stores the fact that an error occurred while writing a dirty
8987 : * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
8988 : * flushed when the block cache get full, it is not convenient/possible to
8989 : * report that a dirty block could not be written correctly. This function
8990 : * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
8991 : * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
8992 : * places where the user can easily match the error with the relevant dataset.
8993 : */
8994 :
8995 0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
8996 : {
8997 0 : eFlushBlockErr = eErr;
8998 0 : }
8999 :
9000 : /************************************************************************/
9001 : /* IncDirtyBlocks() */
9002 : /************************************************************************/
9003 :
9004 : /**
9005 : * \brief Increment/decrement the number of dirty blocks
9006 : */
9007 :
9008 794650 : void GDALRasterBand::IncDirtyBlocks(int nInc)
9009 : {
9010 794650 : if (poBandBlockCache)
9011 794651 : poBandBlockCache->IncDirtyBlocks(nInc);
9012 794649 : }
9013 :
9014 : /************************************************************************/
9015 : /* ReportError() */
9016 : /************************************************************************/
9017 :
9018 : #ifndef DOXYGEN_XML
9019 : /**
9020 : * \brief Emits an error related to a raster band.
9021 : *
9022 : * This function is a wrapper for regular CPLError(). The only difference
9023 : * with CPLError() is that it prepends the error message with the dataset
9024 : * name and the band number.
9025 : *
9026 : * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
9027 : * @param err_no the error number (CPLE_*) from cpl_error.h.
9028 : * @param fmt a printf() style format string. Any additional arguments
9029 : * will be treated as arguments to fill in this format in a manner
9030 : * similar to printf().
9031 : *
9032 : * @since GDAL 1.9.0
9033 : */
9034 :
9035 2474 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
9036 : const char *fmt, ...) const
9037 : {
9038 : va_list args;
9039 :
9040 2474 : va_start(args, fmt);
9041 :
9042 2474 : const char *pszDSName = poDS ? poDS->GetDescription() : "";
9043 2474 : pszDSName = CPLGetFilename(pszDSName);
9044 2474 : if (pszDSName[0] != '\0')
9045 : {
9046 2402 : CPLError(eErrClass, err_no, "%s",
9047 4804 : CPLString()
9048 2402 : .Printf("%s, band %d: ", pszDSName, GetBand())
9049 4804 : .append(CPLString().vPrintf(fmt, args))
9050 : .c_str());
9051 : }
9052 : else
9053 : {
9054 72 : CPLErrorV(eErrClass, err_no, fmt, args);
9055 : }
9056 :
9057 2474 : va_end(args);
9058 2474 : }
9059 : #endif
9060 :
9061 : /************************************************************************/
9062 : /* GetVirtualMemAuto() */
9063 : /************************************************************************/
9064 :
9065 : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
9066 : *
9067 : * Only supported on Linux and Unix systems with mmap() for now.
9068 : *
9069 : * This method allows creating a virtual memory object for a GDALRasterBand,
9070 : * that exposes the whole image data as a virtual array.
9071 : *
9072 : * The default implementation relies on GDALRasterBandGetVirtualMem(), but
9073 : * specialized implementation, such as for raw files, may also directly use
9074 : * mechanisms of the operating system to create a view of the underlying file
9075 : * into virtual memory ( CPLVirtualMemFileMapNew() )
9076 : *
9077 : * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
9078 : * offer a specialized implementation with direct file mapping, provided that
9079 : * some requirements are met :
9080 : * - for all drivers, the dataset must be backed by a "real" file in the file
9081 : * system, and the byte ordering of multi-byte datatypes (Int16, etc.)
9082 : * must match the native ordering of the CPU.
9083 : * - in addition, for the GeoTIFF driver, the GeoTIFF file must be
9084 : * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
9085 : * the file in sequential order, and be equally spaced (which is generally the
9086 : * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
9087 : * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
9088 : *
9089 : * The pointer returned remains valid until CPLVirtualMemFree() is called.
9090 : * CPLVirtualMemFree() must be called before the raster band object is
9091 : * destroyed.
9092 : *
9093 : * If p is such a pointer and base_type the type matching
9094 : * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
9095 : * accessed with
9096 : * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
9097 : *
9098 : * This method is the same as the C GDALGetVirtualMemAuto() function.
9099 : *
9100 : * @param eRWFlag Either GF_Read to read the band, or GF_Write to
9101 : * read/write the band.
9102 : *
9103 : * @param pnPixelSpace Output parameter giving the byte offset from the start of
9104 : * one pixel value in the buffer to the start of the next pixel value within a
9105 : * scanline.
9106 : *
9107 : * @param pnLineSpace Output parameter giving the byte offset from the start of
9108 : * one scanline in the buffer to the start of the next.
9109 : *
9110 : * @param papszOptions NULL terminated list of options.
9111 : * If a specialized implementation exists, defining
9112 : * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
9113 : * used. On the contrary, starting with GDAL 2.2, defining
9114 : * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
9115 : * being used (thus only allowing efficient implementations to be used). When
9116 : * requiring or falling back to the default implementation, the following
9117 : * options are available : CACHE_SIZE (in bytes, defaults to
9118 : * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
9119 : * to FALSE)
9120 : *
9121 : * @return a virtual memory object that must be unreferenced by
9122 : * CPLVirtualMemFree(), or NULL in case of failure.
9123 : *
9124 : * @since GDAL 1.11
9125 : */
9126 :
9127 9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
9128 : int *pnPixelSpace,
9129 : GIntBig *pnLineSpace,
9130 : char **papszOptions)
9131 : {
9132 9 : const char *pszImpl = CSLFetchNameValueDef(
9133 : papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
9134 9 : if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
9135 8 : EQUAL(pszImpl, "FALSE"))
9136 : {
9137 1 : return nullptr;
9138 : }
9139 :
9140 8 : const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
9141 8 : const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
9142 8 : if (pnPixelSpace)
9143 8 : *pnPixelSpace = nPixelSpace;
9144 8 : if (pnLineSpace)
9145 8 : *pnLineSpace = nLineSpace;
9146 : const size_t nCacheSize =
9147 8 : atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
9148 : const size_t nPageSizeHint =
9149 8 : atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
9150 8 : const bool bSingleThreadUsage = CPLTestBool(
9151 : CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
9152 8 : return GDALRasterBandGetVirtualMem(
9153 : GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
9154 : nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
9155 : nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
9156 8 : papszOptions);
9157 : }
9158 :
9159 : /************************************************************************/
9160 : /* GDALGetVirtualMemAuto() */
9161 : /************************************************************************/
9162 :
9163 : /**
9164 : * \brief Create a CPLVirtualMem object from a GDAL raster band object.
9165 : *
9166 : * @see GDALRasterBand::GetVirtualMemAuto()
9167 : */
9168 :
9169 31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
9170 : int *pnPixelSpace, GIntBig *pnLineSpace,
9171 : CSLConstList papszOptions)
9172 : {
9173 31 : VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
9174 :
9175 31 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9176 :
9177 31 : return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
9178 31 : const_cast<char **>(papszOptions));
9179 : }
9180 :
9181 : /************************************************************************/
9182 : /* GDALGetDataCoverageStatus() */
9183 : /************************************************************************/
9184 :
9185 : /**
9186 : * \brief Get the coverage status of a sub-window of the raster.
9187 : *
9188 : * Returns whether a sub-window of the raster contains only data, only empty
9189 : * blocks or a mix of both. This function can be used to determine quickly
9190 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9191 : * be sparse.
9192 : *
9193 : * Empty blocks are blocks that are generally not physically present in the
9194 : * file, and when read through GDAL, contain only pixels whose value is the
9195 : * nodata value when it is set, or whose value is 0 when the nodata value is
9196 : * not set.
9197 : *
9198 : * The query is done in an efficient way without reading the actual pixel
9199 : * values. If not possible, or not implemented at all by the driver,
9200 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9201 : * be returned.
9202 : *
9203 : * The values that can be returned by the function are the following,
9204 : * potentially combined with the binary or operator :
9205 : * <ul>
9206 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9207 : * GetDataCoverageStatus(). This flag should be returned together with
9208 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9209 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9210 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9211 : * the queried window. This is typically identified by the concept of missing
9212 : * block in formats that supports it.
9213 : * </li>
9214 : * </ul>
9215 : *
9216 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9217 : * should be interpreted more as hint of potential presence of data. For example
9218 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9219 : * nodata value), instead of using the missing block mechanism,
9220 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9221 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9222 : *
9223 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9224 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9225 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9226 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9227 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9228 : * the function will exit, so that you can potentially refine the requested area
9229 : * to find which particular region(s) have missing blocks.
9230 : *
9231 : * @see GDALRasterBand::GetDataCoverageStatus()
9232 : *
9233 : * @param hBand raster band
9234 : *
9235 : * @param nXOff The pixel offset to the top left corner of the region
9236 : * of the band to be queried. This would be zero to start from the left side.
9237 : *
9238 : * @param nYOff The line offset to the top left corner of the region
9239 : * of the band to be queried. This would be zero to start from the top.
9240 : *
9241 : * @param nXSize The width of the region of the band to be queried in pixels.
9242 : *
9243 : * @param nYSize The height of the region of the band to be queried in lines.
9244 : *
9245 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9246 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9247 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9248 : * as the computation of the coverage matches the mask, the computation will be
9249 : * stopped. *pdfDataPct will not be valid in that case.
9250 : *
9251 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9252 : * to the (approximate) percentage in [0,100] of pixels in the queried
9253 : * sub-window that have valid values. The implementation might not always be
9254 : * able to compute it, in which case it will be set to a negative value.
9255 : *
9256 : * @return a binary-or'ed combination of possible values
9257 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9258 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9259 : *
9260 : * @note Added in GDAL 2.2
9261 : */
9262 :
9263 26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
9264 : int nYOff, int nXSize, int nYSize,
9265 : int nMaskFlagStop, double *pdfDataPct)
9266 : {
9267 26 : VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
9268 : GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
9269 :
9270 26 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
9271 :
9272 26 : return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
9273 26 : nMaskFlagStop, pdfDataPct);
9274 : }
9275 :
9276 : /************************************************************************/
9277 : /* GetDataCoverageStatus() */
9278 : /************************************************************************/
9279 :
9280 : /**
9281 : * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
9282 : * int nYOff,
9283 : * int nXSize,
9284 : * int nYSize,
9285 : * int nMaskFlagStop,
9286 : * double* pdfDataPct)
9287 : * \brief Get the coverage status of a sub-window of the raster.
9288 : *
9289 : * Returns whether a sub-window of the raster contains only data, only empty
9290 : * blocks or a mix of both. This function can be used to determine quickly
9291 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9292 : * be sparse.
9293 : *
9294 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9295 : * value when it is set, or whose value is 0 when the nodata value is not set.
9296 : *
9297 : * The query is done in an efficient way without reading the actual pixel
9298 : * values. If not possible, or not implemented at all by the driver,
9299 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9300 : * be returned.
9301 : *
9302 : * The values that can be returned by the function are the following,
9303 : * potentially combined with the binary or operator :
9304 : * <ul>
9305 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9306 : * GetDataCoverageStatus(). This flag should be returned together with
9307 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9308 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9309 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9310 : * the queried window. This is typically identified by the concept of missing
9311 : * block in formats that supports it.
9312 : * </li>
9313 : * </ul>
9314 : *
9315 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9316 : * should be interpreted more as hint of potential presence of data. For example
9317 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9318 : * nodata value), instead of using the missing block mechanism,
9319 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9320 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9321 : *
9322 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9323 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9324 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9325 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9326 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9327 : * the function will exit, so that you can potentially refine the requested area
9328 : * to find which particular region(s) have missing blocks.
9329 : *
9330 : * @see GDALGetDataCoverageStatus()
9331 : *
9332 : * @param nXOff The pixel offset to the top left corner of the region
9333 : * of the band to be queried. This would be zero to start from the left side.
9334 : *
9335 : * @param nYOff The line offset to the top left corner of the region
9336 : * of the band to be queried. This would be zero to start from the top.
9337 : *
9338 : * @param nXSize The width of the region of the band to be queried in pixels.
9339 : *
9340 : * @param nYSize The height of the region of the band to be queried in lines.
9341 : *
9342 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9343 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9344 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9345 : * as the computation of the coverage matches the mask, the computation will be
9346 : * stopped. *pdfDataPct will not be valid in that case.
9347 : *
9348 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9349 : * to the (approximate) percentage in [0,100] of pixels in the queried
9350 : * sub-window that have valid values. The implementation might not always be
9351 : * able to compute it, in which case it will be set to a negative value.
9352 : *
9353 : * @return a binary-or'ed combination of possible values
9354 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9355 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9356 : *
9357 : * @note Added in GDAL 2.2
9358 : */
9359 :
9360 : /**
9361 : * \brief Get the coverage status of a sub-window of the raster.
9362 : *
9363 : * Returns whether a sub-window of the raster contains only data, only empty
9364 : * blocks or a mix of both. This function can be used to determine quickly
9365 : * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
9366 : * be sparse.
9367 : *
9368 : * Empty blocks are blocks that contain only pixels whose value is the nodata
9369 : * value when it is set, or whose value is 0 when the nodata value is not set.
9370 : *
9371 : * The query is done in an efficient way without reading the actual pixel
9372 : * values. If not possible, or not implemented at all by the driver,
9373 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
9374 : * be returned.
9375 : *
9376 : * The values that can be returned by the function are the following,
9377 : * potentially combined with the binary or operator :
9378 : * <ul>
9379 : * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
9380 : * GetDataCoverageStatus(). This flag should be returned together with
9381 : * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
9382 : * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
9383 : * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
9384 : * the queried window. This is typically identified by the concept of missing
9385 : * block in formats that supports it.
9386 : * </li>
9387 : * </ul>
9388 : *
9389 : * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
9390 : * should be interpreted more as hint of potential presence of data. For example
9391 : * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
9392 : * nodata value), instead of using the missing block mechanism,
9393 : * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
9394 : * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
9395 : *
9396 : * The nMaskFlagStop should be generally set to 0. It can be set to a
9397 : * binary-or'ed mask of the above mentioned values to enable a quick exiting of
9398 : * the function as soon as the computed mask matches the nMaskFlagStop. For
9399 : * example, you can issue a request on the whole raster with nMaskFlagStop =
9400 : * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
9401 : * the function will exit, so that you can potentially refine the requested area
9402 : * to find which particular region(s) have missing blocks.
9403 : *
9404 : * @see GDALGetDataCoverageStatus()
9405 : *
9406 : * @param nXOff The pixel offset to the top left corner of the region
9407 : * of the band to be queried. This would be zero to start from the left side.
9408 : *
9409 : * @param nYOff The line offset to the top left corner of the region
9410 : * of the band to be queried. This would be zero to start from the top.
9411 : *
9412 : * @param nXSize The width of the region of the band to be queried in pixels.
9413 : *
9414 : * @param nYSize The height of the region of the band to be queried in lines.
9415 : *
9416 : * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
9417 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9418 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
9419 : * as the computation of the coverage matches the mask, the computation will be
9420 : * stopped. *pdfDataPct will not be valid in that case.
9421 : *
9422 : * @param pdfDataPct Optional output parameter whose pointed value will be set
9423 : * to the (approximate) percentage in [0,100] of pixels in the queried
9424 : * sub-window that have valid values. The implementation might not always be
9425 : * able to compute it, in which case it will be set to a negative value.
9426 : *
9427 : * @return a binary-or'ed combination of possible values
9428 : * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
9429 : * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
9430 : *
9431 : * @note Added in GDAL 2.2
9432 : */
9433 :
9434 4658 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
9435 : int nYSize, int nMaskFlagStop,
9436 : double *pdfDataPct)
9437 : {
9438 4658 : if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
9439 4658 : nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
9440 4658 : nYOff + nYSize > nRasterYSize)
9441 : {
9442 0 : CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
9443 0 : if (pdfDataPct)
9444 0 : *pdfDataPct = 0.0;
9445 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9446 0 : GDAL_DATA_COVERAGE_STATUS_EMPTY;
9447 : }
9448 4658 : return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
9449 4658 : pdfDataPct);
9450 : }
9451 :
9452 : /************************************************************************/
9453 : /* IGetDataCoverageStatus() */
9454 : /************************************************************************/
9455 :
9456 684 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
9457 : int /*nXSize*/, int /*nYSize*/,
9458 : int /*nMaskFlagStop*/,
9459 : double *pdfDataPct)
9460 : {
9461 684 : if (pdfDataPct != nullptr)
9462 0 : *pdfDataPct = 100.0;
9463 : return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
9464 684 : GDAL_DATA_COVERAGE_STATUS_DATA;
9465 : }
9466 :
9467 : //! @cond Doxygen_Suppress
9468 : /************************************************************************/
9469 : /* EnterReadWrite() */
9470 : /************************************************************************/
9471 :
9472 7783200 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
9473 : {
9474 7783200 : if (poDS != nullptr)
9475 7024510 : return poDS->EnterReadWrite(eRWFlag);
9476 758693 : return FALSE;
9477 : }
9478 :
9479 : /************************************************************************/
9480 : /* LeaveReadWrite() */
9481 : /************************************************************************/
9482 :
9483 1128450 : void GDALRasterBand::LeaveReadWrite()
9484 : {
9485 1128450 : if (poDS != nullptr)
9486 1128290 : poDS->LeaveReadWrite();
9487 1128530 : }
9488 :
9489 : /************************************************************************/
9490 : /* InitRWLock() */
9491 : /************************************************************************/
9492 :
9493 3977220 : void GDALRasterBand::InitRWLock()
9494 : {
9495 3977220 : if (poDS != nullptr)
9496 3976810 : poDS->InitRWLock();
9497 3977220 : }
9498 :
9499 : //! @endcond
9500 :
9501 : // clang-format off
9502 :
9503 : /**
9504 : * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
9505 : * \brief Set metadata.
9506 : *
9507 : * CAUTION: depending on the format, older values of the updated information
9508 : * might still be found in the file in a "ghost" state, even if no longer
9509 : * accessible through the GDAL API. This is for example the case of the GTiff
9510 : * format (this is not a exhaustive list)
9511 : *
9512 : * The C function GDALSetMetadata() does the same thing as this method.
9513 : *
9514 : * @param papszMetadata the metadata in name=value string list format to
9515 : * apply.
9516 : * @param pszDomain the domain of interest. Use "" or NULL for the default
9517 : * domain.
9518 : * @return CE_None on success, CE_Failure on failure and CE_Warning if the
9519 : * metadata has been accepted, but is likely not maintained persistently
9520 : * by the underlying object between sessions.
9521 : */
9522 :
9523 : /**
9524 : * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
9525 : * \brief Set single metadata item.
9526 : *
9527 : * CAUTION: depending on the format, older values of the updated information
9528 : * might still be found in the file in a "ghost" state, even if no longer
9529 : * accessible through the GDAL API. This is for example the case of the GTiff
9530 : * format (this is not a exhaustive list)
9531 : *
9532 : * The C function GDALSetMetadataItem() does the same thing as this method.
9533 : *
9534 : * @param pszName the key for the metadata item to fetch.
9535 : * @param pszValue the value to assign to the key.
9536 : * @param pszDomain the domain to set within, use NULL for the default domain.
9537 : *
9538 : * @return CE_None on success, or an error code on failure.
9539 : */
9540 :
9541 : // clang-format on
9542 :
9543 : //! @cond Doxygen_Suppress
9544 : /************************************************************************/
9545 : /* EnablePixelTypeSignedByteWarning() */
9546 : /************************************************************************/
9547 :
9548 156756 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
9549 : {
9550 156756 : m_bEnablePixelTypeSignedByteWarning = b;
9551 156756 : }
9552 :
9553 4884 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
9554 : {
9555 4884 : GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
9556 4884 : }
9557 :
9558 : //! @endcond
9559 :
9560 : /************************************************************************/
9561 : /* GetMetadataItem() */
9562 : /************************************************************************/
9563 :
9564 620065 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
9565 : const char *pszDomain)
9566 : {
9567 : // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
9568 620065 : if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
9569 462121 : pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
9570 321691 : EQUAL(pszName, "PIXELTYPE"))
9571 : {
9572 2 : CPLError(CE_Warning, CPLE_AppDefined,
9573 : "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
9574 : "used to signal signed 8-bit raster. Change your code to "
9575 : "test for the new GDT_Int8 data type instead.");
9576 : }
9577 620065 : return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
9578 : }
9579 :
9580 : /************************************************************************/
9581 : /* WindowIterator */
9582 : /************************************************************************/
9583 :
9584 : //! @cond Doxygen_Suppress
9585 :
9586 442 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
9587 : int nRasterYSize,
9588 : int nBlockXSize, int nBlockYSize,
9589 442 : int nRow, int nCol)
9590 : : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
9591 : m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
9592 442 : m_col(nCol)
9593 : {
9594 442 : }
9595 :
9596 553 : bool GDALRasterBand::WindowIterator::operator==(
9597 : const WindowIterator &other) const
9598 : {
9599 192 : return m_row == other.m_row && m_col == other.m_col &&
9600 192 : m_nRasterXSize == other.m_nRasterXSize &&
9601 192 : m_nRasterYSize == other.m_nRasterYSize &&
9602 937 : m_nBlockXSize == other.m_nBlockXSize &&
9603 745 : m_nBlockYSize == other.m_nBlockYSize;
9604 : }
9605 :
9606 527 : bool GDALRasterBand::WindowIterator::operator!=(
9607 : const WindowIterator &other) const
9608 : {
9609 527 : return !(*this == other);
9610 : }
9611 :
9612 : GDALRasterBand::WindowIterator::value_type
9613 360 : GDALRasterBand::WindowIterator::operator*() const
9614 : {
9615 : GDALRasterWindow ret;
9616 360 : ret.nXOff = m_col * m_nBlockXSize;
9617 360 : ret.nYOff = m_row * m_nBlockYSize;
9618 360 : ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
9619 360 : ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
9620 :
9621 360 : return ret;
9622 : }
9623 :
9624 358 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
9625 : {
9626 358 : m_col++;
9627 358 : if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
9628 : {
9629 352 : m_col = 0;
9630 352 : m_row++;
9631 : }
9632 358 : return *this;
9633 : }
9634 :
9635 234 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
9636 234 : const GDALRasterBand &band)
9637 234 : : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
9638 234 : m_nBlockXSize(-1), m_nBlockYSize(-1)
9639 : {
9640 : // If invalid block size is reported, just use a value of 1.
9641 234 : CPLErrorStateBackuper state(CPLQuietErrorHandler);
9642 : #ifdef CSA_BUILD
9643 : assert(this);
9644 : #endif
9645 234 : band.GetBlockSize(&m_nBlockXSize, &m_nBlockYSize);
9646 234 : m_nBlockXSize = std::max<int>(m_nBlockXSize, 1);
9647 234 : m_nBlockYSize = std::max<int>(m_nBlockYSize, 1);
9648 234 : }
9649 :
9650 : GDALRasterBand::WindowIterator
9651 207 : GDALRasterBand::WindowIteratorWrapper::begin() const
9652 : {
9653 207 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9654 207 : m_nBlockYSize, 0, 0);
9655 : }
9656 :
9657 : GDALRasterBand::WindowIterator
9658 207 : GDALRasterBand::WindowIteratorWrapper::end() const
9659 : {
9660 207 : return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
9661 207 : m_nBlockYSize,
9662 207 : DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
9663 : }
9664 :
9665 : //! @endcond
9666 :
9667 : /** Return an object whose begin() and end() methods can be used to iterate
9668 : * over a GDALRasterWindow for each block in this raster band. The iteration
9669 : * order is from left to right, then from top to bottom.
9670 : *
9671 : \code{.cpp}
9672 : std::vector<double> pixelValues;
9673 : for (const auto& window : poBand->IterateWindows()) {
9674 : CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
9675 : window.nXSize, window.nYSize);
9676 : // check eErr
9677 : }
9678 : \endcode
9679 : *
9680 : *
9681 : * @since GDAL 3.12
9682 : */
9683 234 : GDALRasterBand::WindowIteratorWrapper GDALRasterBand::IterateWindows() const
9684 : {
9685 234 : return WindowIteratorWrapper(*this);
9686 : }
9687 :
9688 : /************************************************************************/
9689 : /* GDALMDArrayFromRasterBand */
9690 : /************************************************************************/
9691 :
9692 : class GDALMDArrayFromRasterBand final : public GDALMDArray
9693 : {
9694 : CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
9695 :
9696 : GDALDataset *m_poDS;
9697 : GDALRasterBand *m_poBand;
9698 : GDALExtendedDataType m_dt;
9699 : std::vector<std::shared_ptr<GDALDimension>> m_dims{};
9700 : std::string m_osUnit;
9701 : std::vector<GByte> m_pabyNoData{};
9702 : std::shared_ptr<GDALMDArray> m_varX{};
9703 : std::shared_ptr<GDALMDArray> m_varY{};
9704 : std::string m_osFilename{};
9705 :
9706 : bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
9707 : const size_t *count, const GInt64 *arrayStep,
9708 : const GPtrDiff_t *bufferStride,
9709 : const GDALExtendedDataType &bufferDataType,
9710 : void *pBuffer) const;
9711 :
9712 : protected:
9713 23 : GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
9714 46 : : GDALAbstractMDArray(std::string(),
9715 46 : std::string(poDS->GetDescription()) +
9716 : CPLSPrintf(" band %d", poBand->GetBand())),
9717 46 : GDALMDArray(std::string(),
9718 46 : std::string(poDS->GetDescription()) +
9719 : CPLSPrintf(" band %d", poBand->GetBand())),
9720 : m_poDS(poDS), m_poBand(poBand),
9721 : m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
9722 115 : m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
9723 : {
9724 23 : m_poDS->Reference();
9725 :
9726 23 : int bHasNoData = false;
9727 23 : if (m_poBand->GetRasterDataType() == GDT_Int64)
9728 : {
9729 0 : const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
9730 0 : if (bHasNoData)
9731 : {
9732 0 : m_pabyNoData.resize(m_dt.GetSize());
9733 0 : GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
9734 : m_dt.GetNumericDataType(), 0, 1);
9735 : }
9736 : }
9737 23 : else if (m_poBand->GetRasterDataType() == GDT_UInt64)
9738 : {
9739 0 : const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
9740 0 : if (bHasNoData)
9741 : {
9742 0 : m_pabyNoData.resize(m_dt.GetSize());
9743 0 : GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
9744 : m_dt.GetNumericDataType(), 0, 1);
9745 : }
9746 : }
9747 : else
9748 : {
9749 23 : const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
9750 23 : if (bHasNoData)
9751 : {
9752 1 : m_pabyNoData.resize(m_dt.GetSize());
9753 1 : GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
9754 : m_dt.GetNumericDataType(), 0, 1);
9755 : }
9756 : }
9757 :
9758 23 : const int nXSize = poBand->GetXSize();
9759 23 : const int nYSize = poBand->GetYSize();
9760 :
9761 23 : auto poSRS = m_poDS->GetSpatialRef();
9762 46 : std::string osTypeY;
9763 46 : std::string osTypeX;
9764 46 : std::string osDirectionY;
9765 46 : std::string osDirectionX;
9766 23 : if (poSRS && poSRS->GetAxesCount() == 2)
9767 : {
9768 21 : const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
9769 21 : OGRAxisOrientation eOrientation1 = OAO_Other;
9770 21 : poSRS->GetAxis(nullptr, 0, &eOrientation1);
9771 21 : OGRAxisOrientation eOrientation2 = OAO_Other;
9772 21 : poSRS->GetAxis(nullptr, 1, &eOrientation2);
9773 21 : if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
9774 : {
9775 5 : if (mapping == std::vector<int>{1, 2})
9776 : {
9777 5 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9778 5 : osDirectionY = "NORTH";
9779 5 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9780 5 : osDirectionX = "EAST";
9781 : }
9782 : }
9783 16 : else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
9784 : {
9785 16 : if (mapping == std::vector<int>{2, 1})
9786 : {
9787 16 : osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
9788 16 : osDirectionY = "NORTH";
9789 16 : osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
9790 16 : osDirectionX = "EAST";
9791 : }
9792 : }
9793 : }
9794 :
9795 115 : m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
9796 : "/", "Y", osTypeY, osDirectionY, nYSize),
9797 46 : std::make_shared<GDALDimensionWeakIndexingVar>(
9798 69 : "/", "X", osTypeX, osDirectionX, nXSize)};
9799 :
9800 23 : GDALGeoTransform gt;
9801 23 : if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
9802 : {
9803 44 : m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
9804 44 : gt[0], gt[1], 0.5);
9805 22 : m_dims[1]->SetIndexingVariable(m_varX);
9806 :
9807 44 : m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
9808 44 : gt[3], gt[5], 0.5);
9809 22 : m_dims[0]->SetIndexingVariable(m_varY);
9810 : }
9811 23 : }
9812 :
9813 : bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
9814 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9815 : const GDALExtendedDataType &bufferDataType,
9816 : void *pDstBuffer) const override;
9817 :
9818 1 : bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
9819 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9820 : const GDALExtendedDataType &bufferDataType,
9821 : const void *pSrcBuffer) override
9822 : {
9823 1 : return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
9824 : bufferStride, bufferDataType,
9825 1 : const_cast<void *>(pSrcBuffer));
9826 : }
9827 :
9828 : public:
9829 46 : ~GDALMDArrayFromRasterBand() override
9830 23 : {
9831 23 : m_poDS->ReleaseRef();
9832 46 : }
9833 :
9834 23 : static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
9835 : GDALRasterBand *poBand)
9836 : {
9837 : auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
9838 46 : new GDALMDArrayFromRasterBand(poDS, poBand)));
9839 23 : array->SetSelf(array);
9840 46 : return array;
9841 : }
9842 :
9843 2 : bool IsWritable() const override
9844 : {
9845 2 : return m_poDS->GetAccess() == GA_Update;
9846 : }
9847 :
9848 97 : const std::string &GetFilename() const override
9849 : {
9850 97 : return m_osFilename;
9851 : }
9852 :
9853 : const std::vector<std::shared_ptr<GDALDimension>> &
9854 299 : GetDimensions() const override
9855 : {
9856 299 : return m_dims;
9857 : }
9858 :
9859 138 : const GDALExtendedDataType &GetDataType() const override
9860 : {
9861 138 : return m_dt;
9862 : }
9863 :
9864 3 : const std::string &GetUnit() const override
9865 : {
9866 3 : return m_osUnit;
9867 : }
9868 :
9869 29 : const void *GetRawNoDataValue() const override
9870 : {
9871 29 : return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
9872 : }
9873 :
9874 2 : double GetOffset(bool *pbHasOffset,
9875 : GDALDataType *peStorageType) const override
9876 : {
9877 2 : int bHasOffset = false;
9878 2 : double dfRes = m_poBand->GetOffset(&bHasOffset);
9879 2 : if (pbHasOffset)
9880 2 : *pbHasOffset = CPL_TO_BOOL(bHasOffset);
9881 2 : if (peStorageType)
9882 1 : *peStorageType = GDT_Unknown;
9883 2 : return dfRes;
9884 : }
9885 :
9886 2 : double GetScale(bool *pbHasScale,
9887 : GDALDataType *peStorageType) const override
9888 : {
9889 2 : int bHasScale = false;
9890 2 : double dfRes = m_poBand->GetScale(&bHasScale);
9891 2 : if (pbHasScale)
9892 2 : *pbHasScale = CPL_TO_BOOL(bHasScale);
9893 2 : if (peStorageType)
9894 1 : *peStorageType = GDT_Unknown;
9895 2 : return dfRes;
9896 : }
9897 :
9898 84 : std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
9899 : {
9900 84 : auto poSrcSRS = m_poDS->GetSpatialRef();
9901 84 : if (!poSrcSRS)
9902 2 : return nullptr;
9903 164 : auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
9904 :
9905 164 : auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
9906 82 : constexpr int iYDim = 0;
9907 82 : constexpr int iXDim = 1;
9908 246 : for (auto &m : axisMapping)
9909 : {
9910 164 : if (m == 1)
9911 82 : m = iXDim + 1;
9912 82 : else if (m == 2)
9913 82 : m = iYDim + 1;
9914 : else
9915 0 : m = 0;
9916 : }
9917 82 : poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
9918 82 : return poSRS;
9919 : }
9920 :
9921 29 : std::vector<GUInt64> GetBlockSize() const override
9922 : {
9923 29 : int nBlockXSize = 0;
9924 29 : int nBlockYSize = 0;
9925 29 : m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
9926 29 : return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
9927 29 : static_cast<GUInt64>(nBlockXSize)};
9928 : }
9929 :
9930 : std::vector<std::shared_ptr<GDALAttribute>>
9931 14 : GetAttributes(CSLConstList) const override
9932 : {
9933 14 : std::vector<std::shared_ptr<GDALAttribute>> res;
9934 14 : auto papszMD = m_poBand->GetMetadata();
9935 16 : for (auto iter = papszMD; iter && iter[0]; ++iter)
9936 : {
9937 2 : char *pszKey = nullptr;
9938 2 : const char *pszValue = CPLParseNameValue(*iter, &pszKey);
9939 2 : if (pszKey && pszValue)
9940 : {
9941 : res.emplace_back(
9942 2 : std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
9943 : }
9944 2 : CPLFree(pszKey);
9945 : }
9946 14 : return res;
9947 : }
9948 : };
9949 :
9950 31 : bool GDALMDArrayFromRasterBand::IRead(
9951 : const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
9952 : const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
9953 : void *pDstBuffer) const
9954 : {
9955 31 : return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
9956 31 : bufferDataType, pDstBuffer);
9957 : }
9958 :
9959 : /************************************************************************/
9960 : /* ReadWrite() */
9961 : /************************************************************************/
9962 :
9963 32 : bool GDALMDArrayFromRasterBand::ReadWrite(
9964 : GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
9965 : const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
9966 : const GDALExtendedDataType &bufferDataType, void *pBuffer) const
9967 : {
9968 32 : constexpr size_t iDimX = 1;
9969 32 : constexpr size_t iDimY = 0;
9970 32 : return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
9971 : arrayStartIdx, count, arrayStep, bufferStride,
9972 32 : bufferDataType, pBuffer);
9973 : }
9974 :
9975 : /************************************************************************/
9976 : /* GDALMDRasterIOFromBand() */
9977 : /************************************************************************/
9978 :
9979 65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
9980 : size_t iDimX, size_t iDimY,
9981 : const GUInt64 *arrayStartIdx, const size_t *count,
9982 : const GInt64 *arrayStep,
9983 : const GPtrDiff_t *bufferStride,
9984 : const GDALExtendedDataType &bufferDataType,
9985 : void *pBuffer)
9986 : {
9987 65 : const auto eDT(bufferDataType.GetNumericDataType());
9988 65 : const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
9989 65 : const int nX =
9990 65 : arrayStep[iDimX] > 0
9991 65 : ? static_cast<int>(arrayStartIdx[iDimX])
9992 2 : : static_cast<int>(arrayStartIdx[iDimX] -
9993 2 : (count[iDimX] - 1) * -arrayStep[iDimX]);
9994 65 : const int nY =
9995 65 : arrayStep[iDimY] > 0
9996 65 : ? static_cast<int>(arrayStartIdx[iDimY])
9997 2 : : static_cast<int>(arrayStartIdx[iDimY] -
9998 2 : (count[iDimY] - 1) * -arrayStep[iDimY]);
9999 65 : const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
10000 65 : const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
10001 65 : GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
10002 65 : int nStrideXSign = 1;
10003 65 : if (arrayStep[iDimX] < 0)
10004 : {
10005 2 : pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
10006 2 : nStrideXSign = -1;
10007 : }
10008 65 : int nStrideYSign = 1;
10009 65 : if (arrayStep[iDimY] < 0)
10010 : {
10011 2 : pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
10012 2 : nStrideYSign = -1;
10013 : }
10014 :
10015 130 : return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
10016 65 : static_cast<int>(count[iDimX]),
10017 65 : static_cast<int>(count[iDimY]), eDT,
10018 : static_cast<GSpacing>(
10019 65 : nStrideXSign * bufferStride[iDimX] * nDTSize),
10020 : static_cast<GSpacing>(
10021 65 : nStrideYSign * bufferStride[iDimY] * nDTSize),
10022 65 : nullptr) == CE_None;
10023 : }
10024 :
10025 : /************************************************************************/
10026 : /* AsMDArray() */
10027 : /************************************************************************/
10028 :
10029 : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
10030 : *
10031 : * The band must be linked to a GDALDataset. If this dataset is not already
10032 : * marked as shared, it will be, so that the returned array holds a reference
10033 : * to it.
10034 : *
10035 : * If the dataset has a geotransform attached, the X and Y dimensions of the
10036 : * returned array will have an associated indexing variable.
10037 : *
10038 : * This is the same as the C function GDALRasterBandAsMDArray().
10039 : *
10040 : * The "reverse" method is GDALMDArray::AsClassicDataset().
10041 : *
10042 : * @return a new array, or nullptr.
10043 : *
10044 : * @since GDAL 3.1
10045 : */
10046 23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
10047 : {
10048 23 : if (!poDS)
10049 : {
10050 0 : CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
10051 0 : return nullptr;
10052 : }
10053 23 : if (!poDS->GetShared())
10054 : {
10055 23 : poDS->MarkAsShared();
10056 : }
10057 : return GDALMDArrayFromRasterBand::Create(
10058 23 : poDS, const_cast<GDALRasterBand *>(this));
10059 : }
10060 :
10061 : /************************************************************************/
10062 : /* InterpolateAtPoint() */
10063 : /************************************************************************/
10064 :
10065 : /**
10066 : * \brief Interpolates the value between pixels using a resampling algorithm,
10067 : * taking pixel/line coordinates as input.
10068 : *
10069 : * @param dfPixel pixel coordinate as a double, where interpolation should be done.
10070 : * @param dfLine line coordinate as a double, where interpolation should be done.
10071 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10072 : * @param pdfRealValue pointer to real part of interpolated value
10073 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10074 : *
10075 : * @return CE_None on success, or an error code on failure.
10076 : * @since GDAL 3.10
10077 : */
10078 :
10079 167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
10080 : GDALRIOResampleAlg eInterpolation,
10081 : double *pdfRealValue,
10082 : double *pdfImagValue) const
10083 : {
10084 167 : if (eInterpolation != GRIORA_NearestNeighbour &&
10085 33 : eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
10086 : eInterpolation != GRIORA_CubicSpline)
10087 : {
10088 2 : CPLError(CE_Failure, CPLE_AppDefined,
10089 : "Only nearest, bilinear, cubic and cubicspline interpolation "
10090 : "methods "
10091 : "allowed");
10092 :
10093 2 : return CE_Failure;
10094 : }
10095 :
10096 165 : GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
10097 165 : if (!m_poPointsCache)
10098 85 : m_poPointsCache = new GDALDoublePointsCache();
10099 :
10100 : const bool res =
10101 165 : GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
10102 : dfPixel, dfLine, pdfRealValue, pdfImagValue);
10103 :
10104 165 : return res ? CE_None : CE_Failure;
10105 : }
10106 :
10107 : /************************************************************************/
10108 : /* GDALRasterInterpolateAtPoint() */
10109 : /************************************************************************/
10110 :
10111 : /**
10112 : * \brief Interpolates the value between pixels using
10113 : * a resampling algorithm
10114 : *
10115 : * @see GDALRasterBand::InterpolateAtPoint()
10116 : * @since GDAL 3.10
10117 : */
10118 :
10119 144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
10120 : double dfLine,
10121 : GDALRIOResampleAlg eInterpolation,
10122 : double *pdfRealValue, double *pdfImagValue)
10123 : {
10124 144 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
10125 :
10126 144 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10127 144 : return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
10128 144 : pdfRealValue, pdfImagValue);
10129 : }
10130 :
10131 : /************************************************************************/
10132 : /* InterpolateAtGeolocation() */
10133 : /************************************************************************/
10134 :
10135 : /**
10136 : * \brief Interpolates the value between pixels using a resampling algorithm,
10137 : * taking georeferenced coordinates as input.
10138 : *
10139 : * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
10140 : * must be in the "natural" SRS of the dataset, that is the one returned by
10141 : * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
10142 : * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
10143 : * array (generally WGS 84) if there is a geolocation array.
10144 : * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
10145 : * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
10146 : * be a easting, and dfGeolocY a northing.
10147 : *
10148 : * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
10149 : * expressed in that CRS, and that tuple must be conformant with the
10150 : * data-axis-to-crs-axis setting of poSRS, that is the one returned by
10151 : * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
10152 : * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
10153 : * before calling this method, and in that case, dfGeolocX must be a longitude
10154 : * or an easting value, and dfGeolocX a latitude or a northing value.
10155 : *
10156 : * The GDALDataset::GeolocationToPixelLine() will be used to transform from
10157 : * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
10158 : * it for details on how that transformation is done.
10159 : *
10160 : * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
10161 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10162 : * where interpolation should be done.
10163 : * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
10164 : * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
10165 : * where interpolation should be done.
10166 : * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
10167 : * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
10168 : * @param pdfRealValue pointer to real part of interpolated value
10169 : * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
10170 : * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
10171 : *
10172 : * @return CE_None on success, or an error code on failure.
10173 : * @since GDAL 3.11
10174 : */
10175 :
10176 15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
10177 : double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
10178 : GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
10179 : double *pdfImagValue, CSLConstList papszTransformerOptions) const
10180 : {
10181 : double dfPixel;
10182 : double dfLine;
10183 15 : if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
10184 : &dfLine,
10185 15 : papszTransformerOptions) != CE_None)
10186 : {
10187 1 : return CE_Failure;
10188 : }
10189 14 : return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
10190 14 : pdfImagValue);
10191 : }
10192 :
10193 : /************************************************************************/
10194 : /* GDALRasterInterpolateAtGeolocation() */
10195 : /************************************************************************/
10196 :
10197 : /**
10198 : * \brief Interpolates the value between pixels using a resampling algorithm,
10199 : * taking georeferenced coordinates as input.
10200 : *
10201 : * @see GDALRasterBand::InterpolateAtGeolocation()
10202 : * @since GDAL 3.11
10203 : */
10204 :
10205 15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
10206 : double dfGeolocX, double dfGeolocY,
10207 : OGRSpatialReferenceH hSRS,
10208 : GDALRIOResampleAlg eInterpolation,
10209 : double *pdfRealValue,
10210 : double *pdfImagValue,
10211 : CSLConstList papszTransformerOptions)
10212 : {
10213 15 : VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
10214 :
10215 15 : GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
10216 15 : return poBand->InterpolateAtGeolocation(
10217 15 : dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
10218 15 : eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
10219 : }
10220 :
10221 : /************************************************************************/
10222 : /* GDALRasterBand::SplitRasterIO() */
10223 : /************************************************************************/
10224 :
10225 : //! @cond Doxygen_Suppress
10226 :
10227 : /** Implements IRasterIO() by dividing the request in 2.
10228 : *
10229 : * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
10230 : *
10231 : * Return CE_Warning if the split could not be done, CE_None in case of
10232 : * success and CE_Failure in case of error.
10233 : *
10234 : * @since 3.12
10235 : */
10236 999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
10237 : [[maybe_unused]] int nXSize,
10238 : [[maybe_unused]] int nYSize, void *pData,
10239 : int nBufXSize, int nBufYSize,
10240 : GDALDataType eBufType,
10241 : GSpacing nPixelSpace, GSpacing nLineSpace,
10242 : GDALRasterIOExtraArg *psExtraArg)
10243 : {
10244 999 : CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
10245 :
10246 999 : GByte *pabyData = static_cast<GByte *>(pData);
10247 999 : if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
10248 : {
10249 : GDALRasterIOExtraArg sArg;
10250 499 : INIT_RASTERIO_EXTRA_ARG(sArg);
10251 499 : const int nHalfHeight = nBufYSize / 2;
10252 :
10253 499 : sArg.pfnProgress = GDALScaledProgress;
10254 499 : sArg.pProgressData = GDALCreateScaledProgress(
10255 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10256 499 : if (sArg.pProgressData == nullptr)
10257 499 : sArg.pfnProgress = nullptr;
10258 998 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
10259 : pabyData, nBufXSize, nHalfHeight, eBufType,
10260 499 : nPixelSpace, nLineSpace, &sArg);
10261 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10262 :
10263 499 : if (eErr == CE_None)
10264 : {
10265 499 : sArg.pfnProgress = GDALScaledProgress;
10266 499 : sArg.pProgressData = GDALCreateScaledProgress(
10267 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10268 499 : if (sArg.pProgressData == nullptr)
10269 499 : sArg.pfnProgress = nullptr;
10270 998 : eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
10271 : nBufYSize - nHalfHeight,
10272 499 : pabyData + nHalfHeight * nLineSpace, nBufXSize,
10273 : nBufYSize - nHalfHeight, eBufType, nPixelSpace,
10274 499 : nLineSpace, &sArg);
10275 499 : GDALDestroyScaledProgress(sArg.pProgressData);
10276 : }
10277 499 : return eErr;
10278 : }
10279 500 : else if (nBufXSize >= 2)
10280 : {
10281 : GDALRasterIOExtraArg sArg;
10282 500 : INIT_RASTERIO_EXTRA_ARG(sArg);
10283 500 : const int nHalfWidth = nBufXSize / 2;
10284 :
10285 500 : sArg.pfnProgress = GDALScaledProgress;
10286 500 : sArg.pProgressData = GDALCreateScaledProgress(
10287 : 0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10288 500 : if (sArg.pProgressData == nullptr)
10289 500 : sArg.pfnProgress = nullptr;
10290 1000 : CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
10291 : pabyData, nHalfWidth, nBufYSize, eBufType,
10292 500 : nPixelSpace, nLineSpace, &sArg);
10293 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10294 :
10295 500 : if (eErr == CE_None)
10296 : {
10297 500 : sArg.pfnProgress = GDALScaledProgress;
10298 500 : sArg.pProgressData = GDALCreateScaledProgress(
10299 : 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
10300 500 : if (sArg.pProgressData == nullptr)
10301 500 : sArg.pfnProgress = nullptr;
10302 1000 : eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
10303 : nBufXSize - nHalfWidth, nBufYSize,
10304 500 : pabyData + nHalfWidth * nPixelSpace,
10305 : nBufXSize - nHalfWidth, nBufYSize, eBufType,
10306 500 : nPixelSpace, nLineSpace, &sArg);
10307 500 : GDALDestroyScaledProgress(sArg.pProgressData);
10308 : }
10309 500 : return eErr;
10310 : }
10311 :
10312 0 : return CE_Warning;
10313 : }
10314 :
10315 : //! @endcond
10316 :
10317 : /************************************************************************/
10318 : /* ThrowIfNotSameDimensions() */
10319 : /************************************************************************/
10320 :
10321 : //! @cond Doxygen_Suppress
10322 : /* static */
10323 169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
10324 : const GDALRasterBand &second)
10325 : {
10326 320 : if (first.GetXSize() != second.GetXSize() ||
10327 151 : first.GetYSize() != second.GetYSize())
10328 : {
10329 36 : throw std::runtime_error("Bands do not have the same dimensions");
10330 : }
10331 133 : }
10332 :
10333 : //! @endcond
10334 :
10335 : /************************************************************************/
10336 : /* GDALRasterBandUnaryOp() */
10337 : /************************************************************************/
10338 :
10339 : /** Apply a unary operation on this band.
10340 : *
10341 : * The resulting band is lazy evaluated. A reference is taken on the input
10342 : * dataset.
10343 : *
10344 : * @since 3.12
10345 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10346 : */
10347 : GDALComputedRasterBandH
10348 6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
10349 : GDALRasterAlgebraUnaryOperation eOp)
10350 : {
10351 6 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10352 6 : GDALComputedRasterBand::Operation cppOp{};
10353 6 : switch (eOp)
10354 : {
10355 2 : case GRAUO_LOGICAL_NOT:
10356 : return new GDALComputedRasterBand(
10357 : GDALComputedRasterBand::Operation::OP_NE,
10358 2 : *(GDALRasterBand::FromHandle(hBand)), true);
10359 1 : case GRAUO_ABS:
10360 1 : cppOp = GDALComputedRasterBand::Operation::OP_ABS;
10361 1 : break;
10362 1 : case GRAUO_SQRT:
10363 1 : cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
10364 1 : break;
10365 1 : case GRAUO_LOG:
10366 : #ifndef HAVE_MUPARSER
10367 : CPLError(
10368 : CE_Failure, CPLE_NotSupported,
10369 : "log(band) not available on a GDAL build without muparser");
10370 : return nullptr;
10371 : #else
10372 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG;
10373 1 : break;
10374 : #endif
10375 1 : case GRAUO_LOG10:
10376 1 : cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
10377 1 : break;
10378 : }
10379 : return new GDALComputedRasterBand(cppOp,
10380 4 : *(GDALRasterBand::FromHandle(hBand)));
10381 : }
10382 :
10383 : /************************************************************************/
10384 : /* ConvertGDALRasterAlgebraBinaryOperationToCpp() */
10385 : /************************************************************************/
10386 :
10387 : static GDALComputedRasterBand::Operation
10388 120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
10389 : GDALRasterAlgebraBinaryOperation eOp)
10390 : {
10391 120 : switch (eOp)
10392 : {
10393 26 : case GRABO_ADD:
10394 26 : return GDALComputedRasterBand::Operation::OP_ADD;
10395 2 : case GRABO_SUB:
10396 2 : return GDALComputedRasterBand::Operation::OP_SUBTRACT;
10397 24 : case GRABO_MUL:
10398 24 : return GDALComputedRasterBand::Operation::OP_MULTIPLY;
10399 3 : case GRABO_DIV:
10400 3 : return GDALComputedRasterBand::Operation::OP_DIVIDE;
10401 6 : case GRABO_GT:
10402 6 : return GDALComputedRasterBand::Operation::OP_GT;
10403 8 : case GRABO_GE:
10404 8 : return GDALComputedRasterBand::Operation::OP_GE;
10405 6 : case GRABO_LT:
10406 6 : return GDALComputedRasterBand::Operation::OP_LT;
10407 6 : case GRABO_LE:
10408 6 : return GDALComputedRasterBand::Operation::OP_LE;
10409 6 : case GRABO_EQ:
10410 6 : return GDALComputedRasterBand::Operation::OP_EQ;
10411 6 : case GRABO_NE:
10412 6 : break;
10413 12 : case GRABO_LOGICAL_AND:
10414 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
10415 12 : case GRABO_LOGICAL_OR:
10416 12 : return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
10417 3 : case GRABO_POW:
10418 3 : return GDALComputedRasterBand::Operation::OP_POW;
10419 : }
10420 6 : return GDALComputedRasterBand::Operation::OP_NE;
10421 : }
10422 :
10423 : /************************************************************************/
10424 : /* GDALRasterBandBinaryOpBand() */
10425 : /************************************************************************/
10426 :
10427 : /** Apply a binary operation on this band with another one.
10428 : *
10429 : * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
10430 : * "hBand1 - hBand2".
10431 : *
10432 : * The resulting band is lazy evaluated. A reference is taken on both input
10433 : * datasets.
10434 : *
10435 : * @since 3.12
10436 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10437 : */
10438 : GDALComputedRasterBandH
10439 57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
10440 : GDALRasterAlgebraBinaryOperation eOp,
10441 : GDALRasterBandH hOtherBand)
10442 : {
10443 57 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10444 57 : VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
10445 : #ifndef HAVE_MUPARSER
10446 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10447 : {
10448 : CPLError(
10449 : CE_Failure, CPLE_NotSupported,
10450 : "Band comparison operators not available on a GDAL build without "
10451 : "muparser");
10452 : return nullptr;
10453 : }
10454 : else if (eOp == GRABO_POW)
10455 : {
10456 : CPLError(
10457 : CE_Failure, CPLE_NotSupported,
10458 : "pow(band, band) not available on a GDAL build without muparser");
10459 : return nullptr;
10460 : }
10461 : #endif
10462 57 : auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
10463 57 : auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
10464 : try
10465 : {
10466 57 : GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
10467 : }
10468 13 : catch (const std::exception &e)
10469 : {
10470 13 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
10471 13 : return nullptr;
10472 : }
10473 : return new GDALComputedRasterBand(
10474 44 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
10475 44 : secondBand);
10476 : }
10477 :
10478 : /************************************************************************/
10479 : /* GDALRasterBandBinaryOpDouble() */
10480 : /************************************************************************/
10481 :
10482 : /** Apply a binary operation on this band with a constant
10483 : *
10484 : * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
10485 : * "hBand - constant".
10486 : *
10487 : * The resulting band is lazy evaluated. A reference is taken on the input
10488 : * dataset.
10489 : *
10490 : * @since 3.12
10491 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10492 : */
10493 : GDALComputedRasterBandH
10494 59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
10495 : GDALRasterAlgebraBinaryOperation eOp,
10496 : double constant)
10497 : {
10498 59 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10499 : #ifndef HAVE_MUPARSER
10500 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10501 : {
10502 : CPLError(
10503 : CE_Failure, CPLE_NotSupported,
10504 : "Band comparison operators not available on a GDAL build without "
10505 : "muparser");
10506 : return nullptr;
10507 : }
10508 : #endif
10509 : return new GDALComputedRasterBand(
10510 59 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10511 59 : *(GDALRasterBand::FromHandle(hBand)), constant);
10512 : }
10513 :
10514 : /************************************************************************/
10515 : /* GDALRasterBandBinaryOpDoubleToBand() */
10516 : /************************************************************************/
10517 :
10518 : /** Apply a binary operation on the constant with this band
10519 : *
10520 : * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
10521 : * "constant - hBand".
10522 : *
10523 : * The resulting band is lazy evaluated. A reference is taken on the input
10524 : * dataset.
10525 : *
10526 : * @since 3.12
10527 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
10528 : */
10529 : GDALComputedRasterBandH
10530 18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
10531 : GDALRasterAlgebraBinaryOperation eOp,
10532 : GDALRasterBandH hBand)
10533 : {
10534 18 : VALIDATE_POINTER1(hBand, __func__, nullptr);
10535 : #ifndef HAVE_MUPARSER
10536 : if (eOp >= GRABO_GT && eOp <= GRABO_NE)
10537 : {
10538 : CPLError(
10539 : CE_Failure, CPLE_NotSupported,
10540 : "Band comparison operators not available on a GDAL build without "
10541 : "muparser");
10542 : return nullptr;
10543 : }
10544 : #endif
10545 18 : switch (eOp)
10546 : {
10547 15 : case GRABO_ADD:
10548 : case GRABO_MUL:
10549 : {
10550 : return new GDALComputedRasterBand(
10551 15 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
10552 15 : *(GDALRasterBand::FromHandle(hBand)), constant);
10553 : }
10554 :
10555 2 : case GRABO_DIV:
10556 : case GRABO_GT:
10557 : case GRABO_GE:
10558 : case GRABO_LT:
10559 : case GRABO_LE:
10560 : case GRABO_EQ:
10561 : case GRABO_NE:
10562 : case GRABO_LOGICAL_AND:
10563 : case GRABO_LOGICAL_OR:
10564 : case GRABO_POW:
10565 : {
10566 : return new GDALComputedRasterBand(
10567 2 : ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
10568 2 : *(GDALRasterBand::FromHandle(hBand)));
10569 : }
10570 :
10571 1 : case GRABO_SUB:
10572 : {
10573 1 : break;
10574 : }
10575 : }
10576 :
10577 : return new GDALComputedRasterBand(
10578 : GDALComputedRasterBand::Operation::OP_ADD,
10579 2 : GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
10580 1 : *(GDALRasterBand::FromHandle(hBand)), -1.0),
10581 1 : constant);
10582 : }
10583 :
10584 : /************************************************************************/
10585 : /* operator+() */
10586 : /************************************************************************/
10587 :
10588 : /** Add this band with another one.
10589 : *
10590 : * The resulting band is lazy evaluated. A reference is taken on both input
10591 : * datasets.
10592 : *
10593 : * @since 3.12
10594 : * @throw std::runtime_error if both bands do not have the same dimensions.
10595 : */
10596 : GDALComputedRasterBand
10597 8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
10598 : {
10599 8 : ThrowIfNotSameDimensions(*this, other);
10600 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10601 7 : *this, other);
10602 : }
10603 :
10604 : /************************************************************************/
10605 : /* operator+() */
10606 : /************************************************************************/
10607 :
10608 : /** Add this band with a constant.
10609 : *
10610 : * The resulting band is lazy evaluated. A reference is taken on the input
10611 : * dataset.
10612 : *
10613 : * @since 3.12
10614 : */
10615 13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
10616 : {
10617 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
10618 13 : *this, constant);
10619 : }
10620 :
10621 : /************************************************************************/
10622 : /* operator+() */
10623 : /************************************************************************/
10624 :
10625 : /** Add a band with a constant.
10626 : *
10627 : * The resulting band is lazy evaluated. A reference is taken on the input
10628 : * dataset.
10629 : *
10630 : * @since 3.12
10631 : */
10632 1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
10633 : {
10634 1 : return other + constant;
10635 : }
10636 :
10637 : /************************************************************************/
10638 : /* operator-() */
10639 : /************************************************************************/
10640 :
10641 : /** Return a band whose value is the opposite value of the band for each
10642 : * pixel.
10643 : *
10644 : * The resulting band is lazy evaluated. A reference is taken on the input
10645 : * dataset.
10646 : *
10647 : * @since 3.12
10648 : */
10649 2 : GDALComputedRasterBand GDALRasterBand::operator-() const
10650 : {
10651 2 : return 0 - *this;
10652 : }
10653 :
10654 : /************************************************************************/
10655 : /* operator-() */
10656 : /************************************************************************/
10657 :
10658 : /** Subtract this band with another one.
10659 : *
10660 : * The resulting band is lazy evaluated. A reference is taken on both input
10661 : * datasets.
10662 : *
10663 : * @since 3.12
10664 : * @throw std::runtime_error if both bands do not have the same dimensions.
10665 : */
10666 : GDALComputedRasterBand
10667 2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
10668 : {
10669 2 : ThrowIfNotSameDimensions(*this, other);
10670 : return GDALComputedRasterBand(
10671 2 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
10672 : }
10673 :
10674 : /************************************************************************/
10675 : /* operator-() */
10676 : /************************************************************************/
10677 :
10678 : /** Subtract this band with a constant.
10679 : *
10680 : * The resulting band is lazy evaluated. A reference is taken on the input
10681 : * dataset.
10682 : *
10683 : * @since 3.12
10684 : */
10685 1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
10686 : {
10687 : return GDALComputedRasterBand(
10688 1 : GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
10689 : }
10690 :
10691 : /************************************************************************/
10692 : /* operator-() */
10693 : /************************************************************************/
10694 :
10695 : /** Subtract a constant with a band.
10696 : *
10697 : * The resulting band is lazy evaluated. A reference is taken on the input
10698 : * dataset.
10699 : *
10700 : * @since 3.12
10701 : */
10702 3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
10703 : {
10704 6 : return other * (-1.0) + constant;
10705 : }
10706 :
10707 : /************************************************************************/
10708 : /* operator*() */
10709 : /************************************************************************/
10710 :
10711 : /** Multiply this band with another one.
10712 : *
10713 : * The resulting band is lazy evaluated. A reference is taken on both input
10714 : * datasets.
10715 : *
10716 : * @since 3.12
10717 : * @throw std::runtime_error if both bands do not have the same dimensions.
10718 : */
10719 : GDALComputedRasterBand
10720 2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
10721 : {
10722 2 : ThrowIfNotSameDimensions(*this, other);
10723 : return GDALComputedRasterBand(
10724 2 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
10725 : }
10726 :
10727 : /************************************************************************/
10728 : /* operator*() */
10729 : /************************************************************************/
10730 :
10731 : /** Multiply this band by a constant.
10732 : *
10733 : * The resulting band is lazy evaluated. A reference is taken on the input
10734 : * dataset.
10735 : *
10736 : * @since 3.12
10737 : */
10738 14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
10739 : {
10740 : return GDALComputedRasterBand(
10741 14 : GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
10742 : }
10743 :
10744 : /************************************************************************/
10745 : /* operator*() */
10746 : /************************************************************************/
10747 :
10748 : /** Multiply a band with a constant.
10749 : *
10750 : * The resulting band is lazy evaluated. A reference is taken on the input
10751 : * dataset.
10752 : *
10753 : * @since 3.12
10754 : */
10755 2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
10756 : {
10757 2 : return other * constant;
10758 : }
10759 :
10760 : /************************************************************************/
10761 : /* operator/() */
10762 : /************************************************************************/
10763 :
10764 : /** Divide this band with another one.
10765 : *
10766 : * The resulting band is lazy evaluated. A reference is taken on both input
10767 : * datasets.
10768 : *
10769 : * @since 3.12
10770 : * @throw std::runtime_error if both bands do not have the same dimensions.
10771 : */
10772 : GDALComputedRasterBand
10773 2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
10774 : {
10775 2 : ThrowIfNotSameDimensions(*this, other);
10776 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10777 2 : *this, other);
10778 : }
10779 :
10780 : /************************************************************************/
10781 : /* operator/() */
10782 : /************************************************************************/
10783 :
10784 : /** Divide this band by a constant.
10785 : *
10786 : * The resulting band is lazy evaluated. A reference is taken on the input
10787 : * dataset.
10788 : *
10789 : * @since 3.12
10790 : */
10791 0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
10792 : {
10793 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10794 0 : *this, constant);
10795 : }
10796 :
10797 : /************************************************************************/
10798 : /* operator/() */
10799 : /************************************************************************/
10800 :
10801 : /** Divide a constant by a band.
10802 : *
10803 : * The resulting band is lazy evaluated. A reference is taken on the input
10804 : * dataset.
10805 : *
10806 : * @since 3.12
10807 : */
10808 1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
10809 : {
10810 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
10811 1 : constant, other);
10812 : }
10813 :
10814 : /************************************************************************/
10815 : /* ThrowIfNotMuparser() */
10816 : /************************************************************************/
10817 :
10818 : #ifndef HAVE_MUPARSER
10819 : static GDALComputedRasterBand ThrowIfNotMuparser()
10820 : {
10821 : throw std::runtime_error("Operator not available on a "
10822 : "GDAL build without muparser");
10823 : }
10824 : #endif
10825 :
10826 : /************************************************************************/
10827 : /* operator>() */
10828 : /************************************************************************/
10829 :
10830 : /** Return a band whose value is 1 if the pixel value of the left operand
10831 : * is greater than the pixel value of the right operand.
10832 : *
10833 : * The resulting band is lazy evaluated. A reference is taken on the input
10834 : * dataset.
10835 : *
10836 : * @since 3.12
10837 : */
10838 : GDALComputedRasterBand
10839 3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
10840 : {
10841 : #ifndef HAVE_MUPARSER
10842 : (void)other;
10843 : return ThrowIfNotMuparser();
10844 : #else
10845 3 : ThrowIfNotSameDimensions(*this, other);
10846 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10847 2 : *this, other);
10848 : #endif
10849 : }
10850 :
10851 : /************************************************************************/
10852 : /* operator>() */
10853 : /************************************************************************/
10854 :
10855 : /** Return a band whose value is 1 if the pixel value of the left operand
10856 : * is greater than the constant.
10857 : *
10858 : * The resulting band is lazy evaluated. A reference is taken on the input
10859 : * dataset.
10860 : *
10861 : * @since 3.12
10862 : */
10863 3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
10864 : {
10865 : #ifndef HAVE_MUPARSER
10866 : (void)constant;
10867 : return ThrowIfNotMuparser();
10868 : #else
10869 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10870 3 : *this, constant);
10871 : #endif
10872 : }
10873 :
10874 : /************************************************************************/
10875 : /* operator>() */
10876 : /************************************************************************/
10877 :
10878 : /** Return a band whose value is 1 if the constant is greater than the pixel
10879 : * value of the right operand.
10880 : *
10881 : * The resulting band is lazy evaluated. A reference is taken on the input
10882 : * dataset.
10883 : *
10884 : * @since 3.12
10885 : */
10886 2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
10887 : {
10888 : #ifndef HAVE_MUPARSER
10889 : (void)constant;
10890 : (void)other;
10891 : return ThrowIfNotMuparser();
10892 : #else
10893 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
10894 2 : constant, other);
10895 : #endif
10896 : }
10897 :
10898 : /************************************************************************/
10899 : /* operator>=() */
10900 : /************************************************************************/
10901 :
10902 : /** Return a band whose value is 1 if the pixel value of the left operand
10903 : * is greater or equal to the pixel value of the right operand.
10904 : *
10905 : * The resulting band is lazy evaluated. A reference is taken on the input
10906 : * dataset.
10907 : *
10908 : * @since 3.12
10909 : */
10910 : GDALComputedRasterBand
10911 4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
10912 : {
10913 : #ifndef HAVE_MUPARSER
10914 : (void)other;
10915 : return ThrowIfNotMuparser();
10916 : #else
10917 4 : ThrowIfNotSameDimensions(*this, other);
10918 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10919 3 : *this, other);
10920 : #endif
10921 : }
10922 :
10923 : /************************************************************************/
10924 : /* operator>=() */
10925 : /************************************************************************/
10926 :
10927 : /** Return a band whose value is 1 if the pixel value of the left operand
10928 : * is greater or equal to the constant.
10929 : *
10930 : * The resulting band is lazy evaluated. A reference is taken on the input
10931 : * dataset.
10932 : *
10933 : * @since 3.12
10934 : */
10935 3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
10936 : {
10937 : #ifndef HAVE_MUPARSER
10938 : (void)constant;
10939 : return ThrowIfNotMuparser();
10940 : #else
10941 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10942 3 : *this, constant);
10943 : #endif
10944 : }
10945 :
10946 : /************************************************************************/
10947 : /* operator>=() */
10948 : /************************************************************************/
10949 :
10950 : /** Return a band whose value is 1 if the constant is greater or equal to
10951 : * the pixel value of the right operand.
10952 : *
10953 : * The resulting band is lazy evaluated. A reference is taken on the input
10954 : * dataset.
10955 : *
10956 : * @since 3.12
10957 : */
10958 2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
10959 : {
10960 : #ifndef HAVE_MUPARSER
10961 : (void)constant;
10962 : (void)other;
10963 : return ThrowIfNotMuparser();
10964 : #else
10965 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
10966 2 : constant, other);
10967 : #endif
10968 : }
10969 :
10970 : /************************************************************************/
10971 : /* operator<() */
10972 : /************************************************************************/
10973 :
10974 : /** Return a band whose value is 1 if the pixel value of the left operand
10975 : * is lesser than the pixel value of the right operand.
10976 : *
10977 : * The resulting band is lazy evaluated. A reference is taken on the input
10978 : * dataset.
10979 : *
10980 : * @since 3.12
10981 : */
10982 : GDALComputedRasterBand
10983 3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
10984 : {
10985 : #ifndef HAVE_MUPARSER
10986 : (void)other;
10987 : return ThrowIfNotMuparser();
10988 : #else
10989 3 : ThrowIfNotSameDimensions(*this, other);
10990 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
10991 2 : *this, other);
10992 : #endif
10993 : }
10994 :
10995 : /************************************************************************/
10996 : /* operator<() */
10997 : /************************************************************************/
10998 :
10999 : /** Return a band whose value is 1 if the pixel value of the left operand
11000 : * is lesser than the constant.
11001 : *
11002 : * The resulting band is lazy evaluated. A reference is taken on the input
11003 : * dataset.
11004 : *
11005 : * @since 3.12
11006 : */
11007 3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
11008 : {
11009 : #ifndef HAVE_MUPARSER
11010 : (void)constant;
11011 : return ThrowIfNotMuparser();
11012 : #else
11013 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11014 3 : *this, constant);
11015 : #endif
11016 : }
11017 :
11018 : /************************************************************************/
11019 : /* operator<() */
11020 : /************************************************************************/
11021 :
11022 : /** Return a band whose value is 1 if the constant is lesser than the pixel
11023 : * value of the right operand.
11024 : *
11025 : * The resulting band is lazy evaluated. A reference is taken on the input
11026 : * dataset.
11027 : *
11028 : * @since 3.12
11029 : */
11030 2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
11031 : {
11032 : #ifndef HAVE_MUPARSER
11033 : (void)constant;
11034 : (void)other;
11035 : return ThrowIfNotMuparser();
11036 : #else
11037 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
11038 2 : constant, other);
11039 : #endif
11040 : }
11041 :
11042 : /************************************************************************/
11043 : /* operator<=() */
11044 : /************************************************************************/
11045 :
11046 : /** Return a band whose value is 1 if the pixel value of the left operand
11047 : * is lesser or equal to the pixel value of the right operand.
11048 : *
11049 : * The resulting band is lazy evaluated. A reference is taken on the input
11050 : * dataset.
11051 : *
11052 : * @since 3.12
11053 : */
11054 : GDALComputedRasterBand
11055 4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
11056 : {
11057 : #ifndef HAVE_MUPARSER
11058 : (void)other;
11059 : return ThrowIfNotMuparser();
11060 : #else
11061 4 : ThrowIfNotSameDimensions(*this, other);
11062 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11063 3 : *this, other);
11064 : #endif
11065 : }
11066 :
11067 : /************************************************************************/
11068 : /* operator<=() */
11069 : /************************************************************************/
11070 :
11071 : /** Return a band whose value is 1 if the pixel value of the left operand
11072 : * is lesser or equal to the constant.
11073 : *
11074 : * The resulting band is lazy evaluated. A reference is taken on the input
11075 : * dataset.
11076 : *
11077 : * @since 3.12
11078 : */
11079 3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
11080 : {
11081 : #ifndef HAVE_MUPARSER
11082 : (void)constant;
11083 : return ThrowIfNotMuparser();
11084 : #else
11085 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11086 3 : *this, constant);
11087 : #endif
11088 : }
11089 :
11090 : /************************************************************************/
11091 : /* operator<=() */
11092 : /************************************************************************/
11093 :
11094 : /** Return a band whose value is 1 if the constant is lesser or equal to
11095 : * the pixel value of the right operand.
11096 : *
11097 : * The resulting band is lazy evaluated. A reference is taken on the input
11098 : * dataset.
11099 : *
11100 : * @since 3.12
11101 : */
11102 2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
11103 : {
11104 : #ifndef HAVE_MUPARSER
11105 : (void)constant;
11106 : (void)other;
11107 : return ThrowIfNotMuparser();
11108 : #else
11109 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
11110 2 : constant, other);
11111 : #endif
11112 : }
11113 :
11114 : /************************************************************************/
11115 : /* operator==() */
11116 : /************************************************************************/
11117 :
11118 : /** Return a band whose value is 1 if the pixel value of the left operand
11119 : * is equal to the pixel value of the right operand.
11120 : *
11121 : * The resulting band is lazy evaluated. A reference is taken on the input
11122 : * dataset.
11123 : *
11124 : * @since 3.12
11125 : */
11126 : GDALComputedRasterBand
11127 3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
11128 : {
11129 : #ifndef HAVE_MUPARSER
11130 : (void)other;
11131 : return ThrowIfNotMuparser();
11132 : #else
11133 3 : ThrowIfNotSameDimensions(*this, other);
11134 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11135 2 : *this, other);
11136 : #endif
11137 : }
11138 :
11139 : /************************************************************************/
11140 : /* operator==() */
11141 : /************************************************************************/
11142 :
11143 : /** Return a band whose value is 1 if the pixel value of the left operand
11144 : * is equal to the constant.
11145 : *
11146 : * The resulting band is lazy evaluated. A reference is taken on the input
11147 : * dataset.
11148 : *
11149 : * @since 3.12
11150 : */
11151 8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
11152 : {
11153 : #ifndef HAVE_MUPARSER
11154 : (void)constant;
11155 : return ThrowIfNotMuparser();
11156 : #else
11157 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11158 8 : *this, constant);
11159 : #endif
11160 : }
11161 :
11162 : /************************************************************************/
11163 : /* operator==() */
11164 : /************************************************************************/
11165 :
11166 : /** Return a band whose value is 1 if the constant is equal to
11167 : * the pixel value of the right operand.
11168 : *
11169 : * The resulting band is lazy evaluated. A reference is taken on the input
11170 : * dataset.
11171 : *
11172 : * @since 3.12
11173 : */
11174 2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
11175 : {
11176 : #ifndef HAVE_MUPARSER
11177 : (void)constant;
11178 : (void)other;
11179 : return ThrowIfNotMuparser();
11180 : #else
11181 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
11182 2 : constant, other);
11183 : #endif
11184 : }
11185 :
11186 : /************************************************************************/
11187 : /* operator!=() */
11188 : /************************************************************************/
11189 :
11190 : /** Return a band whose value is 1 if the pixel value of the left operand
11191 : * is different from the pixel value of the right operand.
11192 : *
11193 : * The resulting band is lazy evaluated. A reference is taken on the input
11194 : * dataset.
11195 : *
11196 : * @since 3.12
11197 : */
11198 : GDALComputedRasterBand
11199 3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
11200 : {
11201 : #ifndef HAVE_MUPARSER
11202 : (void)other;
11203 : return ThrowIfNotMuparser();
11204 : #else
11205 3 : ThrowIfNotSameDimensions(*this, other);
11206 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11207 2 : *this, other);
11208 : #endif
11209 : }
11210 :
11211 : /************************************************************************/
11212 : /* operator!=() */
11213 : /************************************************************************/
11214 :
11215 : /** Return a band whose value is 1 if the pixel value of the left operand
11216 : * is different from the constant.
11217 : *
11218 : * The resulting band is lazy evaluated. A reference is taken on the input
11219 : * dataset.
11220 : *
11221 : * @since 3.12
11222 : */
11223 6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
11224 : {
11225 : #ifndef HAVE_MUPARSER
11226 : (void)constant;
11227 : return ThrowIfNotMuparser();
11228 : #else
11229 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11230 6 : *this, constant);
11231 : #endif
11232 : }
11233 :
11234 : /************************************************************************/
11235 : /* operator!=() */
11236 : /************************************************************************/
11237 :
11238 : /** Return a band whose value is 1 if the constant is different from
11239 : * the pixel value of the right operand.
11240 : *
11241 : * The resulting band is lazy evaluated. A reference is taken on the input
11242 : * dataset.
11243 : *
11244 : * @since 3.12
11245 : */
11246 2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
11247 : {
11248 : #ifndef HAVE_MUPARSER
11249 : (void)constant;
11250 : (void)other;
11251 : return ThrowIfNotMuparser();
11252 : #else
11253 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11254 2 : constant, other);
11255 : #endif
11256 : }
11257 :
11258 : #if defined(__GNUC__)
11259 : #pragma GCC diagnostic push
11260 : #pragma GCC diagnostic ignored "-Weffc++"
11261 : #endif
11262 :
11263 : /************************************************************************/
11264 : /* operator&&() */
11265 : /************************************************************************/
11266 :
11267 : /** Return a band whose value is 1 if the pixel value of the left and right
11268 : * operands is true.
11269 : *
11270 : * The resulting band is lazy evaluated. A reference is taken on the input
11271 : * dataset.
11272 : *
11273 : * @since 3.12
11274 : */
11275 : GDALComputedRasterBand
11276 3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
11277 : {
11278 : #ifndef HAVE_MUPARSER
11279 : (void)other;
11280 : return ThrowIfNotMuparser();
11281 : #else
11282 3 : ThrowIfNotSameDimensions(*this, other);
11283 : return GDALComputedRasterBand(
11284 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
11285 : #endif
11286 : }
11287 :
11288 : /************************************************************************/
11289 : /* operator&&() */
11290 : /************************************************************************/
11291 :
11292 : /** Return a band whose value is 1 if the pixel value of the left operand
11293 : * is true, as well as the constant
11294 : *
11295 : * The resulting band is lazy evaluated. A reference is taken on the input
11296 : * dataset.
11297 : *
11298 : * @since 3.12
11299 : */
11300 2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
11301 : {
11302 : #ifndef HAVE_MUPARSER
11303 : (void)constant;
11304 : return ThrowIfNotMuparser();
11305 : #else
11306 : return GDALComputedRasterBand(
11307 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
11308 : #endif
11309 : }
11310 :
11311 : /************************************************************************/
11312 : /* operator&&() */
11313 : /************************************************************************/
11314 :
11315 : /** Return a band whose value is 1 if the constant is true, as well as
11316 : * the pixel value of the right operand.
11317 : *
11318 : * The resulting band is lazy evaluated. A reference is taken on the input
11319 : * dataset.
11320 : *
11321 : * @since 3.12
11322 : */
11323 2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
11324 : {
11325 : #ifndef HAVE_MUPARSER
11326 : (void)constant;
11327 : (void)other;
11328 : return ThrowIfNotMuparser();
11329 : #else
11330 : return GDALComputedRasterBand(
11331 2 : GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
11332 : #endif
11333 : }
11334 :
11335 : /************************************************************************/
11336 : /* operator||() */
11337 : /************************************************************************/
11338 :
11339 : /** Return a band whose value is 1 if the pixel value of the left or right
11340 : * operands is true.
11341 : *
11342 : * The resulting band is lazy evaluated. A reference is taken on the input
11343 : * dataset.
11344 : *
11345 : * @since 3.12
11346 : */
11347 : GDALComputedRasterBand
11348 4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
11349 : {
11350 : #ifndef HAVE_MUPARSER
11351 : (void)other;
11352 : return ThrowIfNotMuparser();
11353 : #else
11354 4 : ThrowIfNotSameDimensions(*this, other);
11355 : return GDALComputedRasterBand(
11356 3 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
11357 : #endif
11358 : }
11359 :
11360 : /************************************************************************/
11361 : /* operator||() */
11362 : /************************************************************************/
11363 :
11364 : /** Return a band whose value is 1 if the pixel value of the left operand
11365 : * is true, or if the constant is true
11366 : *
11367 : * The resulting band is lazy evaluated. A reference is taken on the input
11368 : * dataset.
11369 : *
11370 : * @since 3.12
11371 : */
11372 4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
11373 : {
11374 : #ifndef HAVE_MUPARSER
11375 : (void)constant;
11376 : return ThrowIfNotMuparser();
11377 : #else
11378 : return GDALComputedRasterBand(
11379 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
11380 : #endif
11381 : }
11382 :
11383 : /************************************************************************/
11384 : /* operator||() */
11385 : /************************************************************************/
11386 :
11387 : /** Return a band whose value is 1 if the constant is true, or
11388 : * the pixel value of the right operand is true
11389 : *
11390 : * The resulting band is lazy evaluated. A reference is taken on the input
11391 : * dataset.
11392 : *
11393 : * @since 3.12
11394 : */
11395 4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
11396 : {
11397 : #ifndef HAVE_MUPARSER
11398 : (void)constant;
11399 : (void)other;
11400 : return ThrowIfNotMuparser();
11401 : #else
11402 : return GDALComputedRasterBand(
11403 4 : GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
11404 : #endif
11405 : }
11406 :
11407 : #if defined(__GNUC__)
11408 : #pragma GCC diagnostic pop
11409 : #endif
11410 :
11411 : /************************************************************************/
11412 : /* operator!() */
11413 : /************************************************************************/
11414 :
11415 : /** Return a band whose value is the logical negation of the pixel value
11416 : *
11417 : * The resulting band is lazy evaluated. A reference is taken on the input
11418 : * dataset.
11419 : *
11420 : * @since 3.12
11421 : */
11422 2 : GDALComputedRasterBand GDALRasterBand::operator!() const
11423 : {
11424 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
11425 2 : *this, true);
11426 : }
11427 :
11428 : namespace gdal
11429 : {
11430 :
11431 : /************************************************************************/
11432 : /* IfThenElse() */
11433 : /************************************************************************/
11434 :
11435 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11436 : * is not zero, or the one from elseBand otherwise.
11437 : *
11438 : * Variants of this method exits where thenBand and/or elseBand can be double
11439 : * values.
11440 : *
11441 : * The resulting band is lazy evaluated. A reference is taken on the input
11442 : * datasets.
11443 : *
11444 : * This method is the same as the C function GDALRasterBandIfThenElse()
11445 : *
11446 : * @since 3.12
11447 : */
11448 5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11449 : const GDALRasterBand &thenBand,
11450 : const GDALRasterBand &elseBand)
11451 : {
11452 : #ifndef HAVE_MUPARSER
11453 : (void)condBand;
11454 : (void)thenBand;
11455 : (void)elseBand;
11456 : return ThrowIfNotMuparser();
11457 : #else
11458 5 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11459 4 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11460 : return GDALComputedRasterBand(
11461 : GDALComputedRasterBand::Operation::OP_TERNARY,
11462 6 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11463 : #endif
11464 : }
11465 :
11466 : //! @cond Doxygen_Suppress
11467 :
11468 : /************************************************************************/
11469 : /* IfThenElse() */
11470 : /************************************************************************/
11471 :
11472 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11473 : * is not zero, or the one from elseBand otherwise.
11474 : *
11475 : * The resulting band is lazy evaluated. A reference is taken on the input
11476 : * datasets.
11477 : *
11478 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11479 : * with thenBand = (condBand * 0) + thenValue
11480 : *
11481 : * @since 3.12
11482 : */
11483 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11484 : double thenValue,
11485 : const GDALRasterBand &elseBand)
11486 : {
11487 : #ifndef HAVE_MUPARSER
11488 : (void)condBand;
11489 : (void)thenValue;
11490 : (void)elseBand;
11491 : return ThrowIfNotMuparser();
11492 : #else
11493 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11494 : auto thenBand =
11495 1 : (condBand * 0)
11496 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11497 1 : thenValue;
11498 : return GDALComputedRasterBand(
11499 : GDALComputedRasterBand::Operation::OP_TERNARY,
11500 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11501 : #endif
11502 : }
11503 :
11504 : /************************************************************************/
11505 : /* IfThenElse() */
11506 : /************************************************************************/
11507 :
11508 : /** Return a band whose value is thenBand if the corresponding pixel in condBand
11509 : * is not zero, or the one from elseValue otherwise.
11510 : *
11511 : * The resulting band is lazy evaluated. A reference is taken on the input
11512 : * datasets.
11513 : *
11514 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11515 : * with elseBand = (condBand * 0) + elseValue
11516 :
11517 : * @since 3.12
11518 : */
11519 1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11520 : const GDALRasterBand &thenBand,
11521 : double elseValue)
11522 : {
11523 : #ifndef HAVE_MUPARSER
11524 : (void)condBand;
11525 : (void)thenBand;
11526 : (void)elseValue;
11527 : return ThrowIfNotMuparser();
11528 : #else
11529 1 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11530 : auto elseBand =
11531 1 : (condBand * 0)
11532 2 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11533 1 : elseValue;
11534 : return GDALComputedRasterBand(
11535 : GDALComputedRasterBand::Operation::OP_TERNARY,
11536 3 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11537 : #endif
11538 : }
11539 :
11540 : /************************************************************************/
11541 : /* IfThenElse() */
11542 : /************************************************************************/
11543 :
11544 : /** Return a band whose value is thenValue if the corresponding pixel in condBand
11545 : * is not zero, or the one from elseValue otherwise.
11546 : *
11547 : * The resulting band is lazy evaluated. A reference is taken on the input
11548 : * datasets.
11549 : *
11550 : * This method is the same as the C function GDALRasterBandIfThenElse(),
11551 : * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
11552 : *
11553 : * @since 3.12
11554 : */
11555 3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
11556 : double thenValue, double elseValue)
11557 : {
11558 : #ifndef HAVE_MUPARSER
11559 : (void)condBand;
11560 : (void)thenValue;
11561 : (void)elseValue;
11562 : return ThrowIfNotMuparser();
11563 : #else
11564 : auto thenBand =
11565 3 : (condBand * 0)
11566 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
11567 6 : thenValue;
11568 : auto elseBand =
11569 3 : (condBand * 0)
11570 6 : .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
11571 3 : elseValue;
11572 : return GDALComputedRasterBand(
11573 : GDALComputedRasterBand::Operation::OP_TERNARY,
11574 9 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11575 : #endif
11576 : }
11577 :
11578 : //! @endcond
11579 :
11580 : } // namespace gdal
11581 :
11582 : /************************************************************************/
11583 : /* GDALRasterBandIfThenElse() */
11584 : /************************************************************************/
11585 :
11586 : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
11587 : * is not zero, or the one from hElseBand otherwise.
11588 : *
11589 : * The resulting band is lazy evaluated. A reference is taken on the input
11590 : * datasets.
11591 : *
11592 : * This function is the same as the C++ method gdal::IfThenElse()
11593 : *
11594 : * @since 3.12
11595 : */
11596 12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
11597 : GDALRasterBandH hThenBand,
11598 : GDALRasterBandH hElseBand)
11599 : {
11600 12 : VALIDATE_POINTER1(hCondBand, __func__, nullptr);
11601 12 : VALIDATE_POINTER1(hThenBand, __func__, nullptr);
11602 12 : VALIDATE_POINTER1(hElseBand, __func__, nullptr);
11603 : #ifndef HAVE_MUPARSER
11604 : CPLError(CE_Failure, CPLE_NotSupported,
11605 : "Band comparison operators not available on a GDAL build without "
11606 : "muparser");
11607 : return nullptr;
11608 : #else
11609 :
11610 12 : auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
11611 12 : auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
11612 12 : auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
11613 : try
11614 : {
11615 12 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
11616 11 : GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
11617 : }
11618 2 : catch (const std::exception &e)
11619 : {
11620 2 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11621 2 : return nullptr;
11622 : }
11623 : return new GDALComputedRasterBand(
11624 : GDALComputedRasterBand::Operation::OP_TERNARY,
11625 10 : std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
11626 : #endif
11627 : }
11628 :
11629 : /************************************************************************/
11630 : /* GDALRasterBand::AsType() */
11631 : /************************************************************************/
11632 :
11633 : /** Cast this band to another type.
11634 : *
11635 : * The resulting band is lazy evaluated. A reference is taken on the input
11636 : * dataset.
11637 : *
11638 : * This method is the same as the C function GDALRasterBandAsDataType()
11639 : *
11640 : * @since 3.12
11641 : */
11642 10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
11643 : {
11644 10 : if (dt == GDT_Unknown)
11645 : {
11646 1 : throw std::runtime_error("AsType(GDT_Unknown) is not supported");
11647 : }
11648 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
11649 9 : *this, dt);
11650 : }
11651 :
11652 : /************************************************************************/
11653 : /* GDALRasterBandAsDataType() */
11654 : /************************************************************************/
11655 :
11656 : /** Cast this band to another type.
11657 : *
11658 : * The resulting band is lazy evaluated. A reference is taken on the input
11659 : * dataset.
11660 : *
11661 : * This function is the same as the C++ method GDALRasterBand::AsType()
11662 : *
11663 : * @since 3.12
11664 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11665 : */
11666 16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
11667 : GDALDataType eDT)
11668 : {
11669 16 : VALIDATE_POINTER1(hBand, __func__, nullptr);
11670 16 : if (eDT == GDT_Unknown)
11671 : {
11672 1 : CPLError(CE_Failure, CPLE_NotSupported,
11673 : "GDALRasterBandAsDataType(GDT_Unknown) not supported");
11674 1 : return nullptr;
11675 : }
11676 : return new GDALComputedRasterBand(
11677 : GDALComputedRasterBand::Operation::OP_CAST,
11678 15 : *(GDALRasterBand::FromHandle(hBand)), eDT);
11679 : }
11680 :
11681 : /************************************************************************/
11682 : /* GetBandVector() */
11683 : /************************************************************************/
11684 :
11685 : static std::vector<const GDALRasterBand *>
11686 10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
11687 : {
11688 10 : std::vector<const GDALRasterBand *> bands;
11689 27 : for (size_t i = 0; i < nBandCount; ++i)
11690 : {
11691 20 : if (i > 0)
11692 : {
11693 10 : GDALRasterBand::ThrowIfNotSameDimensions(
11694 10 : *(GDALRasterBand::FromHandle(pahBands[0])),
11695 10 : *(GDALRasterBand::FromHandle(pahBands[i])));
11696 : }
11697 17 : bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
11698 : }
11699 7 : return bands;
11700 : }
11701 :
11702 : /************************************************************************/
11703 : /* GDALOperationOnNBands() */
11704 : /************************************************************************/
11705 :
11706 : static GDALComputedRasterBandH
11707 11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
11708 : GDALRasterBandH *pahBands)
11709 : {
11710 11 : VALIDATE_POINTER1(pahBands, __func__, nullptr);
11711 11 : if (nBandCount == 0)
11712 : {
11713 1 : CPLError(CE_Failure, CPLE_AppDefined,
11714 : "At least one band should be passed");
11715 1 : return nullptr;
11716 : }
11717 :
11718 20 : std::vector<const GDALRasterBand *> bands;
11719 : try
11720 : {
11721 10 : bands = GetBandVector(nBandCount, pahBands);
11722 : }
11723 3 : catch (const std::exception &e)
11724 : {
11725 3 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
11726 3 : return nullptr;
11727 : }
11728 7 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
11729 : }
11730 :
11731 : /************************************************************************/
11732 : /* GDALMaximumOfNBands() */
11733 : /************************************************************************/
11734 :
11735 : /** Return a band whose each pixel value is the maximum of the corresponding
11736 : * pixel values in the input bands.
11737 : *
11738 : * The resulting band is lazy evaluated. A reference is taken on input
11739 : * datasets.
11740 : *
11741 : * This function is the same as the C ++ method gdal::max()
11742 : *
11743 : * @since 3.12
11744 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11745 : */
11746 4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
11747 : GDALRasterBandH *pahBands)
11748 : {
11749 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
11750 4 : nBandCount, pahBands);
11751 : }
11752 :
11753 : /************************************************************************/
11754 : /* gdal::max() */
11755 : /************************************************************************/
11756 :
11757 : namespace gdal
11758 : {
11759 : /** Return a band whose each pixel value is the maximum of the corresponding
11760 : * pixel values in the inputs (bands or constants)
11761 : *
11762 : * The resulting band is lazy evaluated. A reference is taken on input
11763 : * datasets.
11764 : *
11765 : * Two or more bands can be passed.
11766 : *
11767 : * This method is the same as the C function GDALMaximumOfNBands()
11768 : *
11769 : * @since 3.12
11770 : * @throw std::runtime_error if bands do not have the same dimensions.
11771 : */
11772 1 : GDALComputedRasterBand max(const GDALRasterBand &first,
11773 : const GDALRasterBand &second)
11774 : {
11775 1 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11776 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
11777 1 : first, second);
11778 : }
11779 : } // namespace gdal
11780 :
11781 : /************************************************************************/
11782 : /* GDALRasterBandMaxConstant() */
11783 : /************************************************************************/
11784 :
11785 : /** Return a band whose each pixel value is the maximum of the corresponding
11786 : * pixel values in the input band and the constant.
11787 : *
11788 : * The resulting band is lazy evaluated. A reference is taken on the input
11789 : * dataset.
11790 : *
11791 : * This function is the same as the C ++ method gdal::max()
11792 : *
11793 : * @since 3.12
11794 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11795 : */
11796 2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
11797 : double dfConstant)
11798 : {
11799 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11800 : GDALComputedRasterBand::Operation::OP_MAX,
11801 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11802 6 : dfConstant));
11803 : }
11804 :
11805 : /************************************************************************/
11806 : /* GDALMinimumOfNBands() */
11807 : /************************************************************************/
11808 :
11809 : /** Return a band whose each pixel value is the minimum of the corresponding
11810 : * pixel values in the input bands.
11811 : *
11812 : * The resulting band is lazy evaluated. A reference is taken on input
11813 : * datasets.
11814 : *
11815 : * This function is the same as the C ++ method gdal::min()
11816 : *
11817 : * @since 3.12
11818 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11819 : */
11820 4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
11821 : GDALRasterBandH *pahBands)
11822 : {
11823 4 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
11824 4 : nBandCount, pahBands);
11825 : }
11826 :
11827 : /************************************************************************/
11828 : /* gdal::min() */
11829 : /************************************************************************/
11830 :
11831 : namespace gdal
11832 : {
11833 : /** Return a band whose each pixel value is the minimum of the corresponding
11834 : * pixel values in the inputs (bands or constants)
11835 : *
11836 : * The resulting band is lazy evaluated. A reference is taken on input
11837 : * datasets.
11838 : *
11839 : * Two or more bands can be passed.
11840 : *
11841 : * This method is the same as the C function GDALMinimumOfNBands()
11842 : *
11843 : * @since 3.12
11844 : * @throw std::runtime_error if bands do not have the same dimensions.
11845 : */
11846 0 : GDALComputedRasterBand min(const GDALRasterBand &first,
11847 : const GDALRasterBand &second)
11848 : {
11849 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11850 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
11851 0 : first, second);
11852 : }
11853 : } // namespace gdal
11854 :
11855 : /************************************************************************/
11856 : /* GDALRasterBandMinConstant() */
11857 : /************************************************************************/
11858 :
11859 : /** Return a band whose each pixel value is the minimum of the corresponding
11860 : * pixel values in the input band and the constant.
11861 : *
11862 : * The resulting band is lazy evaluated. A reference is taken on the input
11863 : * dataset.
11864 : *
11865 : * This function is the same as the C ++ method gdal::min()
11866 : *
11867 : * @since 3.12
11868 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11869 : */
11870 2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
11871 : double dfConstant)
11872 : {
11873 2 : return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
11874 : GDALComputedRasterBand::Operation::OP_MIN,
11875 4 : std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
11876 6 : dfConstant));
11877 : }
11878 :
11879 : /************************************************************************/
11880 : /* GDALMeanOfNBands() */
11881 : /************************************************************************/
11882 :
11883 : /** Return a band whose each pixel value is the arithmetic mean of the
11884 : * corresponding pixel values in the input bands.
11885 : *
11886 : * The resulting band is lazy evaluated. A reference is taken on input
11887 : * datasets.
11888 : *
11889 : * This function is the same as the C ++ method gdal::mean()
11890 : *
11891 : * @since 3.12
11892 : * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
11893 : */
11894 3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
11895 : GDALRasterBandH *pahBands)
11896 : {
11897 3 : return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
11898 3 : nBandCount, pahBands);
11899 : }
11900 :
11901 : /************************************************************************/
11902 : /* gdal::mean() */
11903 : /************************************************************************/
11904 :
11905 : namespace gdal
11906 : {
11907 :
11908 : /** Return a band whose each pixel value is the arithmetic mean of the
11909 : * corresponding pixel values in the input bands.
11910 : *
11911 : * The resulting band is lazy evaluated. A reference is taken on input
11912 : * datasets.
11913 : *
11914 : * Two or more bands can be passed.
11915 : *
11916 : * This method is the same as the C function GDALMeanOfNBands()
11917 : *
11918 : * @since 3.12
11919 : * @throw std::runtime_error if bands do not have the same dimensions.
11920 : */
11921 0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
11922 : const GDALRasterBand &second)
11923 : {
11924 0 : GDALRasterBand::ThrowIfNotSameDimensions(first, second);
11925 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
11926 0 : first, second);
11927 : }
11928 : } // namespace gdal
11929 :
11930 : /************************************************************************/
11931 : /* gdal::abs() */
11932 : /************************************************************************/
11933 :
11934 : namespace gdal
11935 : {
11936 :
11937 : /** Return a band whose each pixel value is the absolute value (or module
11938 : * for complex data type) of the corresponding pixel value in the input band.
11939 : *
11940 : * The resulting band is lazy evaluated. A reference is taken on input
11941 : * datasets.
11942 : *
11943 : * @since 3.12
11944 : */
11945 1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
11946 : {
11947 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
11948 1 : band);
11949 : }
11950 : } // namespace gdal
11951 :
11952 : /************************************************************************/
11953 : /* gdal::fabs() */
11954 : /************************************************************************/
11955 :
11956 : namespace gdal
11957 : {
11958 :
11959 : /** Return a band whose each pixel value is the absolute value (or module
11960 : * for complex data type) of the corresponding pixel value in the input band.
11961 : *
11962 : * The resulting band is lazy evaluated. A reference is taken on input
11963 : * datasets.
11964 : *
11965 : * @since 3.12
11966 : */
11967 1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
11968 : {
11969 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
11970 1 : band);
11971 : }
11972 : } // namespace gdal
11973 :
11974 : /************************************************************************/
11975 : /* gdal::sqrt() */
11976 : /************************************************************************/
11977 :
11978 : namespace gdal
11979 : {
11980 :
11981 : /** Return a band whose each pixel value is the square root of the
11982 : * corresponding pixel value in the input band.
11983 : *
11984 : * The resulting band is lazy evaluated. A reference is taken on input
11985 : * datasets.
11986 : *
11987 : * @since 3.12
11988 : */
11989 1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
11990 : {
11991 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
11992 1 : band);
11993 : }
11994 : } // namespace gdal
11995 :
11996 : /************************************************************************/
11997 : /* gdal::log() */
11998 : /************************************************************************/
11999 :
12000 : namespace gdal
12001 : {
12002 :
12003 : /** Return a band whose each pixel value is the natural logarithm of the
12004 : * corresponding pixel value in the input band.
12005 : *
12006 : * The resulting band is lazy evaluated. A reference is taken on input
12007 : * datasets.
12008 : *
12009 : * @since 3.12
12010 : */
12011 1 : GDALComputedRasterBand log(const GDALRasterBand &band)
12012 : {
12013 : #ifndef HAVE_MUPARSER
12014 : (void)band;
12015 : return ThrowIfNotMuparser();
12016 : #else
12017 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
12018 1 : band);
12019 : #endif
12020 : }
12021 : } // namespace gdal
12022 :
12023 : /************************************************************************/
12024 : /* gdal::log10() */
12025 : /************************************************************************/
12026 :
12027 : namespace gdal
12028 : {
12029 :
12030 : /** Return a band whose each pixel value is the logarithm base 10 of the
12031 : * corresponding pixel value in the input band.
12032 : *
12033 : * The resulting band is lazy evaluated. A reference is taken on input
12034 : * datasets.
12035 : *
12036 : * @since 3.12
12037 : */
12038 1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
12039 : {
12040 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
12041 1 : band);
12042 : }
12043 : } // namespace gdal
12044 :
12045 : /************************************************************************/
12046 : /* gdal::pow() */
12047 : /************************************************************************/
12048 :
12049 : namespace gdal
12050 : {
12051 :
12052 : #ifndef DOXYGEN_SKIP
12053 : /** Return a band whose each pixel value is the constant raised to the power of
12054 : * the corresponding pixel value in the input band.
12055 : *
12056 : * The resulting band is lazy evaluated. A reference is taken on input
12057 : * datasets.
12058 : *
12059 : * @since 3.12
12060 : */
12061 1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
12062 : {
12063 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12064 1 : constant, band);
12065 : }
12066 : #endif
12067 :
12068 : } // namespace gdal
12069 :
12070 : /************************************************************************/
12071 : /* gdal::pow() */
12072 : /************************************************************************/
12073 :
12074 : namespace gdal
12075 : {
12076 :
12077 : /** Return a band whose each pixel value is the the corresponding pixel value
12078 : * in the input band raised to the power of the constant.
12079 : *
12080 : * The resulting band is lazy evaluated. A reference is taken on input
12081 : * datasets.
12082 : *
12083 : * @since 3.12
12084 : */
12085 1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
12086 : {
12087 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12088 1 : band, constant);
12089 : }
12090 : } // namespace gdal
12091 :
12092 : /************************************************************************/
12093 : /* gdal::pow() */
12094 : /************************************************************************/
12095 :
12096 : namespace gdal
12097 : {
12098 :
12099 : #ifndef DOXYGEN_SKIP
12100 : /** Return a band whose each pixel value is the the corresponding pixel value
12101 : * in the input band1 raised to the power of the corresponding pixel value
12102 : * in the input band2
12103 : *
12104 : * The resulting band is lazy evaluated. A reference is taken on input
12105 : * datasets.
12106 : *
12107 : * @since 3.12
12108 : * @throw std::runtime_error if bands do not have the same dimensions.
12109 : */
12110 2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
12111 : const GDALRasterBand &band2)
12112 : {
12113 : #ifndef HAVE_MUPARSER
12114 : (void)band1;
12115 : (void)band2;
12116 : return ThrowIfNotMuparser();
12117 : #else
12118 2 : GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
12119 : return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
12120 1 : band1, band2);
12121 : #endif
12122 : }
12123 : #endif
12124 : } // namespace gdal
|