Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/pcraster/pcrasterrasterband.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  PCRaster Integration
4
 * Purpose:  PCRaster raster band implementation.
5
 * Author:   Kor de Jong, Oliver Schmitz
6
 *
7
 ******************************************************************************
8
 * Copyright (c) PCRaster owners
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "csf.h"
14
#include "csfimpl.h"
15
#include "pcrasterdataset.h"
16
#include "pcrasterrasterband.h"
17
#include "pcrasterutil.h"
18
19
/*!
20
  \file
21
  This file contains the implementation of the PCRasterRasterBand class.
22
*/
23
24
//------------------------------------------------------------------------------
25
// DEFINITION OF PCRRASTERBAND MEMBERS
26
//------------------------------------------------------------------------------
27
28
//! Constructor.
29
/*!
30
  \param     dataset The dataset we are a part of.
31
*/
32
PCRasterRasterBand::PCRasterRasterBand(PCRasterDataset *dataset)
33
1
    : GDALPamRasterBand(), d_dataset(dataset), d_noDataValue(),
34
1
      d_defaultNoDataValueOverridden(false), d_create_in(GDT_Unknown)
35
1
{
36
1
    poDS = dataset;
37
1
    nBand = 1;
38
1
    eDataType = cellRepresentation2GDALType(dataset->cellRepresentation());
39
1
    nBlockXSize = dataset->GetRasterXSize();
40
1
    nBlockYSize = 1;
41
1
}
42
43
//! Destructor.
44
/*!
45
 */
46
PCRasterRasterBand::~PCRasterRasterBand()
47
1
{
48
1
}
49
50
double PCRasterRasterBand::GetNoDataValue(int *success)
51
516
{
52
516
    if (success)
53
3
    {
54
3
        *success = 1;
55
3
    }
56
57
516
    return d_defaultNoDataValueOverridden ? d_noDataValue
58
516
                                          : d_dataset->defaultNoDataValue();
59
516
}
60
61
double PCRasterRasterBand::GetMinimum(int *success)
62
0
{
63
0
    double result;
64
0
    bool isValid;
65
66
0
    switch (d_dataset->cellRepresentation())
67
0
    {
68
        // CSF version 2.
69
        // ----------------------------------------------------------
70
0
        case CR_UINT1:
71
0
        {
72
0
            UINT1 min;
73
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
74
0
            result = static_cast<double>(min);
75
0
            break;
76
0
        }
77
0
        case CR_INT4:
78
0
        {
79
0
            INT4 min;
80
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
81
0
            result = static_cast<double>(min);
82
0
            break;
83
0
        }
84
0
        case CR_REAL4:
85
0
        {
86
0
            REAL4 min;
87
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
88
0
            result = static_cast<double>(min);
89
0
            break;
90
0
        }
91
0
        case CR_REAL8:
92
0
        {
93
0
            REAL8 min;
94
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
95
0
            result = static_cast<double>(min);
96
0
            break;
97
0
        }
98
        // CSF version 1.
99
        // ----------------------------------------------------------
100
0
        case CR_INT1:
101
0
        {
102
0
            INT1 min;
103
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
104
0
            result = static_cast<double>(min);
105
0
            break;
106
0
        }
107
0
        case CR_INT2:
108
0
        {
109
0
            INT2 min;
110
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
111
0
            result = static_cast<double>(min);
112
0
            break;
113
0
        }
114
0
        case CR_UINT2:
115
0
        {
116
0
            UINT2 min;
117
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
118
0
            result = static_cast<double>(min);
119
0
            break;
120
0
        }
121
0
        case CR_UINT4:
122
0
        {
123
0
            UINT4 min;
124
0
            isValid = CPL_TO_BOOL(RgetMinVal(d_dataset->map(), &min));
125
0
            result = static_cast<double>(min);
126
0
            break;
127
0
        }
128
0
        default:
129
0
        {
130
0
            result = 0.0;
131
0
            isValid = false;
132
0
            break;
133
0
        }
134
0
    }
135
136
0
    if (success)
137
0
    {
138
0
        *success = isValid ? 1 : 0;
139
0
    }
140
141
0
    return result;
142
0
}
143
144
double PCRasterRasterBand::GetMaximum(int *success)
145
0
{
146
0
    double result;
147
0
    bool isValid;
148
149
0
    switch (d_dataset->cellRepresentation())
150
0
    {
151
0
        case CR_UINT1:
152
0
        {
153
0
            UINT1 max;
154
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
155
0
            result = static_cast<double>(max);
156
0
            break;
157
0
        }
158
0
        case CR_INT4:
159
0
        {
160
0
            INT4 max;
161
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
162
0
            result = static_cast<double>(max);
163
0
            break;
164
0
        }
165
0
        case CR_REAL4:
166
0
        {
167
0
            REAL4 max;
168
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
169
0
            result = static_cast<double>(max);
170
0
            break;
171
0
        }
172
        // CSF version 1.
173
        // ----------------------------------------------------------
174
0
        case CR_INT1:
175
0
        {
176
0
            INT1 max;
177
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
178
0
            result = static_cast<double>(max);
179
0
            break;
180
0
        }
181
0
        case CR_INT2:
182
0
        {
183
0
            INT2 max;
184
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
185
0
            result = static_cast<double>(max);
186
0
            break;
187
0
        }
188
0
        case CR_UINT2:
189
0
        {
190
0
            UINT2 max;
191
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
192
0
            result = static_cast<double>(max);
193
0
            break;
194
0
        }
195
0
        case CR_UINT4:
196
0
        {
197
0
            UINT4 max;
198
0
            isValid = CPL_TO_BOOL(RgetMaxVal(d_dataset->map(), &max));
199
0
            result = static_cast<double>(max);
200
0
            break;
201
0
        }
202
0
        default:
203
0
        {
204
0
            result = 0.0;
205
0
            isValid = false;
206
0
            break;
207
0
        }
208
0
    }
209
210
0
    if (success)
211
0
    {
212
0
        *success = isValid ? 1 : 0;
213
0
    }
214
215
0
    return result;
216
0
}
217
218
CPLErr PCRasterRasterBand::IReadBlock(CPL_UNUSED int nBlockXoff, int nBlockYoff,
219
                                      void *buffer)
