/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 | } |