Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PCRaster Integration
4 : * Purpose: PCRaster driver support functions.
5 : * Author: Kor de Jong, Oliver Schmitz
6 : *
7 : ******************************************************************************
8 : * Copyright (c) PCRaster owners
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include <cfloat>
14 :
15 : #include <algorithm>
16 : #include <limits>
17 :
18 : #include "pcrasterutil.h"
19 : #include "pcrtypes.h"
20 :
21 : //! Converts PCRaster data type to GDAL data type.
22 : /*!
23 : \param cellRepresentation Cell representation.
24 : \return GDAL data type, GDT_Uknown if conversion is not possible.
25 : */
26 13 : GDALDataType cellRepresentation2GDALType(CSF_CR cellRepresentation)
27 : {
28 13 : GDALDataType type = GDT_Unknown;
29 :
30 13 : switch (cellRepresentation)
31 : {
32 : // CSF version 2.
33 : // ----------------------------------------------------------
34 7 : case CR_UINT1:
35 : {
36 7 : type = GDT_Byte;
37 7 : break;
38 : }
39 1 : case CR_INT4:
40 : {
41 1 : type = GDT_Int32;
42 1 : break;
43 : }
44 5 : case CR_REAL4:
45 : {
46 5 : type = GDT_Float32;
47 5 : break;
48 : }
49 0 : case CR_REAL8:
50 : {
51 0 : type = GDT_Float64;
52 0 : break;
53 : }
54 : // CSF version 1.
55 : // ----------------------------------------------------------
56 0 : case CR_INT1:
57 : {
58 0 : type = GDT_Byte;
59 0 : break;
60 : }
61 0 : case CR_INT2:
62 : {
63 0 : type = GDT_Int16;
64 0 : break;
65 : }
66 0 : case CR_UINT2:
67 : {
68 0 : type = GDT_UInt16;
69 0 : break;
70 : }
71 0 : case CR_UINT4:
72 : {
73 0 : type = GDT_UInt32;
74 0 : break;
75 : }
76 0 : default:
77 : {
78 0 : break;
79 : }
80 : }
81 :
82 13 : return type;
83 : }
84 :
85 2 : CSF_VS string2ValueScale(std::string const &string)
86 : {
87 2 : CSF_VS valueScale = VS_UNDEFINED;
88 :
89 : // CSF version 2.
90 : // ------------------------------------------------------------
91 2 : if (string == "VS_BOOLEAN")
92 : {
93 0 : valueScale = VS_BOOLEAN;
94 : }
95 2 : else if (string == "VS_NOMINAL")
96 : {
97 0 : valueScale = VS_NOMINAL;
98 : }
99 2 : else if (string == "VS_ORDINAL")
100 : {
101 0 : valueScale = VS_ORDINAL;
102 : }
103 2 : else if (string == "VS_SCALAR")
104 : {
105 1 : valueScale = VS_SCALAR;
106 : }
107 1 : else if (string == "VS_DIRECTION")
108 : {
109 0 : valueScale = VS_DIRECTION;
110 : }
111 1 : else if (string == "VS_LDD")
112 : {
113 1 : valueScale = VS_LDD;
114 : }
115 : // CSF version1.
116 : // -------------------------------------------------------------
117 0 : else if (string == "VS_CLASSIFIED")
118 : {
119 0 : valueScale = VS_CLASSIFIED;
120 : }
121 0 : else if (string == "VS_CONTINUOUS")
122 : {
123 0 : valueScale = VS_CONTINUOUS;
124 : }
125 0 : else if (string == "VS_NOTDETERMINED")
126 : {
127 0 : valueScale = VS_NOTDETERMINED;
128 : }
129 :
130 2 : return valueScale;
131 : }
132 :
133 13 : std::string valueScale2String(CSF_VS valueScale)
134 : {
135 13 : std::string result = "VS_UNDEFINED";
136 :
137 13 : switch (valueScale)
138 : {
139 : // CSF version 2.
140 : // ----------------------------------------------------------
141 1 : case VS_BOOLEAN:
142 : {
143 1 : result = "VS_BOOLEAN";
144 1 : break;
145 : }
146 1 : case VS_NOMINAL:
147 : {
148 1 : result = "VS_NOMINAL";
149 1 : break;
150 : }
151 0 : case VS_ORDINAL:
152 : {
153 0 : result = "VS_ORDINAL";
154 0 : break;
155 : }
156 5 : case VS_SCALAR:
157 : {
158 5 : result = "VS_SCALAR";
159 5 : break;
160 : }
161 0 : case VS_DIRECTION:
162 : {
163 0 : result = "VS_DIRECTION";
164 0 : break;
165 : }
166 6 : case VS_LDD:
167 : {
168 6 : result = "VS_LDD";
169 6 : break;
170 : }
171 : // CSF version 1.
172 : // ----------------------------------------------------------
173 0 : case VS_CLASSIFIED:
174 : {
175 0 : result = "VS_CLASSIFIED";
176 0 : break;
177 : }
178 0 : case VS_CONTINUOUS:
179 : {
180 0 : result = "VS_CONTINUOUS";
181 0 : break;
182 : }
183 0 : case VS_NOTDETERMINED:
184 : {
185 0 : result = "VS_NOTDETERMINED";
186 0 : break;
187 : }
188 0 : default:
189 : {
190 0 : break;
191 : }
192 : }
193 :
194 13 : return result;
195 : }
196 :
197 0 : std::string cellRepresentation2String(CSF_CR cellRepresentation)
198 : {
199 0 : std::string result = "CR_UNDEFINED";
200 :
201 0 : switch (cellRepresentation)
202 : {
203 :
204 : // CSF version 2.
205 : // ----------------------------------------------------------
206 0 : case CR_UINT1:
207 : {
208 0 : result = "CR_UINT1";
209 0 : break;
210 : }
211 0 : case CR_INT4:
212 : {
213 0 : result = "CR_INT4";
214 0 : break;
215 : }
216 0 : case CR_REAL4:
217 : {
218 0 : result = "CR_REAL4";
219 0 : break;
220 : }
221 0 : case CR_REAL8:
222 : {
223 0 : result = "CR_REAL8";
224 0 : break;
225 : }
226 : // CSF version 1.
227 : // ----------------------------------------------------------
228 0 : case CR_INT1:
229 : {
230 0 : result = "CR_INT1";
231 0 : break;
232 : }
233 0 : case CR_INT2:
234 : {
235 0 : result = "CR_INT2";
236 0 : break;
237 : }
238 0 : case CR_UINT2:
239 : {
240 0 : result = "CR_UINT2";
241 0 : break;
242 : }
243 0 : case CR_UINT4:
244 : {
245 0 : result = "CR_UINT4";
246 0 : break;
247 : }
248 0 : default:
249 : {
250 0 : break;
251 : }
252 : }
253 :
254 0 : return result;
255 : }
256 :
257 : //! Converts GDAL data type to PCRaster value scale.
258 : /*!
259 : \param type GDAL data type.
260 : \return Value scale.
261 : \warning \a type must be one of the standard numerical types and not
262 : complex.
263 :
264 : GDAL byte is regarded as PCRaster boolean, integral as nominal and float
265 : as scalar. This function will never return VS_LDD, VS_ORDINAL or
266 : VS_DIRECTION.
267 : */
268 10 : CSF_VS GDALType2ValueScale(GDALDataType type)
269 : {
270 10 : CSF_VS valueScale = VS_UNDEFINED;
271 :
272 10 : switch (type)
273 : {
274 4 : case GDT_Byte:
275 : {
276 : // A foreign dataset is unlikely to support our LDD's.
277 4 : valueScale = VS_BOOLEAN;
278 4 : break;
279 : }
280 4 : case GDT_UInt16:
281 : case GDT_UInt32:
282 : case GDT_Int16:
283 : case GDT_Int32:
284 : {
285 4 : valueScale = VS_NOMINAL;
286 4 : break;
287 : }
288 1 : case GDT_Float32:
289 : {
290 : // A foreign dataset is unlikely to support our directional.
291 1 : valueScale = VS_SCALAR;
292 1 : break;
293 : }
294 1 : case GDT_Float64:
295 : {
296 : // A foreign dataset is unlikely to support our directional.
297 1 : valueScale = VS_SCALAR;
298 1 : break;
299 : }
300 0 : default:
301 : {
302 0 : CPLAssert(false);
303 : break;
304 : }
305 : }
306 :
307 10 : return valueScale;
308 : }
309 :
310 : //! Converts a GDAL type to a PCRaster cell representation.
311 : /*!
312 : \param type GDAL type.
313 : \param exact Whether an exact match or a CSF2.0 supported cell
314 : representation should be returned.
315 : \return Cell representation.
316 : \warning \a type must be one of the standard numerical types and not
317 : complex.
318 :
319 : If exact is false, conversion to CSF2.0 types will take place. This is
320 : useful for in file cell representations. If exact is true, and exact match
321 : is made. This is useful for in app cell representations.
322 :
323 : If exact is false, this function always returns one of CR_UINT1, CR_INT4
324 : or CR_REAL4.
325 : */
326 27 : CSF_CR GDALType2CellRepresentation(GDALDataType type, bool exact)
327 : {
328 27 : CSF_CR cellRepresentation = CR_UNDEFINED;
329 :
330 27 : switch (type)
331 : {
332 10 : case GDT_Byte:
333 : {
334 10 : cellRepresentation = CR_UINT1;
335 10 : break;
336 : }
337 2 : case GDT_UInt16:
338 : {
339 2 : cellRepresentation = exact ? CR_UINT2 : CR_UINT1;
340 2 : break;
341 : }
342 2 : case GDT_UInt32:
343 : {
344 2 : cellRepresentation = exact ? CR_UINT4 : CR_UINT1;
345 2 : break;
346 : }
347 2 : case GDT_Int16:
348 : {
349 2 : cellRepresentation = exact ? CR_INT2 : CR_INT4;
350 2 : break;
351 : }
352 2 : case GDT_Int32:
353 : {
354 2 : cellRepresentation = CR_INT4;
355 2 : break;
356 : }
357 3 : case GDT_Float32:
358 : {
359 3 : cellRepresentation = CR_REAL4;
360 3 : break;
361 : }
362 2 : case GDT_Float64:
363 : {
364 2 : cellRepresentation = exact ? CR_REAL8 : CR_REAL4;
365 2 : break;
366 : }
367 4 : default:
368 : {
369 4 : break;
370 : }
371 : }
372 :
373 27 : return cellRepresentation;
374 : }
375 :
376 : //! Determines a missing value to use for data of \a cellRepresentation.
377 : /*!
378 : \param cellRepresentation Cell representation of the data.
379 : \return Missing value.
380 : */
381 18 : double missingValue(CSF_CR cellRepresentation)
382 : {
383 : // It turns out that the missing values set here should be equal to the ones
384 : // used in gdal's code to do data type conversion. Otherwise missing values
385 : // in the source raster will be lost in the destination raster. It seems
386 : // that when assigning new missing values gdal uses its own nodata values
387 : // instead of the value set in the dataset.
388 :
389 18 : double missingValue = 0.0;
390 :
391 18 : switch (cellRepresentation)
392 : {
393 : // CSF version 2.
394 : // ----------------------------------------------------------
395 7 : case CR_UINT1:
396 : {
397 : // missingValue = static_cast<double>(MV_UINT1);
398 7 : missingValue = UINT1(255);
399 7 : break;
400 : }
401 1 : case CR_INT4:
402 : {
403 : // missingValue = static_cast<double>(MV_INT4);
404 1 : missingValue = INT4(-2147483647);
405 1 : break;
406 : }
407 10 : case CR_REAL4:
408 : {
409 : // using <limits> breaks on gcc 2.95
410 : // CPLAssert(std::numeric_limits<REAL4>::is_iec559);
411 : // missingValue = -std::numeric_limits<REAL4>::max();
412 10 : missingValue = std::numeric_limits<float>::lowest();
413 10 : break;
414 : }
415 : // CSF version 1.
416 : // ----------------------------------------------------------
417 0 : case CR_INT1:
418 : {
419 0 : missingValue = static_cast<double>(MV_INT1);
420 0 : break;
421 : }
422 0 : case CR_INT2:
423 : {
424 0 : missingValue = static_cast<double>(MV_INT2);
425 0 : break;
426 : }
427 0 : case CR_UINT2:
428 : {
429 0 : missingValue = static_cast<double>(MV_UINT2);
430 0 : break;
431 : }
432 0 : case CR_UINT4:
433 : {
434 0 : missingValue = static_cast<double>(MV_UINT4);
435 0 : break;
436 : }
437 0 : default:
438 : {
439 0 : CPLError(CE_Failure, CPLE_NotSupported,
440 : "Unexpected value for cellRepresentation = %d",
441 : cellRepresentation);
442 0 : break;
443 : }
444 : }
445 :
446 18 : return missingValue;
447 : }
448 :
449 : //! Opens the raster in \a filename using mode \a mode.
450 : /*!
451 : \param filename Filename of raster to open.
452 : \return Pointer to CSF MAP structure.
453 : */
454 13 : MAP *mapOpen(std::string const &filename, MOPEN_PERM mode)
455 : {
456 13 : MAP *map = Mopen(filename.c_str(), mode);
457 :
458 13 : return map;
459 : }
460 :
461 420 : void alterFromStdMV(void *buffer, size_t size, CSF_CR cellRepresentation,
462 : double missingValue)
463 : {
464 420 : switch (cellRepresentation)
465 : {
466 : // CSF version 2.
467 : // ----------------------------------------------------------
468 400 : case (CR_UINT1):
469 : {
470 : std::for_each(
471 : static_cast<UINT1 *>(buffer),
472 : static_cast<UINT1 *>(buffer) + size,
473 400 : pcr::AlterFromStdMV<UINT1>(static_cast<UINT1>(missingValue)));
474 400 : break;
475 : }
476 0 : case (CR_INT4):
477 : {
478 : std::for_each(
479 0 : static_cast<INT4 *>(buffer), static_cast<INT4 *>(buffer) + size,
480 0 : pcr::AlterFromStdMV<INT4>(static_cast<INT4>(missingValue)));
481 0 : break;
482 : }
483 20 : case (CR_REAL4):
484 : {
485 : std::for_each(
486 : static_cast<REAL4 *>(buffer),
487 20 : static_cast<REAL4 *>(buffer) + size,
488 20 : pcr::AlterFromStdMV<REAL4>(static_cast<REAL4>(missingValue)));
489 20 : break;
490 : }
491 0 : case (CR_REAL8):
492 : {
493 : std::for_each(
494 : static_cast<REAL8 *>(buffer),
495 0 : static_cast<REAL8 *>(buffer) + size,
496 0 : pcr::AlterFromStdMV<REAL8>(static_cast<REAL8>(missingValue)));
497 0 : break;
498 : }
499 : // CSF version 1.
500 : // ----------------------------------------------------------
501 0 : case CR_INT1:
502 : {
503 : std::for_each(
504 : static_cast<INT1 *>(buffer), static_cast<INT1 *>(buffer) + size,
505 0 : pcr::AlterFromStdMV<INT1>(static_cast<INT1>(missingValue)));
506 0 : break;
507 : }
508 0 : case CR_INT2:
509 : {
510 : std::for_each(
511 0 : static_cast<INT2 *>(buffer), static_cast<INT2 *>(buffer) + size,
512 0 : pcr::AlterFromStdMV<INT2>(static_cast<INT2>(missingValue)));
513 0 : break;
514 : }
515 0 : case CR_UINT2:
516 : {
517 : std::for_each(
518 : static_cast<UINT2 *>(buffer),
519 0 : static_cast<UINT2 *>(buffer) + size,
520 0 : pcr::AlterFromStdMV<UINT2>(static_cast<UINT2>(missingValue)));
521 0 : break;
522 : }
523 0 : case CR_UINT4:
524 : {
525 : std::for_each(
526 : static_cast<UINT4 *>(buffer),
527 0 : static_cast<UINT4 *>(buffer) + size,
528 0 : pcr::AlterFromStdMV<UINT4>(static_cast<UINT4>(missingValue)));
529 0 : break;
530 : }
531 0 : default:
532 : {
533 0 : CPLAssert(false);
534 : break;
535 : }
536 : }
537 420 : }
538 :
539 120 : void alterToStdMV(void *buffer, size_t size, CSF_CR cellRepresentation,
540 : double missingValue)
541 : {
542 120 : switch (cellRepresentation)
543 : {
544 : // CSF version 2.
545 : // ----------------------------------------------------------
546 100 : case (CR_UINT1):
547 : {
548 : std::for_each(
549 : static_cast<UINT1 *>(buffer),
550 : static_cast<UINT1 *>(buffer) + size,
551 100 : pcr::AlterToStdMV<UINT1>(static_cast<UINT1>(missingValue)));
552 100 : break;
553 : }
554 0 : case (CR_INT4):
555 : {
556 : std::for_each(
557 0 : static_cast<INT4 *>(buffer), static_cast<INT4 *>(buffer) + size,
558 0 : pcr::AlterToStdMV<INT4>(static_cast<INT4>(missingValue)));
559 0 : break;
560 : }
561 20 : case (CR_REAL4):
562 : {
563 : std::for_each(
564 : static_cast<REAL4 *>(buffer),
565 20 : static_cast<REAL4 *>(buffer) + size,
566 20 : pcr::AlterToStdMV<REAL4>(static_cast<REAL4>(missingValue)));
567 20 : break;
568 : }
569 0 : case (CR_REAL8):
570 : {
571 : std::for_each(
572 : static_cast<REAL8 *>(buffer),
573 0 : static_cast<REAL8 *>(buffer) + size,
574 0 : pcr::AlterToStdMV<REAL8>(static_cast<REAL8>(missingValue)));
575 0 : break;
576 : }
577 : // CSF version 1.
578 : // ----------------------------------------------------------
579 0 : case CR_INT1:
580 : {
581 : std::for_each(
582 : static_cast<INT1 *>(buffer), static_cast<INT1 *>(buffer) + size,
583 0 : pcr::AlterToStdMV<INT1>(static_cast<INT1>(missingValue)));
584 0 : break;
585 : }
586 0 : case CR_INT2:
587 : {
588 : std::for_each(
589 0 : static_cast<INT2 *>(buffer), static_cast<INT2 *>(buffer) + size,
590 0 : pcr::AlterToStdMV<INT2>(static_cast<INT2>(missingValue)));
591 0 : break;
592 : }
593 0 : case CR_UINT2:
594 : {
595 : std::for_each(
596 : static_cast<UINT2 *>(buffer),
597 0 : static_cast<UINT2 *>(buffer) + size,
598 0 : pcr::AlterToStdMV<UINT2>(static_cast<UINT2>(missingValue)));
599 0 : break;
600 : }
601 0 : case CR_UINT4:
602 : {
603 : std::for_each(
604 : static_cast<UINT4 *>(buffer),
605 0 : static_cast<UINT4 *>(buffer) + size,
606 0 : pcr::AlterToStdMV<UINT4>(static_cast<UINT4>(missingValue)));
607 0 : break;
608 : }
609 0 : default:
610 : {
611 0 : CPLAssert(false);
612 : break;
613 : }
614 : }
615 120 : }
616 :
617 11 : CSF_VS fitValueScale(CSF_VS valueScale, CSF_CR cellRepresentation)
618 : {
619 11 : CSF_VS result = valueScale;
620 :
621 11 : switch (cellRepresentation)
622 : {
623 5 : case CR_UINT1:
624 : {
625 5 : switch (valueScale)
626 : {
627 1 : case VS_LDD:
628 : {
629 1 : result = VS_LDD;
630 1 : break;
631 : }
632 4 : default:
633 : {
634 4 : result = VS_BOOLEAN;
635 4 : break;
636 : }
637 : }
638 5 : break;
639 : }
640 1 : case CR_INT4:
641 : {
642 1 : switch (valueScale)
643 : {
644 0 : case VS_BOOLEAN:
645 : {
646 0 : result = VS_NOMINAL;
647 0 : break;
648 : }
649 0 : case VS_SCALAR:
650 : {
651 0 : result = VS_ORDINAL;
652 0 : break;
653 : }
654 0 : case VS_DIRECTION:
655 : {
656 0 : result = VS_ORDINAL;
657 0 : break;
658 : }
659 0 : case VS_LDD:
660 : {
661 0 : result = VS_NOMINAL;
662 0 : break;
663 : }
664 1 : default:
665 : {
666 1 : result = valueScale;
667 1 : break;
668 : }
669 : }
670 1 : break;
671 : }
672 1 : case CR_REAL4:
673 : {
674 1 : switch (valueScale)
675 : {
676 0 : case VS_DIRECTION:
677 : {
678 0 : result = VS_DIRECTION;
679 0 : break;
680 : }
681 1 : default:
682 : {
683 1 : result = VS_SCALAR;
684 1 : break;
685 : }
686 : }
687 1 : break;
688 : }
689 4 : default:
690 : {
691 4 : break;
692 : }
693 : }
694 :
695 11 : return result;
696 : }
697 :
698 10 : void castValuesToBooleanRange(void *buffer, size_t size,
699 : CSF_CR cellRepresentation)
700 : {
701 10 : switch (cellRepresentation)
702 : {
703 : // CSF version 2.
704 : // ----------------------------------------------------------
705 10 : case (CR_UINT1):
706 : {
707 : std::for_each(static_cast<UINT1 *>(buffer),
708 : static_cast<UINT1 *>(buffer) + size,
709 10 : CastToBooleanRange<UINT1>());
710 10 : break;
711 : }
712 0 : case (CR_INT4):
713 : {
714 : std::for_each(static_cast<INT4 *>(buffer),
715 0 : static_cast<INT4 *>(buffer) + size,
716 0 : CastToBooleanRange<INT4>());
717 0 : break;
718 : }
719 0 : case (CR_REAL4):
720 : {
721 : std::for_each(static_cast<REAL4 *>(buffer),
722 0 : static_cast<REAL4 *>(buffer) + size,
723 0 : CastToBooleanRange<REAL4>());
724 0 : break;
725 : }
726 0 : case (CR_REAL8):
727 : {
728 : std::for_each(static_cast<REAL8 *>(buffer),
729 0 : static_cast<REAL8 *>(buffer) + size,
730 0 : CastToBooleanRange<REAL8>());
731 0 : break;
732 : }
733 : // CSF version 1.
734 : // ----------------------------------------------------------
735 0 : case CR_INT1:
736 : {
737 : std::for_each(static_cast<INT1 *>(buffer),
738 : static_cast<INT1 *>(buffer) + size,
739 0 : CastToBooleanRange<INT1>());
740 0 : break;
741 : }
742 0 : case CR_INT2:
743 : {
744 : std::for_each(static_cast<INT2 *>(buffer),
745 0 : static_cast<INT2 *>(buffer) + size,
746 0 : CastToBooleanRange<INT2>());
747 0 : break;
748 : }
749 0 : case CR_UINT2:
750 : {
751 : std::for_each(static_cast<UINT2 *>(buffer),
752 0 : static_cast<UINT2 *>(buffer) + size,
753 0 : CastToBooleanRange<UINT2>());
754 0 : break;
755 : }
756 0 : case CR_UINT4:
757 : {
758 : std::for_each(static_cast<UINT4 *>(buffer),
759 0 : static_cast<UINT4 *>(buffer) + size,
760 0 : CastToBooleanRange<UINT4>());
761 0 : break;
762 : }
763 0 : default:
764 : {
765 0 : CPLAssert(false);
766 : break;
767 : }
768 : }
769 10 : }
770 :
771 0 : void castValuesToDirectionRange(void *buffer, size_t size)
772 : {
773 : std::for_each(static_cast<REAL4 *>(buffer),
774 0 : static_cast<REAL4 *>(buffer) + size, CastToDirection());
775 0 : }
776 :
777 0 : void castValuesToLddRange(void *buffer, size_t size)
778 : {
779 : std::for_each(static_cast<UINT1 *>(buffer),
780 0 : static_cast<UINT1 *>(buffer) + size, CastToLdd());
781 0 : }
|