220
512
{
221
512
    size_t nrCellsRead = RgetRow(d_dataset->map(), nBlockYoff, buffer);
222
223
    // Now we have raw values, missing values are set according to the CSF
224
    // conventions. This means that floating points should not be evaluated.
225
    // Since this is done by the GDal library we replace these with valid
226
    // values. Non-MV values are not touched.
227
228
    // Replace in-file MV with in-app MV which may be different.
229
512
    alterFromStdMV(buffer, nrCellsRead, d_dataset->cellRepresentation(),
230
512
                   GetNoDataValue());
231
232
512
    return CE_None;
233
512
}
234
235
CPLErr PCRasterRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
236
                                     int nXSize, int nYSize, void *pData,
237
                                     int nBufXSize, int nBufYSize,
238
                                     GDALDataType eBufType,
239
                                     GSpacing nPixelSpace, GSpacing nLineSpace,
240
                                     GDALRasterIOExtraArg *psExtraArg)
241
512
{
242
512
    if (eRWFlag == GF_Read)
243
512
    {
244
        // read should just be the default
245
512
        return GDALRasterBand::IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
246
512
                                         pData, nBufXSize, nBufYSize, eBufType,
247
512
                                         nPixelSpace, nLineSpace, psExtraArg);
248
512
    }
249
0
    else
250
0
    {
251
        // the datatype of the incoming data can be of different type than the
252
        // cell representation used in the raster
253
        // 'remember' the GDAL type to distinguish it later on in iWriteBlock
254
0
        d_create_in = eBufType;
255
0
        return GDALRasterBand::IRasterIO(GF_Write, nXOff, nYOff, nXSize, nYSize,
256
0
                                         pData, nBufXSize, nBufYSize, eBufType,
257
0
                                         nPixelSpace, nLineSpace, psExtraArg);
258
0
    }
259
512
}
260
261
CPLErr PCRasterRasterBand::IWriteBlock(CPL_UNUSED int nBlockXoff,
262
                                       int nBlockYoff, void *source)
263
0
{
264
0
    CSF_VS valuescale = d_dataset->valueScale();
265
266
0
    if (valuescale == VS_LDD)
267
0
    {
268
0
        if ((d_create_in == GDT_Byte) || (d_create_in == GDT_Float32) ||
269
0
            (d_create_in == GDT_Float64))
270
0
        {
271
0
            CPLError(CE_Failure, CPLE_NotSupported,
272
0
                     "PCRaster driver: "
273
0
                     "conversion from %s to LDD not supported",
274
0
                     GDALGetDataTypeName(d_create_in));
275
0
            return CE_Failure;
276
0
        }
277
0
    }
278
279
    // set new location attributes to the header
280
0
    if (d_dataset->location_changed())
281
0
    {
282
0
        REAL8 west = 0.0;
283
0
        REAL8 north = 0.0;
284
0
        REAL8 cellSize = 1.0;
285
0
        GDALGeoTransform gt;
286
0
        if (this->poDS->GetGeoTransform(gt) == CE_None)
287
0
        {
288
0
            if (gt[2] == 0.0 && gt[4] == 0.0)
289
0
            {
290
0
                west = static_cast<REAL8>(gt[0]);
291
0
                north = static_cast<REAL8>(gt[3]);
292
0
                cellSize = static_cast<REAL8>(gt[1]);
293
0
            }
294
0
        }
295
0
        (void)RputXUL(d_dataset->map(), west);
296
0
        (void)RputYUL(d_dataset->map(), north);
297
0
        (void)RputCellSize(d_dataset->map(), cellSize);
298
0
    }
299
300
0
    const int nr_cols = this->poDS->GetRasterXSize();
301
302
    // new maps from create() set min/max to MV
303
    // in case of reopening that map the min/max
304
    // value tracking is disabled (MM_WRONGVALUE)
305
    // reactivate it again to ensure that the output will
306
    // get the correct values when values are written to map
307
0
    d_dataset->map()->minMaxStatus = MM_KEEPTRACK;
308
309
    // allocate memory for row
310
0
    void *buffer = Rmalloc(d_dataset->map(), nr_cols);
311
0
    memcpy(buffer, source, nr_cols * 4);
312
313
    // convert source no_data values to MV in dest
314
0
    switch (valuescale)
315
0
    {
316
0
        case VS_BOOLEAN:
317
0
        case VS_LDD:
318
0
        {
319
0
            alterToStdMV(buffer, nr_cols, CR_UINT1, GetNoDataValue());
320
0
            break;
321
0
        }
322
0
        case VS_NOMINAL:
323
0
        case VS_ORDINAL:
324
0
        {
325
0
            alterToStdMV(buffer, nr_cols, CR_INT4, GetNoDataValue());
326
0
            break;
327
0
        }
328
0
        case VS_SCALAR:
329
0
        case VS_DIRECTION:
330
0
        {
331
0
            alterToStdMV(buffer, nr_cols, CR_REAL4, GetNoDataValue());
332
0
            break;
333
0
        }
334
0
        default:
335
0
        {
336
0
            break;
337
0
        }
338
0
    }
339
340
    // conversion of values according to value scale
341
0
    switch (valuescale)
342
0
    {
343
0
        case VS_BOOLEAN:
344
0
        {
345
0
            castValuesToBooleanRange(buffer, nr_cols, CR_UINT1);
346
0
            break;
347
0
        }
348
0
        case VS_LDD:
349
0
        {
350
0
            castValuesToLddRange(buffer, nr_cols);
351
0
            break;
352
0
        }
353
0
        case VS_DIRECTION:
354
0
        {
355
0
            castValuesToDirectionRange(buffer, nr_cols);
356
0
            break;
357
0
        }
358
0
        default:
359
0
        {
360
0
            break;
361
0
        }
362
0
    }
363
364
0
    RputRow(d_dataset->map(), nBlockYoff, buffer);
365
0
    free(buffer);
366
367
0
    return CE_None;
368
0
}
369
370
CPLErr PCRasterRasterBand::SetNoDataValue(double nodata)
371
0
{
372
0
    d_noDataValue = nodata;
373
0
    d_defaultNoDataValueOverridden = true;
374
375
0
    return CE_None;
376
0
}