Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Implementation of GDALRasterAttributeTable and related classes.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2005, Frank Warmerdam
9 : * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "gdal.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_rat.h"
18 :
19 : #include <cmath>
20 : #include <cstddef>
21 : #include <cstdlib>
22 :
23 : #include <algorithm>
24 : #include <vector>
25 :
26 : #include "cpl_conv.h"
27 : #include "cpl_error.h"
28 : #include "cpl_string.h"
29 : #include "cpl_vsi.h"
30 : #include "cpl_vsi_virtual.h"
31 :
32 : #ifdef __clang__
33 : #pragma clang diagnostic push
34 : #pragma clang diagnostic ignored "-Wunknown-pragmas"
35 : #pragma clang diagnostic ignored "-Wdocumentation"
36 : #pragma clang diagnostic ignored "-Wold-style-cast"
37 : #endif
38 : #include "json.h"
39 : #ifdef __clang__
40 : #pragma clang diagnostic pop
41 : #endif
42 : #include "ogrlibjsonutils.h"
43 :
44 : // NOTE: keep the below description in sync with doc/source/user/raster_data_model.rst::raster_data_model_rat
45 :
46 : /**
47 : * \class GDALRasterAttributeTable
48 : *
49 : * The GDALRasterAttributeTable (or RAT) class is used to encapsulate a table
50 : * used to provide attribute information about pixel values. Each row
51 : * in the table applies to a range of pixel values (or a single value in
52 : * some cases), and might have attributes such as the histogram count for
53 : * that range, the color pixels of that range should be drawn names of classes
54 : * or any other generic information.
55 : *
56 : * Raster attribute tables can be used to represent histograms, color tables,
57 : * and classification information.
58 : *
59 : * Each column in a raster attribute table has a name, a type (integer,
60 : * floating point, string, boolean, date time, geometries encoded as WKB),
61 : * and a GDALRATFieldUsage.
62 : * The usage distinguishes columns with particular understood purposes
63 : * (such as color, histogram count, name) and columns that have specific
64 : * purposes not understood by the library (long label,
65 : * suitability_for_growing_wheat, etc).
66 : *
67 : * In the general case each row has a column indicating the minimum pixel
68 : * values falling into that category, and a column indicating the maximum
69 : * pixel value. These are indicated with usage values of GFU_Min, and
70 : * GFU_Max. In other cases where each row is a discrete pixel value, one
71 : * column of usage GFU_MinMax can be used.
72 : *
73 : * In other cases all the categories are of equal size and regularly spaced
74 : * and the categorization information can be determined just by knowing the
75 : * value at which the categories start, and the size of a category. This
76 : * is called "Linear Binning" and the information is kept specially on
77 : * the raster attribute table as a whole.
78 : *
79 : * RATs are normally associated with GDALRasterBands and can be queried
80 : * using the GDALRasterBand::GetDefaultRAT() method.
81 : */
82 :
83 : /************************************************************************/
84 : /* GDALGetRATFieldTypeName() */
85 : /************************************************************************/
86 :
87 : /** Return the string representation of a GDALRATFieldType.
88 : *
89 : * @since 3.12
90 : */
91 74 : const char *GDALGetRATFieldTypeName(GDALRATFieldType eType)
92 : {
93 : #define CASE_GFT(x) \
94 : case GFT_##x: \
95 : return #x
96 :
97 74 : switch (eType)
98 : {
99 31 : CASE_GFT(Integer);
100 11 : CASE_GFT(String);
101 12 : CASE_GFT(Real);
102 8 : CASE_GFT(Boolean);
103 6 : CASE_GFT(DateTime);
104 6 : case GFT_WKBGeometry:
105 6 : break;
106 : }
107 6 : return "WKBGeometry";
108 :
109 : #undef CASE_GFT
110 : }
111 :
112 : /************************************************************************/
113 : /* GDALGetRATFieldUsageName() */
114 : /************************************************************************/
115 :
116 : /** Return the string representation of a GDALRATFieldUsage.
117 : *
118 : * @since 3.12
119 : */
120 74 : const char *GDALGetRATFieldUsageName(GDALRATFieldUsage eUsage)
121 : {
122 : #define CASE_GFU(x) \
123 : case GFU_##x: \
124 : return #x
125 :
126 74 : switch (eUsage)
127 : {
128 50 : CASE_GFU(Generic);
129 5 : CASE_GFU(PixelCount);
130 2 : CASE_GFU(Name);
131 0 : CASE_GFU(Min);
132 0 : CASE_GFU(Max);
133 17 : CASE_GFU(MinMax);
134 0 : CASE_GFU(Red);
135 0 : CASE_GFU(Green);
136 0 : CASE_GFU(Blue);
137 0 : CASE_GFU(Alpha);
138 0 : CASE_GFU(RedMin);
139 0 : CASE_GFU(GreenMin);
140 0 : CASE_GFU(BlueMin);
141 0 : CASE_GFU(AlphaMin);
142 0 : CASE_GFU(RedMax);
143 0 : CASE_GFU(GreenMax);
144 0 : CASE_GFU(BlueMax);
145 0 : CASE_GFU(AlphaMax);
146 0 : case GFU_MaxCount:
147 0 : break;
148 : }
149 0 : return "MaxCount";
150 :
151 : #undef CASE_GFU
152 : }
153 :
154 : /************************************************************************/
155 : /* ~GDALRasterAttributeTable() */
156 : /* */
157 : /* Virtual Destructor */
158 : /************************************************************************/
159 :
160 : GDALRasterAttributeTable::~GDALRasterAttributeTable() = default;
161 :
162 : /************************************************************************/
163 : /* ValuesIO() */
164 : /* */
165 : /* Default Implementations */
166 : /************************************************************************/
167 :
168 : /**
169 : * \brief Read or Write a block of doubles to/from the Attribute Table.
170 : *
171 : * This method is the same as the C function GDALRATValuesIOAsDouble().
172 : *
173 : * @param eRWFlag either GF_Read or GF_Write
174 : * @param iField column of the Attribute Table
175 : * @param iStartRow start row to start reading/writing (zero based)
176 : * @param iLength number of rows to read or write
177 : * @param pdfData pointer to array of doubles to read/write. Should be at least
178 : * iLength long.
179 : *
180 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
181 : * rows in table.
182 : */
183 :
184 8 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
185 : int iStartRow, int iLength,
186 : double *pdfData)
187 : {
188 8 : if ((iStartRow + iLength) > GetRowCount())
189 : {
190 0 : return CE_Failure;
191 : }
192 :
193 8 : CPLErr eErr = CE_None;
194 8 : if (eRWFlag == GF_Read)
195 : {
196 28 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
197 : {
198 22 : pdfData[iIndex - iStartRow] = GetValueAsDouble(iIndex, iField);
199 : }
200 : }
201 : else
202 : {
203 2 : for (int iIndex = iStartRow;
204 4 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
205 : {
206 2 : eErr = SetValue(iIndex, iField, pdfData[iIndex - iStartRow]);
207 : }
208 : }
209 8 : return eErr;
210 : }
211 :
212 : /************************************************************************/
213 : /* GDALRATValuesIOAsDouble() */
214 : /************************************************************************/
215 :
216 : /**
217 : * \brief Read or Write a block of doubles to/from the Attribute Table.
218 : *
219 : * This function is the same as the C++ method
220 : * GDALRasterAttributeTable::ValuesIO()
221 : */
222 30 : CPLErr CPL_STDCALL GDALRATValuesIOAsDouble(GDALRasterAttributeTableH hRAT,
223 : GDALRWFlag eRWFlag, int iField,
224 : int iStartRow, int iLength,
225 : double *pdfData)
226 :
227 : {
228 30 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDouble", CE_Failure);
229 :
230 60 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
231 30 : eRWFlag, iField, iStartRow, iLength, pdfData);
232 : }
233 :
234 : /**
235 : * \brief Read or Write a block of integers to/from the Attribute Table.
236 : *
237 : * This method is the same as the C function GDALRATValuesIOAsInteger().
238 : *
239 : * @param eRWFlag either GF_Read or GF_Write
240 : * @param iField column of the Attribute Table
241 : * @param iStartRow start row to start reading/writing (zero based)
242 : * @param iLength number of rows to read or write
243 : * @param pnData pointer to array of ints to read/write. Should be at least
244 : * iLength long.
245 : *
246 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
247 : * rows in table.
248 : */
249 :
250 11 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
251 : int iStartRow, int iLength,
252 : int *pnData)
253 : {
254 11 : if ((iStartRow + iLength) > GetRowCount())
255 : {
256 1 : return CE_Failure;
257 : }
258 :
259 10 : CPLErr eErr = CE_None;
260 10 : if (eRWFlag == GF_Read)
261 : {
262 52 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
263 : {
264 42 : pnData[iIndex - iStartRow] = GetValueAsInt(iIndex, iField);
265 : }
266 : }
267 : else
268 : {
269 0 : for (int iIndex = iStartRow;
270 0 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
271 : {
272 0 : eErr = SetValue(iIndex, iField, pnData[iIndex - iStartRow]);
273 : }
274 : }
275 10 : return eErr;
276 : }
277 :
278 : /************************************************************************/
279 : /* GDALRATValuesIOAsInteger() */
280 : /************************************************************************/
281 :
282 : /**
283 : * \brief Read or Write a block of ints to/from the Attribute Table.
284 : *
285 : * This function is the same as the C++ method
286 : * GDALRasterAttributeTable::ValuesIO()
287 : */
288 33 : CPLErr CPL_STDCALL GDALRATValuesIOAsInteger(GDALRasterAttributeTableH hRAT,
289 : GDALRWFlag eRWFlag, int iField,
290 : int iStartRow, int iLength,
291 : int *pnData)
292 :
293 : {
294 33 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsInteger", CE_Failure);
295 :
296 66 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
297 33 : eRWFlag, iField, iStartRow, iLength, pnData);
298 : }
299 :
300 : /**
301 : * \brief Read or Write a block of strings to/from the Attribute Table.
302 : *
303 : * This method is the same as the C function GDALRATValuesIOAsString().
304 : * When reading, papszStrList must be already allocated to the correct size.
305 : * The caller is expected to call CPLFree on each read string.
306 : *
307 : * @param eRWFlag either GF_Read or GF_Write
308 : * @param iField column of the Attribute Table
309 : * @param iStartRow start row to start reading/writing (zero based)
310 : * @param iLength number of rows to read or write
311 : * @param papszStrList pointer to array of strings to read/write. Should be at
312 : * least iLength long.
313 : *
314 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
315 : * rows in table.
316 : */
317 :
318 6 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
319 : int iStartRow, int iLength,
320 : char **papszStrList)
321 : {
322 6 : if ((iStartRow + iLength) > GetRowCount())
323 : {
324 0 : return CE_Failure;
325 : }
326 :
327 6 : CPLErr eErr = CE_None;
328 6 : if (eRWFlag == GF_Read)
329 : {
330 28 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
331 : {
332 44 : papszStrList[iIndex - iStartRow] =
333 22 : VSIStrdup(GetValueAsString(iIndex, iField));
334 : }
335 : }
336 : else
337 : {
338 0 : for (int iIndex = iStartRow;
339 0 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
340 : {
341 0 : eErr = SetValue(iIndex, iField, papszStrList[iIndex - iStartRow]);
342 : }
343 : }
344 6 : return eErr;
345 : }
346 :
347 : /************************************************************************/
348 : /* GDALRATValuesIOAsString() */
349 : /************************************************************************/
350 :
351 : /**
352 : * \brief Read or Write a block of strings to/from the Attribute Table.
353 : *
354 : * This function is the same as the C++ method
355 : * GDALRasterAttributeTable::ValuesIO()
356 : */
357 30 : CPLErr CPL_STDCALL GDALRATValuesIOAsString(GDALRasterAttributeTableH hRAT,
358 : GDALRWFlag eRWFlag, int iField,
359 : int iStartRow, int iLength,
360 : char **papszStrList)
361 :
362 : {
363 30 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsString", CE_Failure);
364 :
365 60 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
366 30 : eRWFlag, iField, iStartRow, iLength, papszStrList);
367 : }
368 :
369 : /************************************************************************/
370 : /* ValuesIO() */
371 : /************************************************************************/
372 :
373 : /**
374 : * \brief Read or Write a block of booleans to/from the Attribute Table.
375 : *
376 : * This method is the same as the C function GDALRATValuesIOAsBoolean().
377 : *
378 : * @param eRWFlag either GF_Read or GF_Write
379 : * @param iField column of the Attribute Table
380 : * @param iStartRow start row to start reading/writing (zero based)
381 : * @param iLength number of rows to read or write
382 : * @param pbData pointer to array of booleans to read/write. Should be at least
383 : * iLength long.
384 : *
385 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
386 : * rows in table.
387 : * @since 3.12
388 : */
389 :
390 5 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
391 : int iStartRow, int iLength,
392 : bool *pbData)
393 : {
394 5 : if ((iStartRow + iLength) > GetRowCount())
395 : {
396 0 : return CE_Failure;
397 : }
398 :
399 5 : CPLErr eErr = CE_None;
400 5 : if (eRWFlag == GF_Read)
401 : {
402 24 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
403 : {
404 20 : pbData[iIndex - iStartRow] = GetValueAsBoolean(iIndex, iField);
405 : }
406 : }
407 : else
408 : {
409 1 : for (int iIndex = iStartRow;
410 6 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
411 : {
412 5 : eErr = SetValue(iIndex, iField, pbData[iIndex - iStartRow]);
413 : }
414 : }
415 5 : return eErr;
416 : }
417 :
418 : /************************************************************************/
419 : /* GDALRATValuesIOAsBoolean() */
420 : /************************************************************************/
421 :
422 : /**
423 : * \brief Read or Write a block of booleans to/from the Attribute Table.
424 : *
425 : * This function is the same as the C++ method
426 : * GDALRasterAttributeTable::ValuesIO()
427 : *
428 : * @since 3.12
429 : */
430 9 : CPLErr GDALRATValuesIOAsBoolean(GDALRasterAttributeTableH hRAT,
431 : GDALRWFlag eRWFlag, int iField, int iStartRow,
432 : int iLength, bool *pbData)
433 :
434 : {
435 9 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsBoolean", CE_Failure);
436 :
437 18 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
438 9 : eRWFlag, iField, iStartRow, iLength, pbData);
439 : }
440 :
441 : /************************************************************************/
442 : /* ValuesIO() */
443 : /************************************************************************/
444 :
445 : /**
446 : * \brief Read or Write a block of DateTime to/from the Attribute Table.
447 : *
448 : * This method is the same as the C function GDALRATValuesIOAsDateTime().
449 : *
450 : * @param eRWFlag either GF_Read or GF_Write
451 : * @param iField column of the Attribute Table
452 : * @param iStartRow start row to start reading/writing (zero based)
453 : * @param iLength number of rows to read or write
454 : * @param psDateTime pointer to array of DateTime to read/write. Should be at
455 : * least iLength long.
456 : *
457 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
458 : * rows in table.
459 : * @since 3.12
460 : */
461 :
462 2 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
463 : int iStartRow, int iLength,
464 : GDALRATDateTime *psDateTime)
465 : {
466 2 : if ((iStartRow + iLength) > GetRowCount())
467 : {
468 0 : return CE_Failure;
469 : }
470 :
471 2 : CPLErr eErr = CE_None;
472 2 : if (eRWFlag == GF_Read)
473 : {
474 3 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
475 : {
476 2 : psDateTime[iIndex - iStartRow] = GetValueAsDateTime(iIndex, iField);
477 : }
478 : }
479 : else
480 : {
481 1 : for (int iIndex = iStartRow;
482 3 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
483 : {
484 2 : eErr = SetValue(iIndex, iField, psDateTime[iIndex - iStartRow]);
485 : }
486 : }
487 2 : return eErr;
488 : }
489 :
490 : /************************************************************************/
491 : /* GDALRATValuesIOAsDateTime() */
492 : /************************************************************************/
493 :
494 : /**
495 : * \brief Read or Write a block of date-times to/from the Attribute Table.
496 : *
497 : * This function is the same as the C++ method
498 : * GDALRasterAttributeTable::ValuesIO()
499 : *
500 : * @since 3.12
501 : */
502 2 : CPLErr GDALRATValuesIOAsDateTime(GDALRasterAttributeTableH hRAT,
503 : GDALRWFlag eRWFlag, int iField, int iStartRow,
504 : int iLength, GDALRATDateTime *psDateTime)
505 :
506 : {
507 2 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDateTime", CE_Failure);
508 :
509 4 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
510 2 : eRWFlag, iField, iStartRow, iLength, psDateTime);
511 : }
512 :
513 : /************************************************************************/
514 : /* ValuesIO() */
515 : /************************************************************************/
516 :
517 : /**
518 : * \brief Read or Write a block of WKB-encoded geometries to/from the Attribute Table.
519 : *
520 : * When reading, each ppabyWKB[] should be CPLFree'd() after use.
521 : *
522 : * This method is the same as the C function GDALRATValuesIOAsWKBGeometry().
523 : *
524 : * @param eRWFlag either GF_Read or GF_Write
525 : * @param iField column of the Attribute Table
526 : * @param iStartRow start row to start reading/writing (zero based)
527 : * @param iLength number of rows to read or write
528 : * @param ppabyWKB pointer to array of pointer of WKB-encoded geometries to
529 : * read/write. Should be at least iLength long.
530 : * @param pnWKBSize pointer to array of WKB size.
531 : * Should be at least iLength long.
532 : *
533 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
534 : * rows in table.
535 : * @since 3.12
536 : */
537 :
538 2 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
539 : int iStartRow, int iLength,
540 : GByte **ppabyWKB, size_t *pnWKBSize)
541 : {
542 2 : if ((iStartRow + iLength) > GetRowCount())
543 : {
544 0 : return CE_Failure;
545 : }
546 :
547 2 : CPLErr eErr = CE_None;
548 2 : if (eRWFlag == GF_Read)
549 : {
550 2 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
551 : {
552 1 : size_t nSize = 0;
553 1 : const GByte *pabyWKB = GetValueAsWKBGeometry(iIndex, iField, nSize);
554 1 : pnWKBSize[iIndex - iStartRow] = nSize;
555 1 : if (nSize)
556 : {
557 2 : ppabyWKB[iIndex - iStartRow] =
558 1 : static_cast<GByte *>(CPLMalloc(nSize));
559 1 : memcpy(ppabyWKB[iIndex - iStartRow], pabyWKB, nSize);
560 : }
561 : else
562 : {
563 0 : ppabyWKB[iIndex - iStartRow] = nullptr;
564 : }
565 : }
566 : }
567 : else
568 : {
569 1 : for (int iIndex = iStartRow;
570 2 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
571 : {
572 1 : eErr = SetValue(iIndex, iField, ppabyWKB[iIndex - iStartRow],
573 1 : pnWKBSize[iIndex - iStartRow]);
574 : }
575 : }
576 2 : return eErr;
577 : }
578 :
579 : /************************************************************************/
580 : /* GDALRATValuesIOAsWKBGeometry() */
581 : /************************************************************************/
582 :
583 : /**
584 : * \brief Read or Write a block of WKB-encoded geometries to/from the Attribute Table.
585 : *
586 : * When reading, each ppabyWKB[] should be CPLFree'd() after use.
587 : *
588 : * This function is the same as the C++ method
589 : * GDALRasterAttributeTable::ValuesIO()
590 : *
591 : * @since 3.12
592 : */
593 2 : CPLErr GDALRATValuesIOAsWKBGeometry(GDALRasterAttributeTableH hRAT,
594 : GDALRWFlag eRWFlag, int iField,
595 : int iStartRow, int iLength,
596 : GByte **ppabyWKB, size_t *pnWKBSize)
597 :
598 : {
599 2 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsWKBGeometry", CE_Failure);
600 :
601 4 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
602 2 : eRWFlag, iField, iStartRow, iLength, ppabyWKB, pnWKBSize);
603 : }
604 :
605 : //! @cond Doxygen_Suppress
606 :
607 : /************************************************************************/
608 : /* ValuesIOBooleanFromIntoInt() */
609 : /************************************************************************/
610 :
611 7 : CPLErr GDALRasterAttributeTable::ValuesIOBooleanFromIntoInt(
612 : GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, bool *pbData)
613 : {
614 7 : if (eRWFlag == GF_Read)
615 : {
616 6 : std::vector<int> anData(iLength);
617 : CPLErr eErr =
618 6 : ValuesIO(eRWFlag, iField, iStartRow, iLength, anData.data());
619 6 : if (eErr == CE_None)
620 : {
621 4 : for (int i = 0; i < iLength; ++i)
622 : {
623 2 : pbData[i] = anData[i] != 0;
624 : }
625 : }
626 6 : return eErr;
627 : }
628 : else
629 : {
630 2 : std::vector<int> anData;
631 1 : anData.reserve(iLength);
632 2 : for (int i = 0; i < iLength; ++i)
633 1 : anData.push_back(pbData[i]);
634 1 : return ValuesIO(eRWFlag, iField, iStartRow, iLength, anData.data());
635 : }
636 : }
637 :
638 : /************************************************************************/
639 : /* DateTimeToString() */
640 : /************************************************************************/
641 :
642 : /* static */
643 : std::string
644 24 : GDALRasterAttributeTable::DateTimeToString(const GDALRATDateTime &sDateTime)
645 : {
646 24 : if (!sDateTime.bIsValid)
647 3 : return std::string();
648 42 : return CPLString().Printf(
649 21 : "%04d-%02d-%02dT%02d:%02d:%06.3f%c%02d:%02d", sDateTime.nYear,
650 21 : sDateTime.nMonth, sDateTime.nDay, sDateTime.nHour, sDateTime.nMinute,
651 21 : static_cast<double>(sDateTime.fSecond),
652 21 : sDateTime.bPositiveTimeZone ? '+' : '-', sDateTime.nTimeZoneHour,
653 21 : sDateTime.nTimeZoneMinute);
654 : }
655 :
656 : /************************************************************************/
657 : /* StringToDateTime() */
658 : /************************************************************************/
659 :
660 : /* static */
661 19 : bool GDALRasterAttributeTable::StringToDateTime(const char *pszStr,
662 : GDALRATDateTime &sDateTime)
663 : {
664 : OGRField sField;
665 19 : if (OGRParseDate(pszStr, &sField, 0))
666 : {
667 16 : sDateTime.nYear = sField.Date.Year;
668 16 : sDateTime.nMonth = sField.Date.Month;
669 16 : sDateTime.nDay = sField.Date.Day;
670 16 : sDateTime.nHour = sField.Date.Hour;
671 16 : sDateTime.nMinute = sField.Date.Minute;
672 16 : sDateTime.fSecond = sField.Date.Second;
673 16 : sDateTime.bPositiveTimeZone =
674 16 : sField.Date.TZFlag <= 2 ? false : sField.Date.TZFlag >= 100;
675 32 : sDateTime.nTimeZoneHour = sField.Date.TZFlag <= 2
676 16 : ? 0
677 16 : : std::abs(sField.Date.TZFlag - 100) / 4;
678 16 : sDateTime.nTimeZoneMinute =
679 16 : sField.Date.TZFlag <= 2
680 16 : ? 0
681 16 : : (std::abs(sField.Date.TZFlag - 100) % 4) * 15;
682 16 : sDateTime.bIsValid = true;
683 16 : return true;
684 : }
685 : else
686 : {
687 3 : sDateTime = GDALRATDateTime();
688 3 : return false;
689 : }
690 : }
691 :
692 : /************************************************************************/
693 : /* ValuesIODateTimeFromIntoString() */
694 : /************************************************************************/
695 :
696 12 : CPLErr GDALRasterAttributeTable::ValuesIODateTimeFromIntoString(
697 : GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
698 : GDALRATDateTime *psDateTime)
699 : {
700 12 : if (eRWFlag == GF_Read)
701 : {
702 7 : std::vector<char *> apszStrList(iLength);
703 : CPLErr eErr =
704 7 : ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStrList.data());
705 7 : if (eErr == CE_None)
706 : {
707 8 : for (int i = 0; i < iLength; ++i)
708 : {
709 4 : StringToDateTime(apszStrList[i], psDateTime[i]);
710 : }
711 : }
712 14 : for (int i = 0; i < iLength; ++i)
713 7 : VSIFree(apszStrList[i]);
714 7 : return eErr;
715 : }
716 : else
717 : {
718 10 : std::vector<std::string> asStr;
719 10 : std::vector<char *> apszStr;
720 5 : asStr.reserve(iLength);
721 5 : apszStr.reserve(iLength);
722 10 : for (int i = 0; i < iLength; ++i)
723 : {
724 5 : asStr.push_back(DateTimeToString(psDateTime[i]));
725 5 : apszStr.push_back(asStr.back().data());
726 : }
727 5 : return ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStr.data());
728 : }
729 : }
730 :
731 : /************************************************************************/
732 : /* WKBGeometryToWKT() */
733 : /************************************************************************/
734 :
735 : /* static */
736 13 : std::string GDALRasterAttributeTable::WKBGeometryToWKT(const void *pabyWKB,
737 : size_t nWKBSize)
738 : {
739 13 : std::string osWKT;
740 13 : if (nWKBSize)
741 : {
742 9 : OGRGeometry *poGeometry = nullptr;
743 9 : if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeometry,
744 : nWKBSize,
745 9 : wkbVariantIso) == OGRERR_NONE)
746 : {
747 9 : osWKT = poGeometry->exportToWkt();
748 : }
749 9 : delete poGeometry;
750 : }
751 13 : return osWKT;
752 : }
753 :
754 : /************************************************************************/
755 : /* WKTGeometryToWKB() */
756 : /************************************************************************/
757 :
758 : /* static */
759 : std::vector<GByte>
760 19 : GDALRasterAttributeTable::WKTGeometryToWKB(const char *pszWKT)
761 : {
762 19 : std::vector<GByte> abyWKB;
763 19 : OGRGeometry *poGeom = nullptr;
764 19 : if (pszWKT[0] && OGRGeometryFactory::createFromWkt(pszWKT, nullptr,
765 : &poGeom) == OGRERR_NONE)
766 : {
767 16 : const size_t nWKBSize = poGeom->WkbSize();
768 16 : abyWKB.resize(nWKBSize);
769 16 : poGeom->exportToWkb(wkbNDR, abyWKB.data(), wkbVariantIso);
770 : }
771 19 : delete poGeom;
772 38 : return abyWKB;
773 : }
774 :
775 : /************************************************************************/
776 : /* ValuesIOWKBGeometryFromIntoString() */
777 : /************************************************************************/
778 :
779 12 : CPLErr GDALRasterAttributeTable::ValuesIOWKBGeometryFromIntoString(
780 : GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
781 : GByte **ppabyWKB, size_t *pnWKBSize)
782 : {
783 12 : if (eRWFlag == GF_Read)
784 : {
785 7 : std::vector<char *> apszStrList(iLength);
786 : CPLErr eErr =
787 7 : ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStrList.data());
788 7 : if (eErr == CE_None)
789 : {
790 8 : for (int i = 0; i < iLength; ++i)
791 : {
792 8 : auto abyWKB = WKTGeometryToWKB(apszStrList[i]);
793 4 : if (abyWKB.empty())
794 : {
795 2 : ppabyWKB[i] = nullptr;
796 2 : pnWKBSize[i] = 0;
797 : }
798 : else
799 : {
800 4 : ppabyWKB[i] =
801 2 : static_cast<GByte *>(CPLMalloc(abyWKB.size()));
802 2 : memcpy(ppabyWKB[i], abyWKB.data(), abyWKB.size());
803 2 : pnWKBSize[i] = abyWKB.size();
804 : }
805 : }
806 : }
807 14 : for (int i = 0; i < iLength; ++i)
808 7 : VSIFree(apszStrList[i]);
809 7 : return eErr;
810 : }
811 : else
812 : {
813 10 : std::vector<std::string> asStr;
814 10 : std::vector<char *> apszStr;
815 5 : asStr.reserve(iLength);
816 5 : apszStr.reserve(iLength);
817 10 : for (int i = 0; i < iLength; ++i)
818 : {
819 5 : asStr.push_back(WKBGeometryToWKT(ppabyWKB[i], pnWKBSize[i]));
820 5 : apszStr.push_back(asStr.back().data());
821 : }
822 5 : return ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStr.data());
823 : }
824 : }
825 :
826 : //! @endcond
827 :
828 : /************************************************************************/
829 : /* SetRowCount() */
830 : /************************************************************************/
831 :
832 : /**
833 : * \brief Set row count.
834 : *
835 : * Resizes the table to include the indicated number of rows. Newly created
836 : * rows will be initialized to their default values - "" for strings,
837 : * and zero for numeric fields.
838 : *
839 : * This method is the same as the C function GDALRATSetRowCount().
840 : *
841 : * @param nNewCount the new number of rows.
842 : */
843 :
844 0 : void GDALRasterAttributeTable::SetRowCount(CPL_UNUSED int nNewCount)
845 : {
846 0 : }
847 :
848 : /************************************************************************/
849 : /* GDALRATSetRowCount() */
850 : /************************************************************************/
851 :
852 : /**
853 : * \brief Set row count.
854 : *
855 : * This function is the same as the C++ method
856 : * GDALRasterAttributeTable::SetRowCount()
857 : *
858 : * @param hRAT RAT handle.
859 : * @param nNewCount the new number of rows.
860 : */
861 40 : void CPL_STDCALL GDALRATSetRowCount(GDALRasterAttributeTableH hRAT,
862 : int nNewCount)
863 :
864 : {
865 40 : VALIDATE_POINTER0(hRAT, "GDALRATSetRowCount");
866 :
867 40 : GDALRasterAttributeTable::FromHandle(hRAT)->SetRowCount(nNewCount);
868 : }
869 :
870 : /************************************************************************/
871 : /* GetRowOfValue() */
872 : /************************************************************************/
873 :
874 : /**
875 : * \fn GDALRasterAttributeTable::GetRowOfValue(double) const
876 : * \brief Get row for pixel value.
877 : *
878 : * Given a raw pixel value, the raster attribute table is scanned to
879 : * determine which row in the table applies to the pixel value. The
880 : * row index is returned.
881 : *
882 : * This method is the same as the C function GDALRATGetRowOfValue().
883 : *
884 : * @param dfValue the pixel value.
885 : *
886 : * @return the row index or -1 if no row is appropriate.
887 : */
888 :
889 : /**/
890 : /**/
891 :
892 0 : int GDALRasterAttributeTable::GetRowOfValue(double /* dfValue */) const
893 : {
894 0 : return -1;
895 : }
896 :
897 : /************************************************************************/
898 : /* GDALRATGetRowOfValue() */
899 : /************************************************************************/
900 :
901 : /**
902 : * \brief Get row for pixel value.
903 : *
904 : * This function is the same as the C++ method
905 : * GDALRasterAttributeTable::GetRowOfValue()
906 : */
907 3 : int CPL_STDCALL GDALRATGetRowOfValue(GDALRasterAttributeTableH hRAT,
908 : double dfValue)
909 :
910 : {
911 3 : VALIDATE_POINTER1(hRAT, "GDALRATGetRowOfValue", 0);
912 :
913 3 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowOfValue(dfValue);
914 : }
915 :
916 : /************************************************************************/
917 : /* GetRowOfValue() */
918 : /************************************************************************/
919 :
920 : /**
921 : * \brief Get row for pixel value.
922 : *
923 : * Given a raw pixel value, the raster attribute table is scanned to
924 : * determine which row in the table applies to the pixel value. The
925 : * row index is returned.
926 : *
927 : * Int arg for now just converted to double. Perhaps we will
928 : * handle this in a special way some day?
929 : *
930 : * This method is the same as the C function GDALRATGetRowOfValue().
931 : *
932 : * @param nValue the pixel value.
933 : *
934 : * @return the row index or -1 if no row is appropriate.
935 : */
936 :
937 0 : int GDALRasterAttributeTable::GetRowOfValue(int nValue) const
938 :
939 : {
940 0 : return GetRowOfValue(static_cast<double>(nValue));
941 : }
942 :
943 : /************************************************************************/
944 : /* CreateColumn() */
945 : /************************************************************************/
946 :
947 : /**
948 : * \fn GDALRasterAttributeTable::CreateColumn(const char*, GDALRATFieldType,
949 : * GDALRATFieldUsage) \brief Create new column.
950 : *
951 : * If the table already has rows, all row values for the new column will
952 : * be initialized to the default value ("", or zero). The new column is
953 : * always created as the last column, and will be column (field)
954 : * "GetColumnCount()-1" after CreateColumn() has completed successfully.
955 : *
956 : * This method is the same as the C function GDALRATCreateColumn().
957 : *
958 : * @param pszFieldName the name of the field to create.
959 : * @param eFieldType the field type (integer, double or string).
960 : * @param eFieldUsage the field usage, GFU_Generic if not known.
961 : *
962 : * @return CE_None on success or CE_Failure if something goes wrong.
963 : */
964 :
965 : /**/
966 : /**/
967 :
968 : CPLErr
969 0 : GDALRasterAttributeTable::CreateColumn(const char * /* pszFieldName */,
970 : GDALRATFieldType /* eFieldType */,
971 : GDALRATFieldUsage /* eFieldUsage */)
972 : {
973 0 : return CE_Failure;
974 : }
975 :
976 : /************************************************************************/
977 : /* GDALRATCreateColumn() */
978 : /************************************************************************/
979 :
980 : /**
981 : * \brief Create new column.
982 : *
983 : * This function is the same as the C++ method
984 : * GDALRasterAttributeTable::CreateColumn()
985 : */
986 182 : CPLErr CPL_STDCALL GDALRATCreateColumn(GDALRasterAttributeTableH hRAT,
987 : const char *pszFieldName,
988 : GDALRATFieldType eFieldType,
989 : GDALRATFieldUsage eFieldUsage)
990 :
991 : {
992 182 : VALIDATE_POINTER1(hRAT, "GDALRATCreateColumn", CE_Failure);
993 :
994 364 : return GDALRasterAttributeTable::FromHandle(hRAT)->CreateColumn(
995 182 : pszFieldName, eFieldType, eFieldUsage);
996 : }
997 :
998 : /************************************************************************/
999 : /* SetLinearBinning() */
1000 : /************************************************************************/
1001 :
1002 : /**
1003 : * \brief Set linear binning information.
1004 : *
1005 : * For RATs with equal sized categories (in pixel value space) that are
1006 : * evenly spaced, this method may be used to associate the linear binning
1007 : * information with the table.
1008 : *
1009 : * This method is the same as the C function GDALRATSetLinearBinning().
1010 : *
1011 : * @param dfRow0MinIn the lower bound (pixel value) of the first category.
1012 : * @param dfBinSizeIn the width of each category (in pixel value units).
1013 : *
1014 : * @return CE_None on success or CE_Failure on failure.
1015 : */
1016 :
1017 0 : CPLErr GDALRasterAttributeTable::SetLinearBinning(CPL_UNUSED double dfRow0MinIn,
1018 : CPL_UNUSED double dfBinSizeIn)
1019 : {
1020 0 : return CE_Failure;
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* GDALRATSetLinearBinning() */
1025 : /************************************************************************/
1026 :
1027 : /**
1028 : * \brief Set linear binning information.
1029 : *
1030 : * This function is the same as the C++ method
1031 : * GDALRasterAttributeTable::SetLinearBinning()
1032 : */
1033 1 : CPLErr CPL_STDCALL GDALRATSetLinearBinning(GDALRasterAttributeTableH hRAT,
1034 : double dfRow0Min, double dfBinSize)
1035 :
1036 : {
1037 1 : VALIDATE_POINTER1(hRAT, "GDALRATSetLinearBinning", CE_Failure);
1038 :
1039 2 : return GDALRasterAttributeTable::FromHandle(hRAT)->SetLinearBinning(
1040 1 : dfRow0Min, dfBinSize);
1041 : }
1042 :
1043 : /************************************************************************/
1044 : /* GetLinearBinning() */
1045 : /************************************************************************/
1046 :
1047 : /**
1048 : * \brief Get linear binning information.
1049 : *
1050 : * Returns linear binning information if any is associated with the RAT.
1051 : *
1052 : * This method is the same as the C function GDALRATGetLinearBinning().
1053 : *
1054 : * @param pdfRow0Min (out) the lower bound (pixel value) of the first category.
1055 : * @param pdfBinSize (out) the width of each category (in pixel value units).
1056 : *
1057 : * @return TRUE if linear binning information exists or FALSE if there is none.
1058 : */
1059 :
1060 0 : int GDALRasterAttributeTable::GetLinearBinning(
1061 : CPL_UNUSED double *pdfRow0Min, CPL_UNUSED double *pdfBinSize) const
1062 : {
1063 0 : return false;
1064 : }
1065 :
1066 : /************************************************************************/
1067 : /* GDALRATGetLinearBinning() */
1068 : /************************************************************************/
1069 :
1070 : /**
1071 : * \brief Get linear binning information.
1072 : *
1073 : * This function is the same as the C++ method
1074 : * GDALRasterAttributeTable::GetLinearBinning()
1075 : */
1076 1 : int CPL_STDCALL GDALRATGetLinearBinning(GDALRasterAttributeTableH hRAT,
1077 : double *pdfRow0Min, double *pdfBinSize)
1078 :
1079 : {
1080 1 : VALIDATE_POINTER1(hRAT, "GDALRATGetLinearBinning", 0);
1081 :
1082 2 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetLinearBinning(
1083 1 : pdfRow0Min, pdfBinSize);
1084 : }
1085 :
1086 : /************************************************************************/
1087 : /* GDALRATGetTableType() */
1088 : /************************************************************************/
1089 :
1090 : /**
1091 : * \brief Get Rat Table Type
1092 : *
1093 : *
1094 : * This function is the same as the C++ method
1095 : * GDALRasterAttributeTable::GetTableType()
1096 : */
1097 10 : GDALRATTableType CPL_STDCALL GDALRATGetTableType(GDALRasterAttributeTableH hRAT)
1098 : {
1099 10 : VALIDATE_POINTER1(hRAT, "GDALRATGetTableType", GRTT_THEMATIC);
1100 :
1101 10 : return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->GetTableType();
1102 : }
1103 :
1104 : /************************************************************************/
1105 : /* GDALRATSetTableType() */
1106 : /************************************************************************/
1107 :
1108 : /**
1109 : * \brief Set RAT Table Type
1110 : *
1111 : *
1112 : * This function is the same as the C++ method
1113 : * GDALRasterAttributeTable::SetTableType()
1114 : */
1115 3 : CPLErr CPL_STDCALL GDALRATSetTableType(GDALRasterAttributeTableH hRAT,
1116 : const GDALRATTableType eInTableType)
1117 :
1118 : {
1119 3 : VALIDATE_POINTER1(hRAT, "GDALRATSetTableType", CE_Failure);
1120 :
1121 6 : return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->SetTableType(
1122 3 : eInTableType);
1123 : }
1124 :
1125 : /************************************************************************/
1126 : /* Serialize() */
1127 : /************************************************************************/
1128 :
1129 : /** Serialize as a XML tree.
1130 : * @return XML tree.
1131 : */
1132 33 : CPLXMLNode *GDALRasterAttributeTable::Serialize() const
1133 :
1134 : {
1135 33 : if ((GetColumnCount() == 0) && (GetRowCount() == 0))
1136 2 : return nullptr;
1137 :
1138 : CPLXMLNode *psTree =
1139 31 : CPLCreateXMLNode(nullptr, CXT_Element, "GDALRasterAttributeTable");
1140 :
1141 : /* -------------------------------------------------------------------- */
1142 : /* Add attributes with regular binning info if appropriate. */
1143 : /* -------------------------------------------------------------------- */
1144 31 : char szValue[128] = {'\0'};
1145 31 : double dfRow0Min = 0.0;
1146 31 : double dfBinSize = 0.0;
1147 :
1148 31 : if (GetLinearBinning(&dfRow0Min, &dfBinSize))
1149 : {
1150 4 : CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfRow0Min);
1151 4 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "Row0Min"),
1152 : CXT_Text, szValue);
1153 :
1154 4 : CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfBinSize);
1155 4 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "BinSize"),
1156 : CXT_Text, szValue);
1157 : }
1158 :
1159 : /* -------------------------------------------------------------------- */
1160 : /* Store table type */
1161 : /* -------------------------------------------------------------------- */
1162 31 : const GDALRATTableType tableType = GetTableType();
1163 31 : if (tableType == GRTT_ATHEMATIC)
1164 : {
1165 3 : CPLsnprintf(szValue, sizeof(szValue), "athematic");
1166 : }
1167 : else
1168 : {
1169 28 : CPLsnprintf(szValue, sizeof(szValue), "thematic");
1170 : }
1171 31 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "tableType"),
1172 : CXT_Text, szValue);
1173 :
1174 : /* -------------------------------------------------------------------- */
1175 : /* Define each column. */
1176 : /* -------------------------------------------------------------------- */
1177 31 : const int iColCount = GetColumnCount();
1178 :
1179 105 : for (int iCol = 0; iCol < iColCount; iCol++)
1180 : {
1181 74 : CPLXMLNode *psCol = CPLCreateXMLNode(psTree, CXT_Element, "FieldDefn");
1182 :
1183 74 : snprintf(szValue, sizeof(szValue), "%d", iCol);
1184 74 : CPLCreateXMLNode(CPLCreateXMLNode(psCol, CXT_Attribute, "index"),
1185 : CXT_Text, szValue);
1186 :
1187 74 : CPLCreateXMLElementAndValue(psCol, "Name", GetNameOfCol(iCol));
1188 :
1189 74 : snprintf(szValue, sizeof(szValue), "%d",
1190 74 : static_cast<int>(GetTypeOfCol(iCol)));
1191 : CPLXMLNode *psType =
1192 74 : CPLCreateXMLElementAndValue(psCol, "Type", szValue);
1193 74 : CPLAddXMLAttributeAndValue(psType, "typeAsString",
1194 74 : GDALGetRATFieldTypeName(GetTypeOfCol(iCol)));
1195 :
1196 74 : snprintf(szValue, sizeof(szValue), "%d",
1197 74 : static_cast<int>(GetUsageOfCol(iCol)));
1198 : CPLXMLNode *psUsage =
1199 74 : CPLCreateXMLElementAndValue(psCol, "Usage", szValue);
1200 74 : CPLAddXMLAttributeAndValue(
1201 : psUsage, "usageAsString",
1202 74 : GDALGetRATFieldUsageName(GetUsageOfCol(iCol)));
1203 : }
1204 :
1205 : /* -------------------------------------------------------------------- */
1206 : /* Write out each row. */
1207 : /* -------------------------------------------------------------------- */
1208 31 : const int iRowCount = GetRowCount();
1209 31 : CPLXMLNode *psTail = nullptr;
1210 31 : CPLXMLNode *psRow = nullptr;
1211 :
1212 1044 : for (int iRow = 0; iRow < iRowCount; iRow++)
1213 : {
1214 1013 : psRow = CPLCreateXMLNode(nullptr, CXT_Element, "Row");
1215 1013 : if (psTail == nullptr)
1216 27 : CPLAddXMLChild(psTree, psRow);
1217 : else
1218 986 : psTail->psNext = psRow;
1219 1013 : psTail = psRow;
1220 :
1221 1013 : snprintf(szValue, sizeof(szValue), "%d", iRow);
1222 1013 : CPLCreateXMLNode(CPLCreateXMLNode(psRow, CXT_Attribute, "index"),
1223 : CXT_Text, szValue);
1224 :
1225 2026 : std::string osStr;
1226 2082 : for (int iCol = 0; iCol < iColCount; iCol++)
1227 : {
1228 1069 : const char *pszValue = szValue;
1229 :
1230 1069 : switch (GetTypeOfCol(iCol))
1231 : {
1232 36 : case GFT_Integer:
1233 72 : snprintf(szValue, sizeof(szValue), "%d",
1234 36 : GetValueAsInt(iRow, iCol));
1235 36 : break;
1236 :
1237 995 : case GFT_Real:
1238 995 : CPLsnprintf(szValue, sizeof(szValue), "%.16g",
1239 995 : GetValueAsDouble(iRow, iCol));
1240 995 : break;
1241 :
1242 14 : case GFT_String:
1243 14 : pszValue = GetValueAsString(iRow, iCol);
1244 14 : break;
1245 :
1246 10 : case GFT_Boolean:
1247 10 : pszValue = GetValueAsBoolean(iRow, iCol) ? "true" : "false";
1248 10 : break;
1249 :
1250 7 : case GFT_DateTime:
1251 7 : osStr = DateTimeToString(GetValueAsDateTime(iRow, iCol));
1252 7 : pszValue = osStr.c_str();
1253 7 : break;
1254 :
1255 7 : case GFT_WKBGeometry:
1256 : {
1257 7 : size_t nWKBSize = 0;
1258 : const GByte *pabyWKB =
1259 7 : GetValueAsWKBGeometry(iRow, iCol, nWKBSize);
1260 7 : osStr = WKBGeometryToWKT(pabyWKB, nWKBSize);
1261 7 : pszValue = osStr.c_str();
1262 7 : break;
1263 : }
1264 : }
1265 :
1266 1069 : CPLCreateXMLElementAndValue(psRow, "F", pszValue);
1267 : }
1268 : }
1269 :
1270 31 : return psTree;
1271 : }
1272 :
1273 : /************************************************************************/
1274 : /* SerializeJSON() */
1275 : /************************************************************************/
1276 :
1277 : /** Serialize as a JSON object.
1278 : * @return JSON object (of type json_object*)
1279 : */
1280 9 : void *GDALRasterAttributeTable::SerializeJSON() const
1281 :
1282 : {
1283 9 : json_object *poRAT = json_object_new_object();
1284 :
1285 9 : if ((GetColumnCount() == 0) && (GetRowCount() == 0))
1286 0 : return poRAT;
1287 :
1288 : /* -------------------------------------------------------------------- */
1289 : /* Add attributes with regular binning info if appropriate. */
1290 : /* -------------------------------------------------------------------- */
1291 9 : double dfRow0Min = 0.0;
1292 9 : double dfBinSize = 0.0;
1293 9 : json_object *poRow0Min = nullptr;
1294 9 : json_object *poBinSize = nullptr;
1295 9 : json_object *poTableType = nullptr;
1296 :
1297 9 : if (GetLinearBinning(&dfRow0Min, &dfBinSize))
1298 : {
1299 2 : poRow0Min = json_object_new_double_with_precision(dfRow0Min, 16);
1300 2 : json_object_object_add(poRAT, "row0Min", poRow0Min);
1301 :
1302 2 : poBinSize = json_object_new_double_with_precision(dfBinSize, 16);
1303 2 : json_object_object_add(poRAT, "binSize", poBinSize);
1304 : }
1305 :
1306 : /* -------------------------------------------------------------------- */
1307 : /* Table Type */
1308 : /* -------------------------------------------------------------------- */
1309 9 : const GDALRATTableType tableType = GetTableType();
1310 9 : if (tableType == GRTT_ATHEMATIC)
1311 : {
1312 2 : poTableType = json_object_new_string("athematic");
1313 : }
1314 : else
1315 : {
1316 7 : poTableType = json_object_new_string("thematic");
1317 : }
1318 9 : json_object_object_add(poRAT, "tableType", poTableType);
1319 :
1320 : /* -------------------------------------------------------------------- */
1321 : /* Define each column. */
1322 : /* -------------------------------------------------------------------- */
1323 9 : const int iColCount = GetColumnCount();
1324 9 : json_object *poFieldDefnArray = json_object_new_array();
1325 :
1326 61 : for (int iCol = 0; iCol < iColCount; iCol++)
1327 : {
1328 52 : json_object *const poFieldDefn = json_object_new_object();
1329 :
1330 52 : json_object *const poColumnIndex = json_object_new_int(iCol);
1331 52 : json_object_object_add(poFieldDefn, "index", poColumnIndex);
1332 :
1333 52 : json_object *const poName = json_object_new_string(GetNameOfCol(iCol));
1334 52 : json_object_object_add(poFieldDefn, "name", poName);
1335 :
1336 : json_object *const poType =
1337 52 : json_object_new_int(static_cast<int>(GetTypeOfCol(iCol)));
1338 52 : json_object_object_add(poFieldDefn, "type", poType);
1339 :
1340 : json_object *const poUsage =
1341 52 : json_object_new_int(static_cast<int>(GetUsageOfCol(iCol)));
1342 52 : json_object_object_add(poFieldDefn, "usage", poUsage);
1343 :
1344 52 : json_object_array_add(poFieldDefnArray, poFieldDefn);
1345 : }
1346 :
1347 9 : json_object_object_add(poRAT, "fieldDefn", poFieldDefnArray);
1348 :
1349 : /* -------------------------------------------------------------------- */
1350 : /* Write out each row. */
1351 : /* -------------------------------------------------------------------- */
1352 9 : const int iRowCount = GetRowCount();
1353 9 : json_object *poRowArray = json_object_new_array();
1354 :
1355 941 : for (int iRow = 0; iRow < iRowCount; iRow++)
1356 : {
1357 932 : json_object *const poRow = json_object_new_object();
1358 :
1359 932 : json_object *const poRowIndex = json_object_new_int(iRow);
1360 932 : json_object_object_add(poRow, "index", poRowIndex);
1361 :
1362 932 : json_object *const poFArray = json_object_new_array();
1363 :
1364 4047 : for (int iCol = 0; iCol < iColCount; iCol++)
1365 : {
1366 3115 : json_object *poF = nullptr;
1367 3115 : switch (GetTypeOfCol(iCol))
1368 : {
1369 2854 : case GFT_Integer:
1370 2854 : poF = json_object_new_int(GetValueAsInt(iRow, iCol));
1371 2854 : break;
1372 :
1373 228 : case GFT_Real:
1374 228 : poF = json_object_new_double_with_precision(
1375 228 : GetValueAsDouble(iRow, iCol), 16);
1376 228 : break;
1377 :
1378 17 : case GFT_String:
1379 17 : poF = json_object_new_string(GetValueAsString(iRow, iCol));
1380 17 : break;
1381 :
1382 6 : case GFT_Boolean:
1383 : poF =
1384 6 : json_object_new_boolean(GetValueAsBoolean(iRow, iCol));
1385 6 : break;
1386 :
1387 10 : case GFT_DateTime:
1388 : case GFT_WKBGeometry:
1389 : {
1390 10 : const char *pszV = GetValueAsString(iRow, iCol);
1391 10 : if (pszV[0])
1392 6 : poF = json_object_new_string(pszV);
1393 10 : break;
1394 : }
1395 : }
1396 :
1397 3115 : json_object_array_add(poFArray, poF);
1398 : }
1399 932 : json_object_object_add(poRow, "f", poFArray);
1400 932 : json_object_array_add(poRowArray, poRow);
1401 : }
1402 9 : json_object_object_add(poRAT, "row", poRowArray);
1403 :
1404 9 : return poRAT;
1405 : }
1406 :
1407 : /************************************************************************/
1408 : /* XMLInit() */
1409 : /************************************************************************/
1410 :
1411 : /** Deserialize from XML.
1412 : * @param psTree XML tree
1413 : * @return error code.
1414 : */
1415 36 : CPLErr GDALRasterAttributeTable::XMLInit(const CPLXMLNode *psTree,
1416 : const char * /*pszVRTPath*/)
1417 :
1418 : {
1419 36 : CPLAssert(GetRowCount() == 0 && GetColumnCount() == 0);
1420 :
1421 : /* -------------------------------------------------------------------- */
1422 : /* Linear binning. */
1423 : /* -------------------------------------------------------------------- */
1424 43 : if (CPLGetXMLValue(psTree, "Row0Min", nullptr) &&
1425 7 : CPLGetXMLValue(psTree, "BinSize", nullptr))
1426 : {
1427 7 : SetLinearBinning(CPLAtof(CPLGetXMLValue(psTree, "Row0Min", "")),
1428 7 : CPLAtof(CPLGetXMLValue(psTree, "BinSize", "")));
1429 : }
1430 :
1431 : /* -------------------------------------------------------------------- */
1432 : /* Table Type */
1433 : /* -------------------------------------------------------------------- */
1434 36 : if (CPLGetXMLValue(psTree, "tableType", nullptr))
1435 : {
1436 34 : const char *pszValue = CPLGetXMLValue(psTree, "tableType", "thematic");
1437 34 : if (EQUAL(pszValue, "athematic"))
1438 : {
1439 4 : SetTableType(GRTT_ATHEMATIC);
1440 : }
1441 : else
1442 : {
1443 30 : SetTableType(GRTT_THEMATIC);
1444 : }
1445 : }
1446 :
1447 : /* -------------------------------------------------------------------- */
1448 : /* Column definitions */
1449 : /* -------------------------------------------------------------------- */
1450 :
1451 1994 : for (CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
1452 1958 : psChild = psChild->psNext)
1453 : {
1454 1958 : if (psChild->eType == CXT_Element &&
1455 1910 : EQUAL(psChild->pszValue, "FieldDefn"))
1456 : {
1457 88 : int nType = atoi(CPLGetXMLValue(psChild, "Type", "1"));
1458 88 : if (nType < 0 || nType >= GFT_MaxCount)
1459 : {
1460 0 : CPLError(CE_Warning, CPLE_AppDefined,
1461 : "Invalid RAT field type: %d(%s). Dealing as if it was "
1462 : "String",
1463 : nType,
1464 : CPLGetXMLValue(psChild, "typeAsString", "(unknown)"));
1465 0 : nType = GFT_String;
1466 : }
1467 88 : int nUsage = atoi(CPLGetXMLValue(psChild, "Usage", "0"));
1468 88 : if (nUsage < 0 || nUsage >= GFU_MaxCount)
1469 : {
1470 0 : CPLError(CE_Warning, CPLE_AppDefined,
1471 : "Invalid RAT field usage: %d(%s). Dealing as if it "
1472 : "was Generic",
1473 : nUsage,
1474 : CPLGetXMLValue(psChild, "usageAsString", "(unknown)"));
1475 0 : nUsage = GFU_Generic;
1476 : }
1477 88 : CreateColumn(CPLGetXMLValue(psChild, "Name", ""),
1478 : static_cast<GDALRATFieldType>(nType),
1479 88 : static_cast<GDALRATFieldUsage>(nUsage));
1480 : }
1481 : }
1482 :
1483 : /* -------------------------------------------------------------------- */
1484 : /* Row data. */
1485 : /* -------------------------------------------------------------------- */
1486 1994 : for (const CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
1487 1958 : psChild = psChild->psNext)
1488 : {
1489 1958 : if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue, "Row"))
1490 : {
1491 1822 : const int iRow = atoi(CPLGetXMLValue(psChild, "index", "0"));
1492 1822 : int iField = 0;
1493 :
1494 5533 : for (CPLXMLNode *psF = psChild->psChild; psF != nullptr;
1495 3711 : psF = psF->psNext)
1496 : {
1497 3711 : if (psF->eType != CXT_Element || !EQUAL(psF->pszValue, "F"))
1498 1822 : continue;
1499 :
1500 1889 : if (psF->psChild != nullptr && psF->psChild->eType == CXT_Text)
1501 1885 : SetValue(iRow, iField++, psF->psChild->pszValue);
1502 : else
1503 4 : SetValue(iRow, iField++, "");
1504 : }
1505 : }
1506 : }
1507 :
1508 36 : return CE_None;
1509 : }
1510 :
1511 : /************************************************************************/
1512 : /* InitializeFromColorTable() */
1513 : /************************************************************************/
1514 :
1515 : /**
1516 : * \brief Initialize from color table.
1517 : *
1518 : * This method will setup a whole raster attribute table based on the
1519 : * contents of the passed color table. The Value (GFU_MinMax),
1520 : * Red (GFU_Red), Green (GFU_Green), Blue (GFU_Blue), and Alpha (GFU_Alpha)
1521 : * fields are created, and a row is set for each entry in the color table.
1522 : *
1523 : * The raster attribute table must be empty before calling
1524 : * InitializeFromColorTable().
1525 : *
1526 : * The Value fields are set based on the implicit assumption with color
1527 : * tables that entry 0 applies to pixel value 0, 1 to 1, etc.
1528 : *
1529 : * This method is the same as the C function GDALRATInitializeFromColorTable().
1530 : *
1531 : * @param poTable the color table to copy from.
1532 : *
1533 : * @return CE_None on success or CE_Failure if something goes wrong.
1534 : */
1535 :
1536 0 : CPLErr GDALRasterAttributeTable::InitializeFromColorTable(
1537 : const GDALColorTable *poTable)
1538 :
1539 : {
1540 0 : if (GetRowCount() > 0 || GetColumnCount() > 0)
1541 : {
1542 0 : CPLError(CE_Failure, CPLE_AppDefined,
1543 : "Raster Attribute Table not empty in "
1544 : "InitializeFromColorTable()");
1545 0 : return CE_Failure;
1546 : }
1547 :
1548 0 : SetLinearBinning(0.0, 1.0);
1549 0 : CreateColumn("Value", GFT_Integer, GFU_MinMax);
1550 0 : CreateColumn("Red", GFT_Integer, GFU_Red);
1551 0 : CreateColumn("Green", GFT_Integer, GFU_Green);
1552 0 : CreateColumn("Blue", GFT_Integer, GFU_Blue);
1553 0 : CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
1554 :
1555 0 : SetRowCount(poTable->GetColorEntryCount());
1556 :
1557 0 : for (int iRow = 0; iRow < poTable->GetColorEntryCount(); iRow++)
1558 : {
1559 : GDALColorEntry sEntry;
1560 :
1561 0 : poTable->GetColorEntryAsRGB(iRow, &sEntry);
1562 :
1563 0 : SetValue(iRow, 0, iRow);
1564 0 : SetValue(iRow, 1, sEntry.c1);
1565 0 : SetValue(iRow, 2, sEntry.c2);
1566 0 : SetValue(iRow, 3, sEntry.c3);
1567 0 : SetValue(iRow, 4, sEntry.c4);
1568 : }
1569 :
1570 0 : return CE_None;
1571 : }
1572 :
1573 : /************************************************************************/
1574 : /* GDALRATInitializeFromColorTable() */
1575 : /************************************************************************/
1576 :
1577 : /**
1578 : * \brief Initialize from color table.
1579 : *
1580 : * This function is the same as the C++ method
1581 : * GDALRasterAttributeTable::InitializeFromColorTable()
1582 : */
1583 0 : CPLErr CPL_STDCALL GDALRATInitializeFromColorTable(
1584 : GDALRasterAttributeTableH hRAT, GDALColorTableH hCT)
1585 :
1586 : {
1587 0 : VALIDATE_POINTER1(hRAT, "GDALRATInitializeFromColorTable", CE_Failure);
1588 :
1589 0 : return GDALRasterAttributeTable::FromHandle(hRAT)->InitializeFromColorTable(
1590 0 : GDALColorTable::FromHandle(hCT));
1591 : }
1592 :
1593 : /************************************************************************/
1594 : /* TranslateToColorTable() */
1595 : /************************************************************************/
1596 :
1597 : /**
1598 : * \brief Translate to a color table.
1599 : *
1600 : * This method will attempt to create a corresponding GDALColorTable from
1601 : * this raster attribute table.
1602 : *
1603 : * This method is the same as the C function GDALRATTranslateToColorTable().
1604 : *
1605 : * @param nEntryCount The number of entries to produce (0 to nEntryCount-1),
1606 : * or -1 to auto-determine the number of entries.
1607 : *
1608 : * @return the generated color table or NULL on failure.
1609 : */
1610 :
1611 0 : GDALColorTable *GDALRasterAttributeTable::TranslateToColorTable(int nEntryCount)
1612 :
1613 : {
1614 : /* -------------------------------------------------------------------- */
1615 : /* Establish which fields are red, green, blue and alpha. */
1616 : /* -------------------------------------------------------------------- */
1617 0 : const int iRed = GetColOfUsage(GFU_Red);
1618 0 : const int iGreen = GetColOfUsage(GFU_Green);
1619 0 : const int iBlue = GetColOfUsage(GFU_Blue);
1620 :
1621 0 : if (iRed == -1 || iGreen == -1 || iBlue == -1)
1622 0 : return nullptr;
1623 :
1624 0 : const int iAlpha = GetColOfUsage(GFU_Alpha);
1625 :
1626 : /* -------------------------------------------------------------------- */
1627 : /* If we aren't given an explicit number of values to scan for, */
1628 : /* search for the maximum "max" value. */
1629 : /* -------------------------------------------------------------------- */
1630 0 : if (nEntryCount == -1)
1631 : {
1632 0 : int iMaxCol = GetColOfUsage(GFU_Max);
1633 0 : if (iMaxCol == -1)
1634 0 : iMaxCol = GetColOfUsage(GFU_MinMax);
1635 :
1636 0 : if (iMaxCol == -1 || GetRowCount() == 0)
1637 0 : return nullptr;
1638 :
1639 0 : for (int iRow = 0; iRow < GetRowCount(); iRow++)
1640 : {
1641 0 : nEntryCount = std::max(
1642 0 : nEntryCount, std::min(65535, GetValueAsInt(iRow, iMaxCol)) + 1);
1643 : }
1644 :
1645 0 : if (nEntryCount < 0)
1646 0 : return nullptr;
1647 :
1648 : // Restrict our number of entries to something vaguely sensible.
1649 0 : nEntryCount = std::min(65535, nEntryCount);
1650 : }
1651 :
1652 : /* -------------------------------------------------------------------- */
1653 : /* Assign values to color table. */
1654 : /* -------------------------------------------------------------------- */
1655 0 : GDALColorTable *poCT = new GDALColorTable();
1656 :
1657 0 : for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
1658 : {
1659 0 : GDALColorEntry sColor = {0, 0, 0, 0};
1660 0 : const int iRow = GetRowOfValue(iEntry);
1661 :
1662 0 : if (iRow != -1)
1663 : {
1664 0 : sColor.c1 = static_cast<short>(GetValueAsInt(iRow, iRed));
1665 0 : sColor.c2 = static_cast<short>(GetValueAsInt(iRow, iGreen));
1666 0 : sColor.c3 = static_cast<short>(GetValueAsInt(iRow, iBlue));
1667 0 : if (iAlpha == -1)
1668 0 : sColor.c4 = 255;
1669 : else
1670 0 : sColor.c4 = static_cast<short>(GetValueAsInt(iRow, iAlpha));
1671 : }
1672 :
1673 0 : poCT->SetColorEntry(iEntry, &sColor);
1674 : }
1675 :
1676 0 : return poCT;
1677 : }
1678 :
1679 : /************************************************************************/
1680 : /* GDALRATInitializeFromColorTable() */
1681 : /************************************************************************/
1682 :
1683 : /**
1684 : * \brief Translate to a color table.
1685 : *
1686 : * This function is the same as the C++ method
1687 : * GDALRasterAttributeTable::TranslateToColorTable()
1688 : */
1689 : GDALColorTableH CPL_STDCALL
1690 0 : GDALRATTranslateToColorTable(GDALRasterAttributeTableH hRAT, int nEntryCount)
1691 :
1692 : {
1693 0 : VALIDATE_POINTER1(hRAT, "GDALRATTranslateToColorTable", nullptr);
1694 :
1695 0 : return GDALRasterAttributeTable::FromHandle(hRAT)->TranslateToColorTable(
1696 0 : nEntryCount);
1697 : }
1698 :
1699 : /************************************************************************/
1700 : /* DumpReadable() */
1701 : /************************************************************************/
1702 :
1703 : /**
1704 : * \brief Dump RAT in readable form.
1705 : *
1706 : * Currently the readable form is the XML encoding ... only barely
1707 : * readable.
1708 : *
1709 : * This method is the same as the C function GDALRATDumpReadable().
1710 : *
1711 : * @param fp file to dump to or NULL for stdout.
1712 : */
1713 :
1714 0 : void GDALRasterAttributeTable::DumpReadable(FILE *fp)
1715 :
1716 : {
1717 0 : CPLXMLNode *psTree = Serialize();
1718 0 : char *const pszXMLText = CPLSerializeXMLTree(psTree);
1719 :
1720 0 : CPLDestroyXMLNode(psTree);
1721 :
1722 0 : if (fp == nullptr)
1723 0 : fp = stdout;
1724 :
1725 0 : fprintf(fp, "%s\n", pszXMLText);
1726 :
1727 0 : CPLFree(pszXMLText);
1728 0 : }
1729 :
1730 : /************************************************************************/
1731 : /* GDALRATDumpReadable() */
1732 : /************************************************************************/
1733 :
1734 : /**
1735 : * \brief Dump RAT in readable form.
1736 : *
1737 : * This function is the same as the C++ method
1738 : * GDALRasterAttributeTable::DumpReadable()
1739 : */
1740 0 : void CPL_STDCALL GDALRATDumpReadable(GDALRasterAttributeTableH hRAT, FILE *fp)
1741 :
1742 : {
1743 0 : VALIDATE_POINTER0(hRAT, "GDALRATDumpReadable");
1744 :
1745 0 : GDALRasterAttributeTable::FromHandle(hRAT)->DumpReadable(fp);
1746 : }
1747 :
1748 : /* \class GDALDefaultRasterAttributeTable
1749 : *
1750 : * An implementation of GDALRasterAttributeTable that keeps
1751 : * all data in memory. This is the same as the implementation
1752 : * of GDALRasterAttributeTable in GDAL <= 1.10.
1753 : */
1754 :
1755 : /************************************************************************/
1756 : /* GDALDefaultRasterAttributeTable() */
1757 : /* */
1758 : /* Simple initialization constructor. */
1759 : /************************************************************************/
1760 :
1761 : //! Construct empty table.
1762 :
1763 : GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable() = default;
1764 :
1765 : /************************************************************************/
1766 : /* GDALCreateRasterAttributeTable() */
1767 : /************************************************************************/
1768 :
1769 : /**
1770 : * \brief Construct empty table.
1771 : *
1772 : * This function is the same as the C++ method
1773 : * GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable()
1774 : */
1775 65 : GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
1776 :
1777 : {
1778 65 : return new GDALDefaultRasterAttributeTable();
1779 : }
1780 :
1781 : /************************************************************************/
1782 : /* ~GDALDefaultRasterAttributeTable() */
1783 : /* */
1784 : /* All magic done by magic by the container destructors. */
1785 : /************************************************************************/
1786 :
1787 : GDALDefaultRasterAttributeTable::~GDALDefaultRasterAttributeTable() = default;
1788 :
1789 : /************************************************************************/
1790 : /* GDALDestroyRasterAttributeTable() */
1791 : /************************************************************************/
1792 :
1793 : /**
1794 : * \brief Destroys a RAT.
1795 : *
1796 : * This function is the same as the C++ method
1797 : * GDALRasterAttributeTable::~GDALRasterAttributeTable()
1798 : */
1799 73 : void CPL_STDCALL GDALDestroyRasterAttributeTable(GDALRasterAttributeTableH hRAT)
1800 :
1801 : {
1802 73 : if (hRAT != nullptr)
1803 73 : delete GDALRasterAttributeTable::FromHandle(hRAT);
1804 73 : }
1805 :
1806 : /************************************************************************/
1807 : /* AnalyseColumns() */
1808 : /* */
1809 : /* Internal method to work out which column to use for various */
1810 : /* tasks. */
1811 : /************************************************************************/
1812 :
1813 2 : void GDALDefaultRasterAttributeTable::AnalyseColumns()
1814 :
1815 : {
1816 2 : bColumnsAnalysed = true;
1817 :
1818 2 : nMinCol = GetColOfUsage(GFU_Min);
1819 2 : if (nMinCol == -1)
1820 2 : nMinCol = GetColOfUsage(GFU_MinMax);
1821 :
1822 2 : nMaxCol = GetColOfUsage(GFU_Max);
1823 2 : if (nMaxCol == -1)
1824 2 : nMaxCol = GetColOfUsage(GFU_MinMax);
1825 2 : }
1826 :
1827 : /************************************************************************/
1828 : /* GetColumnCount() */
1829 : /************************************************************************/
1830 :
1831 388 : int GDALDefaultRasterAttributeTable::GetColumnCount() const
1832 :
1833 : {
1834 388 : return static_cast<int>(aoFields.size());
1835 : }
1836 :
1837 : /************************************************************************/
1838 : /* GDALRATGetColumnCount() */
1839 : /************************************************************************/
1840 :
1841 : /**
1842 : * \brief Fetch table column count.
1843 : *
1844 : * This function is the same as the C++ method
1845 : * GDALRasterAttributeTable::GetColumnCount()
1846 : */
1847 59 : int CPL_STDCALL GDALRATGetColumnCount(GDALRasterAttributeTableH hRAT)
1848 :
1849 : {
1850 59 : VALIDATE_POINTER1(hRAT, "GDALRATGetColumnCount", 0);
1851 :
1852 59 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetColumnCount();
1853 : }
1854 :
1855 : /************************************************************************/
1856 : /* GetNameOfCol() */
1857 : /************************************************************************/
1858 :
1859 : /** \brief Fetch name of indicated column.
1860 : * @param iCol column index.
1861 : * @return name.
1862 : */
1863 462 : const char *GDALDefaultRasterAttributeTable::GetNameOfCol(int iCol) const
1864 :
1865 : {
1866 462 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1867 0 : return "";
1868 :
1869 462 : return aoFields[iCol].sName;
1870 : }
1871 :
1872 : /************************************************************************/
1873 : /* GDALRATGetNameOfCol() */
1874 : /************************************************************************/
1875 :
1876 : /**
1877 : * \brief Fetch name of indicated column.
1878 : *
1879 : * This function is the same as the C++ method
1880 : * GDALRasterAttributeTable::GetNameOfCol()
1881 : * @param hRAT RAT handle.
1882 : * @param iCol column index.
1883 : * @return name.
1884 : */
1885 192 : const char *CPL_STDCALL GDALRATGetNameOfCol(GDALRasterAttributeTableH hRAT,
1886 : int iCol)
1887 :
1888 : {
1889 192 : VALIDATE_POINTER1(hRAT, "GDALRATGetNameOfCol", nullptr);
1890 :
1891 192 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetNameOfCol(iCol);
1892 : }
1893 :
1894 : /************************************************************************/
1895 : /* GetUsageOfCol() */
1896 : /************************************************************************/
1897 :
1898 : /**
1899 : * \brief Fetch column usage value.
1900 : *
1901 : * @param iCol column index.
1902 : * @return usage.
1903 : */
1904 231 : GDALRATFieldUsage GDALDefaultRasterAttributeTable::GetUsageOfCol(int iCol) const
1905 :
1906 : {
1907 231 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1908 0 : return GFU_Generic;
1909 :
1910 231 : return aoFields[iCol].eUsage;
1911 : }
1912 :
1913 : /************************************************************************/
1914 : /* GDALRATGetUsageOfCol() */
1915 : /************************************************************************/
1916 :
1917 : /**
1918 : * \brief Fetch column usage value.
1919 : *
1920 : * This function is the same as the C++ method
1921 : * GDALRasterAttributeTable::GetUsageOfCol()
1922 : * @param hRAT RAT handle.
1923 : * @param iCol column index.
1924 : * @return usage.
1925 : */
1926 : GDALRATFieldUsage CPL_STDCALL
1927 67 : GDALRATGetUsageOfCol(GDALRasterAttributeTableH hRAT, int iCol)
1928 :
1929 : {
1930 67 : VALIDATE_POINTER1(hRAT, "GDALRATGetUsageOfCol", GFU_Generic);
1931 :
1932 67 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetUsageOfCol(iCol);
1933 : }
1934 :
1935 : /************************************************************************/
1936 : /* GetTypeOfCol() */
1937 : /************************************************************************/
1938 :
1939 : /**
1940 : * \brief Fetch column type.
1941 : *
1942 : * @param iCol column index.
1943 : * @return type.
1944 : */
1945 4893 : GDALRATFieldType GDALDefaultRasterAttributeTable::GetTypeOfCol(int iCol) const
1946 :
1947 : {
1948 4893 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1949 665 : return GFT_Integer;
1950 :
1951 4228 : return aoFields[iCol].eType;
1952 : }
1953 :
1954 : /************************************************************************/
1955 : /* GDALRATGetTypeOfCol() */
1956 : /************************************************************************/
1957 :
1958 : /**
1959 : * \brief Fetch column type.
1960 : *
1961 : * This function is the same as the C++ method
1962 : * GDALRasterAttributeTable::GetTypeOfCol()
1963 : * @param hRAT RAT handle.
1964 : * @param iCol column index.
1965 : * @return type.
1966 : */
1967 325 : GDALRATFieldType CPL_STDCALL GDALRATGetTypeOfCol(GDALRasterAttributeTableH hRAT,
1968 : int iCol)
1969 :
1970 : {
1971 325 : VALIDATE_POINTER1(hRAT, "GDALRATGetTypeOfCol", GFT_Integer);
1972 :
1973 325 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetTypeOfCol(iCol);
1974 : }
1975 :
1976 : /************************************************************************/
1977 : /* GetColOfUsage() */
1978 : /************************************************************************/
1979 :
1980 : /** Return the index of the column that corresponds to the passed usage.
1981 : * @param eUsage usage.
1982 : * @return column index, or -1 in case of error.
1983 : */
1984 65 : int GDALDefaultRasterAttributeTable::GetColOfUsage(
1985 : GDALRATFieldUsage eUsage) const
1986 :
1987 : {
1988 192 : for (unsigned int i = 0; i < aoFields.size(); i++)
1989 : {
1990 160 : if (aoFields[i].eUsage == eUsage)
1991 33 : return i;
1992 : }
1993 :
1994 32 : return -1;
1995 : }
1996 :
1997 : /************************************************************************/
1998 : /* GDALRATGetColOfUsage() */
1999 : /************************************************************************/
2000 :
2001 : /**
2002 : * \brief Fetch column index for given usage.
2003 : *
2004 : * This function is the same as the C++ method
2005 : * GDALRasterAttributeTable::GetColOfUsage()
2006 : */
2007 13 : int CPL_STDCALL GDALRATGetColOfUsage(GDALRasterAttributeTableH hRAT,
2008 : GDALRATFieldUsage eUsage)
2009 :
2010 : {
2011 13 : VALIDATE_POINTER1(hRAT, "GDALRATGetColOfUsage", 0);
2012 :
2013 13 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetColOfUsage(eUsage);
2014 : }
2015 :
2016 : /************************************************************************/
2017 : /* GetRowCount() */
2018 : /************************************************************************/
2019 :
2020 1071 : int GDALDefaultRasterAttributeTable::GetRowCount() const
2021 :
2022 : {
2023 1071 : return static_cast<int>(nRowCount);
2024 : }
2025 :
2026 : /************************************************************************/
2027 : /* GDALRATGetUsageOfCol() */
2028 : /************************************************************************/
2029 : /**
2030 : * \brief Fetch row count.
2031 : *
2032 : * This function is the same as the C++ method
2033 : * GDALRasterAttributeTable::GetRowCount()
2034 : */
2035 270 : int CPL_STDCALL GDALRATGetRowCount(GDALRasterAttributeTableH hRAT)
2036 :
2037 : {
2038 270 : VALIDATE_POINTER1(hRAT, "GDALRATGetRowCount", 0);
2039 :
2040 270 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowCount();
2041 : }
2042 :
2043 : /************************************************************************/
2044 : /* GetValueAsString() */
2045 : /************************************************************************/
2046 :
2047 1304 : const char *GDALDefaultRasterAttributeTable::GetValueAsString(int iRow,
2048 : int iField) const
2049 :
2050 : {
2051 1304 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2052 : {
2053 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2054 : iField);
2055 :
2056 1 : return "";
2057 : }
2058 :
2059 1303 : if (iRow < 0 || iRow >= nRowCount)
2060 : {
2061 3 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2062 :
2063 3 : return "";
2064 : }
2065 :
2066 1300 : switch (aoFields[iField].eType)
2067 : {
2068 421 : case GFT_Integer:
2069 : {
2070 : const_cast<GDALDefaultRasterAttributeTable *>(this)
2071 421 : ->osWorkingResult.Printf("%d", aoFields[iField].anValues[iRow]);
2072 421 : return osWorkingResult;
2073 : }
2074 :
2075 289 : case GFT_Real:
2076 : {
2077 : const_cast<GDALDefaultRasterAttributeTable *>(this)
2078 : ->osWorkingResult.Printf("%.16g",
2079 289 : aoFields[iField].adfValues[iRow]);
2080 289 : return osWorkingResult;
2081 : }
2082 :
2083 567 : case GFT_String:
2084 : {
2085 567 : return aoFields[iField].aosValues[iRow];
2086 : }
2087 :
2088 2 : case GFT_Boolean:
2089 : {
2090 2 : return aoFields[iField].abValues[iRow] ? "true" : "false";
2091 : }
2092 :
2093 11 : case GFT_DateTime:
2094 : {
2095 11 : const auto &sDateTime = aoFields[iField].asDateTimeValues[iRow];
2096 : const_cast<GDALDefaultRasterAttributeTable *>(this)
2097 11 : ->osWorkingResult = DateTimeToString(sDateTime);
2098 11 : return osWorkingResult;
2099 : }
2100 :
2101 10 : case GFT_WKBGeometry:
2102 : {
2103 10 : OGRGeometry *poGeom = nullptr;
2104 18 : if (!aoFields[iField].aabyWKBGeometryValues[iRow].empty() &&
2105 16 : OGRGeometryFactory::createFromWkb(
2106 8 : aoFields[iField].aabyWKBGeometryValues[iRow].data(),
2107 : nullptr, &poGeom,
2108 8 : aoFields[iField].aabyWKBGeometryValues[iRow].size(),
2109 : wkbVariantIso) == OGRERR_NONE)
2110 : {
2111 : const_cast<GDALDefaultRasterAttributeTable *>(this)
2112 8 : ->osWorkingResult = poGeom->exportToWkt();
2113 : }
2114 : else
2115 : {
2116 : const_cast<GDALDefaultRasterAttributeTable *>(this)
2117 2 : ->osWorkingResult.clear();
2118 : }
2119 10 : delete poGeom;
2120 10 : return osWorkingResult;
2121 : }
2122 : }
2123 :
2124 0 : return "";
2125 : }
2126 :
2127 : /************************************************************************/
2128 : /* GDALRATGetValueAsString() */
2129 : /************************************************************************/
2130 : /**
2131 : * \brief Fetch field value as a string.
2132 : *
2133 : * This function is the same as the C++ method
2134 : * GDALRasterAttributeTable::GetValueAsString()
2135 : */
2136 259 : const char *CPL_STDCALL GDALRATGetValueAsString(GDALRasterAttributeTableH hRAT,
2137 : int iRow, int iField)
2138 :
2139 : {
2140 259 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsString", nullptr);
2141 :
2142 518 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsString(iRow,
2143 259 : iField);
2144 : }
2145 :
2146 : /************************************************************************/
2147 : /* GetValueAsInt() */
2148 : /************************************************************************/
2149 :
2150 642 : int GDALDefaultRasterAttributeTable::GetValueAsInt(int iRow, int iField) const
2151 :
2152 : {
2153 642 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2154 : {
2155 21 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2156 : iField);
2157 :
2158 21 : return 0;
2159 : }
2160 :
2161 621 : if (iRow < 0 || iRow >= nRowCount)
2162 : {
2163 3 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2164 :
2165 3 : return 0;
2166 : }
2167 :
2168 618 : switch (aoFields[iField].eType)
2169 : {
2170 609 : case GFT_Integer:
2171 609 : return aoFields[iField].anValues[iRow];
2172 :
2173 1 : case GFT_Real:
2174 1 : return static_cast<int>(aoFields[iField].adfValues[iRow]);
2175 :
2176 1 : case GFT_String:
2177 1 : return atoi(aoFields[iField].aosValues[iRow].c_str());
2178 :
2179 5 : case GFT_Boolean:
2180 5 : return aoFields[iField].abValues[iRow];
2181 :
2182 2 : case GFT_DateTime:
2183 : case GFT_WKBGeometry:
2184 2 : CPLError(CE_Failure, CPLE_AppDefined,
2185 : "Incompatible RAT field type");
2186 2 : break;
2187 : }
2188 :
2189 2 : return 0;
2190 : }
2191 :
2192 : /************************************************************************/
2193 : /* GDALRATGetValueAsInt() */
2194 : /************************************************************************/
2195 :
2196 : /**
2197 : * \brief Fetch field value as a integer.
2198 : *
2199 : * This function is the same as the C++ method
2200 : * GDALRasterAttributeTable::GetValueAsInt()
2201 : */
2202 305 : int CPL_STDCALL GDALRATGetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
2203 : int iField)
2204 :
2205 : {
2206 305 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsInt", 0);
2207 :
2208 610 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsInt(iRow,
2209 305 : iField);
2210 : }
2211 :
2212 : /************************************************************************/
2213 : /* GetValueAsDouble() */
2214 : /************************************************************************/
2215 :
2216 775 : double GDALDefaultRasterAttributeTable::GetValueAsDouble(int iRow,
2217 : int iField) const
2218 :
2219 : {
2220 775 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2221 : {
2222 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2223 : iField);
2224 :
2225 1 : return 0;
2226 : }
2227 :
2228 774 : if (iRow < 0 || iRow >= nRowCount)
2229 : {
2230 3 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2231 :
2232 3 : return 0;
2233 : }
2234 :
2235 771 : switch (aoFields[iField].eType)
2236 : {
2237 1 : case GFT_Integer:
2238 1 : return aoFields[iField].anValues[iRow];
2239 :
2240 766 : case GFT_Real:
2241 766 : return aoFields[iField].adfValues[iRow];
2242 :
2243 1 : case GFT_String:
2244 1 : return CPLAtof(aoFields[iField].aosValues[iRow].c_str());
2245 :
2246 1 : case GFT_Boolean:
2247 1 : return aoFields[iField].abValues[iRow];
2248 :
2249 2 : case GFT_DateTime:
2250 : case GFT_WKBGeometry:
2251 2 : CPLError(CE_Failure, CPLE_AppDefined,
2252 : "Incompatible RAT field type");
2253 2 : break;
2254 : }
2255 :
2256 2 : return 0;
2257 : }
2258 :
2259 : /************************************************************************/
2260 : /* GDALRATGetValueAsDouble() */
2261 : /************************************************************************/
2262 :
2263 : /**
2264 : * \brief Fetch field value as a double.
2265 : *
2266 : * This function is the same as the C++ method
2267 : * GDALRasterAttributeTable::GetValueAsDouble()
2268 : */
2269 243 : double CPL_STDCALL GDALRATGetValueAsDouble(GDALRasterAttributeTableH hRAT,
2270 : int iRow, int iField)
2271 :
2272 : {
2273 243 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsDouble", 0);
2274 :
2275 486 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDouble(iRow,
2276 243 : iField);
2277 : }
2278 :
2279 : /************************************************************************/
2280 : /* GetValueAsBoolean() */
2281 : /************************************************************************/
2282 :
2283 51 : bool GDALDefaultRasterAttributeTable::GetValueAsBoolean(int iRow,
2284 : int iField) const
2285 :
2286 : {
2287 51 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2288 : {
2289 6 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2290 : iField);
2291 :
2292 6 : return false;
2293 : }
2294 :
2295 45 : if (iRow < 0 || iRow >= nRowCount)
2296 : {
2297 2 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2298 :
2299 2 : return false;
2300 : }
2301 :
2302 43 : switch (aoFields[iField].eType)
2303 : {
2304 5 : case GFT_Integer:
2305 5 : return aoFields[iField].anValues[iRow] != 0;
2306 :
2307 1 : case GFT_Real:
2308 1 : return aoFields[iField].adfValues[iRow] != 0;
2309 :
2310 1 : case GFT_String:
2311 1 : return CPLTestBool(aoFields[iField].aosValues[iRow].c_str());
2312 :
2313 34 : case GFT_Boolean:
2314 34 : return aoFields[iField].abValues[iRow];
2315 :
2316 2 : case GFT_DateTime:
2317 : case GFT_WKBGeometry:
2318 2 : CPLError(CE_Failure, CPLE_AppDefined,
2319 : "Incompatible RAT field type");
2320 2 : break;
2321 : }
2322 :
2323 2 : return false;
2324 : }
2325 :
2326 : /************************************************************************/
2327 : /* GDALRATGetValueAsBoolean() */
2328 : /************************************************************************/
2329 :
2330 : /**
2331 : * \brief Fetch field value as a boolean.
2332 : *
2333 : * This function is the same as the C++ method
2334 : * GDALRasterAttributeTable::GetValueAsBoolean()
2335 : *
2336 : * \since 3.12
2337 : */
2338 22 : bool GDALRATGetValueAsBoolean(GDALRasterAttributeTableH hRAT, int iRow,
2339 : int iField)
2340 :
2341 : {
2342 22 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsBoolean", false);
2343 :
2344 44 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsBoolean(
2345 22 : iRow, iField);
2346 : }
2347 :
2348 : /************************************************************************/
2349 : /* GetValueAsDateTime() */
2350 : /************************************************************************/
2351 :
2352 : GDALRATDateTime
2353 18 : GDALDefaultRasterAttributeTable::GetValueAsDateTime(int iRow, int iField) const
2354 :
2355 : {
2356 18 : GDALRATDateTime dt;
2357 :
2358 18 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2359 : {
2360 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2361 : iField);
2362 :
2363 1 : return dt;
2364 : }
2365 :
2366 17 : if (iRow < 0 || iRow >= nRowCount)
2367 : {
2368 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2369 :
2370 1 : return dt;
2371 : }
2372 :
2373 16 : switch (aoFields[iField].eType)
2374 : {
2375 0 : case GFT_String:
2376 0 : StringToDateTime(aoFields[iField].aosValues[iRow].c_str(), dt);
2377 0 : break;
2378 :
2379 12 : case GFT_DateTime:
2380 12 : dt = aoFields[iField].asDateTimeValues[iRow];
2381 12 : break;
2382 :
2383 4 : case GFT_Integer:
2384 : case GFT_Real:
2385 : case GFT_Boolean:
2386 : case GFT_WKBGeometry:
2387 4 : CPLError(CE_Failure, CPLE_AppDefined,
2388 : "Incompatible RAT field type");
2389 4 : break;
2390 : }
2391 :
2392 16 : return dt;
2393 : }
2394 :
2395 : /************************************************************************/
2396 : /* GDALRATGetValueAsDateTime() */
2397 : /************************************************************************/
2398 :
2399 : /**
2400 : * \brief Fetch field value as a datetime.
2401 : *
2402 : * The value of the requested column in the requested row is returned
2403 : * as a datetime. Besides being called on a GFT_DateTime field, it
2404 : * is also possible to call this method on a string field that contains a
2405 : * ISO-8601 encoded datetime.
2406 : *
2407 : * This function is the same as the C++ method
2408 : * GDALRasterAttributeTable::GetValueAsDateTime()
2409 : *
2410 : * @param hRAT Raster attribute table handle. Must NOT be null.
2411 : * @param iRow Row index (0-based indexing)
2412 : * @param iField Field index (0-based indexing)
2413 : * @param[out] psDateTime Output date time struct. Must NOT be null.
2414 : * @return error code.
2415 : *
2416 : * \since 3.12
2417 : */
2418 16 : CPLErr GDALRATGetValueAsDateTime(GDALRasterAttributeTableH hRAT, int iRow,
2419 : int iField, GDALRATDateTime *psDateTime)
2420 :
2421 : {
2422 16 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsBoolean", CE_Failure);
2423 16 : VALIDATE_POINTER1(psDateTime, "GDALRATGetValueAsBoolean", CE_Failure);
2424 :
2425 16 : const auto nErrorCounter = CPLGetErrorCounter();
2426 16 : *psDateTime =
2427 16 : GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDateTime(iRow,
2428 16 : iField);
2429 16 : return nErrorCounter == CPLGetErrorCounter() ? CE_None : CE_Failure;
2430 : }
2431 :
2432 : /************************************************************************/
2433 : /* GetValueAsWKBGeometry() */
2434 : /************************************************************************/
2435 :
2436 : const GByte *
2437 15 : GDALDefaultRasterAttributeTable::GetValueAsWKBGeometry(int iRow, int iField,
2438 : size_t &nWKBSize) const
2439 :
2440 : {
2441 15 : nWKBSize = 0;
2442 :
2443 15 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2444 : {
2445 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2446 : iField);
2447 :
2448 1 : return nullptr;
2449 : }
2450 :
2451 14 : if (iRow < 0 || iRow >= nRowCount)
2452 : {
2453 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2454 :
2455 1 : return nullptr;
2456 : }
2457 :
2458 13 : switch (aoFields[iField].eType)
2459 : {
2460 0 : case GFT_String:
2461 : {
2462 : auto abyWKB =
2463 0 : WKTGeometryToWKB(aoFields[iField].aosValues[iRow].c_str());
2464 0 : if (!abyWKB.empty())
2465 : {
2466 0 : nWKBSize = abyWKB.size();
2467 0 : m_abyWKB = std::move(abyWKB);
2468 0 : return m_abyWKB.data();
2469 : }
2470 0 : return nullptr;
2471 : }
2472 :
2473 9 : case GFT_WKBGeometry:
2474 : {
2475 9 : nWKBSize = aoFields[iField].aabyWKBGeometryValues[iRow].size();
2476 9 : return nWKBSize
2477 9 : ? aoFields[iField].aabyWKBGeometryValues[iRow].data()
2478 9 : : nullptr;
2479 : }
2480 :
2481 4 : case GFT_Integer:
2482 : case GFT_Real:
2483 : case GFT_Boolean:
2484 : case GFT_DateTime:
2485 4 : CPLError(CE_Failure, CPLE_AppDefined,
2486 : "Incompatible RAT field type");
2487 4 : break;
2488 : }
2489 :
2490 4 : return nullptr;
2491 : }
2492 :
2493 : /************************************************************************/
2494 : /* GDALRATGetValueAsWKBGeometry() */
2495 : /************************************************************************/
2496 :
2497 : /**
2498 : * \brief Fetch field value as a WKB-encoded geometry.
2499 : *
2500 : * The value of the requested column in the requested row is returned
2501 : * as a WKB geometry. Besides being called on a GFT_WKBGeometry field, it
2502 : * is also possible to call this method on a string field that contains a WKT
2503 : * encoded geometry.
2504 : *
2505 : * The returned pointer may be invalidated by a following call call to a method
2506 : * of this GDALRasterAttributeTable instance.
2507 : *
2508 : * This function is the same as the C++ method
2509 : * GDALRasterAttributeTable::GetValueAsWKBGeometry()
2510 : *
2511 : * \since 3.12
2512 : */
2513 14 : const GByte *GDALRATGetValueAsWKBGeometry(GDALRasterAttributeTableH hRAT,
2514 : int iRow, int iField,
2515 : size_t *pnWKBSize)
2516 :
2517 : {
2518 14 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsWKBGeometry", nullptr);
2519 14 : VALIDATE_POINTER1(pnWKBSize, "GDALRATGetValueAsWKBGeometry", nullptr);
2520 :
2521 28 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsWKBGeometry(
2522 14 : iRow, iField, *pnWKBSize);
2523 : }
2524 :
2525 : /************************************************************************/
2526 : /* SetRowCount() */
2527 : /************************************************************************/
2528 :
2529 : /** Set row count.
2530 : * @param nNewCount new count.
2531 : */
2532 4770 : void GDALDefaultRasterAttributeTable::SetRowCount(int nNewCount)
2533 :
2534 : {
2535 4770 : if (nNewCount == nRowCount)
2536 1823 : return;
2537 :
2538 9845 : for (auto &oField : aoFields)
2539 : {
2540 6898 : switch (oField.eType)
2541 : {
2542 2564 : case GFT_Integer:
2543 2564 : oField.anValues.resize(nNewCount);
2544 2564 : break;
2545 :
2546 2806 : case GFT_Real:
2547 2806 : oField.adfValues.resize(nNewCount);
2548 2806 : break;
2549 :
2550 1480 : case GFT_String:
2551 1480 : oField.aosValues.resize(nNewCount);
2552 1480 : break;
2553 :
2554 20 : case GFT_Boolean:
2555 20 : oField.abValues.resize(nNewCount);
2556 20 : break;
2557 :
2558 15 : case GFT_DateTime:
2559 15 : oField.asDateTimeValues.resize(nNewCount);
2560 15 : break;
2561 :
2562 13 : case GFT_WKBGeometry:
2563 13 : oField.aabyWKBGeometryValues.resize(nNewCount);
2564 13 : break;
2565 : }
2566 : }
2567 :
2568 2947 : nRowCount = nNewCount;
2569 : }
2570 :
2571 : /************************************************************************/
2572 : /* SetValue() */
2573 : /************************************************************************/
2574 :
2575 : /** Set value
2576 : * @param iRow row index.
2577 : * @param iField field index.
2578 : * @param pszValue value.
2579 : */
2580 5442 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2581 : const char *pszValue)
2582 :
2583 : {
2584 5442 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2585 : {
2586 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2587 : iField);
2588 :
2589 1 : return CE_Failure;
2590 : }
2591 :
2592 5441 : if (iRow == nRowCount)
2593 1824 : SetRowCount(nRowCount + 1);
2594 :
2595 5441 : if (iRow < 0 || iRow >= nRowCount)
2596 : {
2597 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2598 :
2599 1 : return CE_Failure;
2600 : }
2601 :
2602 5440 : switch (aoFields[iField].eType)
2603 : {
2604 315 : case GFT_Integer:
2605 315 : aoFields[iField].anValues[iRow] = atoi(pszValue);
2606 315 : break;
2607 :
2608 2333 : case GFT_Real:
2609 2333 : aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
2610 2333 : break;
2611 :
2612 2748 : case GFT_String:
2613 2748 : aoFields[iField].aosValues[iRow] = pszValue;
2614 2748 : break;
2615 :
2616 14 : case GFT_Boolean:
2617 14 : aoFields[iField].abValues[iRow] = CPLTestBool(pszValue);
2618 14 : break;
2619 :
2620 15 : case GFT_DateTime:
2621 : {
2622 15 : GDALRATDateTime sDateTime;
2623 15 : StringToDateTime(pszValue, sDateTime);
2624 15 : aoFields[iField].asDateTimeValues[iRow] = std::move(sDateTime);
2625 15 : break;
2626 : }
2627 :
2628 15 : case GFT_WKBGeometry:
2629 : {
2630 30 : auto abyWKB = WKTGeometryToWKB(pszValue);
2631 15 : aoFields[iField].aabyWKBGeometryValues[iRow] = std::move(abyWKB);
2632 15 : break;
2633 : }
2634 : }
2635 :
2636 5440 : return CE_None;
2637 : }
2638 :
2639 : /************************************************************************/
2640 : /* GDALRATSetValueAsString() */
2641 : /************************************************************************/
2642 :
2643 : /**
2644 : * \brief Set field value from string.
2645 : *
2646 : * This function is the same as the C++ method
2647 : * GDALRasterAttributeTable::SetValue()
2648 : * @param hRAT RAT handle.
2649 : * @param iRow row index.
2650 : * @param iField field index.
2651 : * @param pszValue value.
2652 : */
2653 214 : void CPL_STDCALL GDALRATSetValueAsString(GDALRasterAttributeTableH hRAT,
2654 : int iRow, int iField,
2655 : const char *pszValue)
2656 :
2657 : {
2658 214 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsString");
2659 :
2660 214 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
2661 214 : pszValue);
2662 : }
2663 :
2664 : /************************************************************************/
2665 : /* SetValue() */
2666 : /************************************************************************/
2667 :
2668 2897 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2669 : int nValue)
2670 :
2671 : {
2672 2897 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2673 : {
2674 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2675 : iField);
2676 :
2677 1 : return CE_Failure;
2678 : }
2679 :
2680 2896 : if (iRow == nRowCount)
2681 792 : SetRowCount(nRowCount + 1);
2682 :
2683 2896 : if (iRow < 0 || iRow >= nRowCount)
2684 : {
2685 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2686 :
2687 1 : return CE_Failure;
2688 : }
2689 :
2690 2895 : switch (aoFields[iField].eType)
2691 : {
2692 2882 : case GFT_Integer:
2693 2882 : aoFields[iField].anValues[iRow] = nValue;
2694 2882 : break;
2695 :
2696 7 : case GFT_Real:
2697 7 : aoFields[iField].adfValues[iRow] = nValue;
2698 7 : break;
2699 :
2700 1 : case GFT_String:
2701 : {
2702 : char szValue[100];
2703 :
2704 1 : snprintf(szValue, sizeof(szValue), "%d", nValue);
2705 1 : aoFields[iField].aosValues[iRow] = szValue;
2706 1 : break;
2707 : }
2708 :
2709 3 : case GFT_Boolean:
2710 3 : aoFields[iField].abValues[iRow] = nValue != 0;
2711 3 : break;
2712 :
2713 2 : case GFT_DateTime:
2714 : case GFT_WKBGeometry:
2715 2 : CPLError(CE_Failure, CPLE_AppDefined,
2716 : "Incompatible RAT field type");
2717 2 : return CE_Failure;
2718 : }
2719 :
2720 2893 : return CE_None;
2721 : }
2722 :
2723 : /************************************************************************/
2724 : /* GDALRATSetValueAsInt() */
2725 : /************************************************************************/
2726 :
2727 : /**
2728 : * \brief Set field value from integer.
2729 : *
2730 : * This function is the same as the C++ method
2731 : * GDALRasterAttributeTable::SetValue()
2732 : */
2733 295 : void CPL_STDCALL GDALRATSetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
2734 : int iField, int nValue)
2735 :
2736 : {
2737 295 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsInt");
2738 :
2739 295 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, nValue);
2740 : }
2741 :
2742 : /************************************************************************/
2743 : /* SetValue() */
2744 : /************************************************************************/
2745 :
2746 6483 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2747 : double dfValue)
2748 :
2749 : {
2750 6483 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2751 : {
2752 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2753 : iField);
2754 :
2755 1 : return CE_Failure;
2756 : }
2757 :
2758 6482 : if (iRow == nRowCount)
2759 0 : SetRowCount(nRowCount + 1);
2760 :
2761 6482 : if (iRow < 0 || iRow >= nRowCount)
2762 : {
2763 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2764 :
2765 1 : return CE_Failure;
2766 : }
2767 :
2768 6481 : switch (aoFields[iField].eType)
2769 : {
2770 1591 : case GFT_Integer:
2771 1591 : aoFields[iField].anValues[iRow] = static_cast<int>(dfValue);
2772 1591 : break;
2773 :
2774 4884 : case GFT_Real:
2775 4884 : aoFields[iField].adfValues[iRow] = dfValue;
2776 4884 : break;
2777 :
2778 1 : case GFT_String:
2779 : {
2780 1 : char szValue[100] = {'\0'};
2781 :
2782 1 : CPLsnprintf(szValue, sizeof(szValue), "%.15g", dfValue);
2783 1 : aoFields[iField].aosValues[iRow] = szValue;
2784 1 : break;
2785 : }
2786 :
2787 1 : case GFT_Boolean:
2788 1 : aoFields[iField].abValues[iRow] = dfValue != 0;
2789 1 : break;
2790 :
2791 4 : case GFT_DateTime:
2792 : case GFT_WKBGeometry:
2793 4 : CPLError(CE_Failure, CPLE_AppDefined,
2794 : "Incompatible RAT field type");
2795 4 : return CE_Failure;
2796 : }
2797 :
2798 6477 : return CE_None;
2799 : }
2800 :
2801 : /************************************************************************/
2802 : /* GDALRATSetValueAsDouble() */
2803 : /************************************************************************/
2804 :
2805 : /**
2806 : * \brief Set field value from double.
2807 : *
2808 : * This function is the same as the C++ method
2809 : * GDALRasterAttributeTable::SetValue()
2810 : */
2811 196 : void CPL_STDCALL GDALRATSetValueAsDouble(GDALRasterAttributeTableH hRAT,
2812 : int iRow, int iField, double dfValue)
2813 :
2814 : {
2815 196 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsDouble");
2816 :
2817 196 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, dfValue);
2818 : }
2819 :
2820 : /************************************************************************/
2821 : /* SetValue() */
2822 : /************************************************************************/
2823 :
2824 29 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2825 : bool bValue)
2826 :
2827 : {
2828 29 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2829 : {
2830 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2831 : iField);
2832 :
2833 1 : return CE_Failure;
2834 : }
2835 :
2836 28 : if (iRow == nRowCount)
2837 1 : SetRowCount(nRowCount + 1);
2838 :
2839 28 : if (iRow < 0 || iRow >= nRowCount)
2840 : {
2841 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2842 :
2843 1 : return CE_Failure;
2844 : }
2845 :
2846 27 : switch (aoFields[iField].eType)
2847 : {
2848 1 : case GFT_Integer:
2849 : {
2850 1 : aoFields[iField].anValues[iRow] = bValue ? 1 : 0;
2851 1 : break;
2852 : }
2853 1 : case GFT_String:
2854 : {
2855 1 : aoFields[iField].aosValues[iRow] = bValue ? "true" : "false";
2856 1 : break;
2857 : }
2858 1 : case GFT_Real:
2859 : {
2860 1 : aoFields[iField].adfValues[iRow] = bValue ? 1 : 0;
2861 1 : break;
2862 : }
2863 22 : case GFT_Boolean:
2864 : {
2865 22 : aoFields[iField].abValues[iRow] = bValue;
2866 22 : break;
2867 : }
2868 2 : case GFT_DateTime:
2869 : case GFT_WKBGeometry:
2870 2 : CPLError(CE_Failure, CPLE_AppDefined,
2871 : "Incompatible RAT field type");
2872 2 : return CE_Failure;
2873 : }
2874 :
2875 25 : return CE_None;
2876 : }
2877 :
2878 : /************************************************************************/
2879 : /* GDALRATSetValueAsBoolean() */
2880 : /************************************************************************/
2881 :
2882 : /**
2883 : * \brief Set field value from a boolean value.
2884 : *
2885 : * This function is the same as the C++ method
2886 : * GDALRasterAttributeTable::SetValue()
2887 : *
2888 : * \since 3.12
2889 : */
2890 29 : CPLErr GDALRATSetValueAsBoolean(GDALRasterAttributeTableH hRAT, int iRow,
2891 : int iField, bool bValue)
2892 :
2893 : {
2894 29 : VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsBoolean", CE_Failure);
2895 :
2896 58 : return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
2897 29 : bValue);
2898 : }
2899 :
2900 : /************************************************************************/
2901 : /* SetValue() */
2902 : /************************************************************************/
2903 :
2904 : CPLErr
2905 14 : GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2906 : const GDALRATDateTime &sDateTime)
2907 :
2908 : {
2909 14 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2910 : {
2911 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2912 : iField);
2913 :
2914 1 : return CE_Failure;
2915 : }
2916 :
2917 13 : if (iRow == nRowCount)
2918 0 : SetRowCount(nRowCount + 1);
2919 :
2920 13 : if (iRow < 0 || iRow >= nRowCount)
2921 : {
2922 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2923 :
2924 1 : return CE_Failure;
2925 : }
2926 :
2927 12 : switch (aoFields[iField].eType)
2928 : {
2929 1 : case GFT_String:
2930 : {
2931 1 : aoFields[iField].aosValues[iRow] = DateTimeToString(sDateTime);
2932 1 : break;
2933 : }
2934 :
2935 7 : case GFT_DateTime:
2936 : {
2937 7 : aoFields[iField].asDateTimeValues[iRow] = sDateTime;
2938 7 : break;
2939 : }
2940 :
2941 4 : case GFT_Integer:
2942 : case GFT_Real:
2943 : case GFT_Boolean:
2944 : case GFT_WKBGeometry:
2945 4 : CPLError(CE_Failure, CPLE_AppDefined,
2946 : "Incompatible RAT field type");
2947 4 : return CE_Failure;
2948 : }
2949 :
2950 8 : return CE_None;
2951 : }
2952 :
2953 : /************************************************************************/
2954 : /* GDALRATSetValueAsDateTime() */
2955 : /************************************************************************/
2956 :
2957 : /**
2958 : * \brief Set field value from datetime.
2959 : *
2960 : * Note that the GDALRATDateTime::bIsValid field must be set to true if
2961 : * the date time is valid.
2962 : *
2963 : * This function is the same as the C++ method
2964 : * GDALRasterAttributeTable::SetValue()
2965 : *
2966 : * \since 3.12
2967 : */
2968 16 : CPLErr GDALRATSetValueAsDateTime(GDALRasterAttributeTableH hRAT, int iRow,
2969 : int iField, const GDALRATDateTime *psDateTime)
2970 :
2971 : {
2972 16 : VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsDateTime", CE_Failure);
2973 16 : VALIDATE_POINTER1(psDateTime, "GDALRATSetValueAsDateTime", CE_Failure);
2974 :
2975 32 : return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
2976 16 : *psDateTime);
2977 : }
2978 :
2979 : /************************************************************************/
2980 : /* SetValue() */
2981 : /************************************************************************/
2982 :
2983 9 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2984 : const void *pabyWKB,
2985 : size_t nWKBSize)
2986 :
2987 : {
2988 9 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2989 : {
2990 1 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2991 : iField);
2992 :
2993 1 : return CE_Failure;
2994 : }
2995 :
2996 8 : if (iRow == nRowCount)
2997 0 : SetRowCount(nRowCount + 1);
2998 :
2999 8 : if (iRow < 0 || iRow >= nRowCount)
3000 : {
3001 1 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
3002 :
3003 1 : return CE_Failure;
3004 : }
3005 :
3006 7 : switch (aoFields[iField].eType)
3007 : {
3008 1 : case GFT_String:
3009 : {
3010 1 : aoFields[iField].aosValues[iRow] =
3011 2 : WKBGeometryToWKT(pabyWKB, nWKBSize);
3012 1 : break;
3013 : }
3014 :
3015 2 : case GFT_WKBGeometry:
3016 : {
3017 2 : if (nWKBSize)
3018 2 : aoFields[iField].aabyWKBGeometryValues[iRow].assign(
3019 : static_cast<const GByte *>(pabyWKB),
3020 : static_cast<const GByte *>(pabyWKB) + nWKBSize);
3021 : else
3022 0 : aoFields[iField].aabyWKBGeometryValues[iRow].clear();
3023 2 : break;
3024 : }
3025 :
3026 4 : case GFT_Integer:
3027 : case GFT_Real:
3028 : case GFT_Boolean:
3029 : case GFT_DateTime:
3030 4 : CPLError(CE_Failure, CPLE_AppDefined,
3031 : "Incompatible RAT field type");
3032 4 : return CE_Failure;
3033 : }
3034 :
3035 3 : return CE_None;
3036 : }
3037 :
3038 : /************************************************************************/
3039 : /* GDALRATSetValueAsWKBGeometry() */
3040 : /************************************************************************/
3041 :
3042 : /**
3043 : * \brief Set field value from a WKB-encoded geometry.
3044 : *
3045 : * This function is the same as the C++ method
3046 : * GDALRasterAttributeTable::SetValue()
3047 : *
3048 : * \since 3.12
3049 : */
3050 14 : CPLErr GDALRATSetValueAsWKBGeometry(GDALRasterAttributeTableH hRAT, int iRow,
3051 : int iField, const void *pabyWKB,
3052 : size_t nWKBSize)
3053 :
3054 : {
3055 14 : VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsWKBGeometry", CE_Failure);
3056 :
3057 28 : return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(
3058 14 : iRow, iField, pabyWKB, nWKBSize);
3059 : }
3060 :
3061 : /************************************************************************/
3062 : /* ChangesAreWrittenToFile() */
3063 : /************************************************************************/
3064 :
3065 0 : int GDALDefaultRasterAttributeTable::ChangesAreWrittenToFile()
3066 : {
3067 : // GDALRasterBand.SetDefaultRAT needs to be called on instances of
3068 : // GDALDefaultRasterAttributeTable since changes are just in-memory
3069 0 : return false;
3070 : }
3071 :
3072 : /************************************************************************/
3073 : /* GDALRATChangesAreWrittenToFile() */
3074 : /************************************************************************/
3075 :
3076 : /**
3077 : * \brief Determine whether changes made to this RAT are reflected directly in
3078 : * the dataset
3079 : *
3080 : * This function is the same as the C++ method
3081 : * GDALRasterAttributeTable::ChangesAreWrittenToFile()
3082 : */
3083 2 : int CPL_STDCALL GDALRATChangesAreWrittenToFile(GDALRasterAttributeTableH hRAT)
3084 : {
3085 2 : VALIDATE_POINTER1(hRAT, "GDALRATChangesAreWrittenToFile", false);
3086 :
3087 2 : return GDALRasterAttributeTable::FromHandle(hRAT)
3088 2 : ->ChangesAreWrittenToFile();
3089 : }
3090 :
3091 : /************************************************************************/
3092 : /* GetRowOfValue() */
3093 : /************************************************************************/
3094 :
3095 2 : int GDALDefaultRasterAttributeTable::GetRowOfValue(double dfValue) const
3096 :
3097 : {
3098 : /* -------------------------------------------------------------------- */
3099 : /* Handle case of regular binning. */
3100 : /* -------------------------------------------------------------------- */
3101 2 : if (bLinearBinning)
3102 : {
3103 0 : const int iBin =
3104 0 : static_cast<int>(floor((dfValue - dfRow0Min) / dfBinSize));
3105 0 : if (iBin < 0 || iBin >= nRowCount)
3106 0 : return -1;
3107 :
3108 0 : return iBin;
3109 : }
3110 :
3111 : /* -------------------------------------------------------------------- */
3112 : /* Do we have any information? */
3113 : /* -------------------------------------------------------------------- */
3114 2 : if (!bColumnsAnalysed)
3115 2 : const_cast<GDALDefaultRasterAttributeTable *>(this)->AnalyseColumns();
3116 :
3117 2 : if (nMinCol == -1 && nMaxCol == -1)
3118 0 : return -1;
3119 :
3120 2 : const GDALRasterAttributeField *poMin = nullptr;
3121 2 : if (nMinCol != -1)
3122 2 : poMin = &(aoFields[nMinCol]);
3123 : else
3124 0 : poMin = nullptr;
3125 :
3126 2 : const GDALRasterAttributeField *poMax = nullptr;
3127 2 : if (nMaxCol != -1)
3128 2 : poMax = &(aoFields[nMaxCol]);
3129 : else
3130 0 : poMax = nullptr;
3131 :
3132 : /* -------------------------------------------------------------------- */
3133 : /* Search through rows for match. */
3134 : /* -------------------------------------------------------------------- */
3135 4 : for (int iRow = 0; iRow < nRowCount; iRow++)
3136 : {
3137 4 : if (poMin != nullptr)
3138 : {
3139 4 : if (poMin->eType == GFT_Integer)
3140 : {
3141 4 : while (iRow < nRowCount && dfValue < poMin->anValues[iRow])
3142 0 : iRow++;
3143 : }
3144 0 : else if (poMin->eType == GFT_Real)
3145 : {
3146 0 : while (iRow < nRowCount && dfValue < poMin->adfValues[iRow])
3147 0 : iRow++;
3148 : }
3149 :
3150 4 : if (iRow == nRowCount)
3151 0 : break;
3152 : }
3153 :
3154 4 : if (poMax != nullptr)
3155 : {
3156 14 : if ((poMax->eType == GFT_Integer &&
3157 6 : dfValue > poMax->anValues[iRow]) ||
3158 2 : (poMax->eType == GFT_Real && dfValue > poMax->adfValues[iRow]))
3159 2 : continue;
3160 : }
3161 :
3162 2 : return iRow;
3163 : }
3164 :
3165 0 : return -1;
3166 : }
3167 :
3168 : /************************************************************************/
3169 : /* GetRowOfValue() */
3170 : /* */
3171 : /* Int arg for now just converted to double. Perhaps we will */
3172 : /* handle this in a special way some day? */
3173 : /************************************************************************/
3174 :
3175 0 : int GDALDefaultRasterAttributeTable::GetRowOfValue(int nValue) const
3176 :
3177 : {
3178 0 : return GetRowOfValue(static_cast<double>(nValue));
3179 : }
3180 :
3181 : /************************************************************************/
3182 : /* SetLinearBinning() */
3183 : /************************************************************************/
3184 :
3185 16 : CPLErr GDALDefaultRasterAttributeTable::SetLinearBinning(double dfRow0MinIn,
3186 : double dfBinSizeIn)
3187 :
3188 : {
3189 16 : bLinearBinning = true;
3190 16 : dfRow0Min = dfRow0MinIn;
3191 16 : dfBinSize = dfBinSizeIn;
3192 :
3193 16 : return CE_None;
3194 : }
3195 :
3196 : /************************************************************************/
3197 : /* GetLinearBinning() */
3198 : /************************************************************************/
3199 :
3200 37 : int GDALDefaultRasterAttributeTable::GetLinearBinning(double *pdfRow0Min,
3201 : double *pdfBinSize) const
3202 :
3203 : {
3204 37 : if (!bLinearBinning)
3205 35 : return false;
3206 :
3207 2 : *pdfRow0Min = dfRow0Min;
3208 2 : *pdfBinSize = dfBinSize;
3209 :
3210 2 : return true;
3211 : }
3212 :
3213 : /************************************************************************/
3214 : /* GetTableType() */
3215 : /************************************************************************/
3216 :
3217 : /**
3218 : * \brief Get RAT Table Type
3219 : *
3220 : * Returns whether table type is thematic or athematic
3221 : *
3222 : * This method is the same as the C function GDALRATGetTableType().
3223 : *
3224 : *
3225 : * @return GRTT_THEMATIC or GRTT_ATHEMATIC
3226 : */
3227 :
3228 37 : GDALRATTableType GDALDefaultRasterAttributeTable::GetTableType() const
3229 : {
3230 37 : return eTableType;
3231 : }
3232 :
3233 : /************************************************************************/
3234 : /* SetTableType() */
3235 : /************************************************************************/
3236 :
3237 : /**
3238 : * \brief Set RAT Table Type
3239 : *
3240 : * Set whether table type is thematic or athematic
3241 : *
3242 : * This method is the same as the C function GDALRATSetTableType().
3243 : *
3244 : * @param eInTableType the new RAT table type (GRTT_THEMATIC or GRTT_ATHEMATIC)
3245 : *
3246 : *
3247 : * @return CE_None on success or CE_Failure on failure.
3248 : */
3249 :
3250 86 : CPLErr GDALDefaultRasterAttributeTable::SetTableType(
3251 : const GDALRATTableType eInTableType)
3252 : {
3253 86 : eTableType = eInTableType;
3254 86 : return CE_None;
3255 : }
3256 :
3257 : /************************************************************************/
3258 : /* CreateColumn() */
3259 : /************************************************************************/
3260 :
3261 : CPLErr
3262 1027 : GDALDefaultRasterAttributeTable::CreateColumn(const char *pszFieldName,
3263 : GDALRATFieldType eFieldType,
3264 : GDALRATFieldUsage eFieldUsage)
3265 :
3266 : {
3267 1027 : const size_t iNewField = aoFields.size();
3268 :
3269 1027 : aoFields.resize(iNewField + 1);
3270 :
3271 1027 : aoFields[iNewField].sName = pszFieldName;
3272 :
3273 : // color columns should be int 0..255
3274 1027 : if ((eFieldUsage == GFU_Red) || (eFieldUsage == GFU_Green) ||
3275 961 : (eFieldUsage == GFU_Blue) || (eFieldUsage == GFU_Alpha))
3276 : {
3277 73 : eFieldType = GFT_Integer;
3278 : }
3279 1027 : aoFields[iNewField].eType = eFieldType;
3280 1027 : aoFields[iNewField].eUsage = eFieldUsage;
3281 :
3282 1027 : switch (eFieldType)
3283 : {
3284 480 : case GFT_Integer:
3285 480 : aoFields[iNewField].anValues.resize(nRowCount);
3286 480 : break;
3287 :
3288 193 : case GFT_Real:
3289 193 : aoFields[iNewField].adfValues.resize(nRowCount);
3290 193 : break;
3291 :
3292 297 : case GFT_String:
3293 297 : aoFields[iNewField].aosValues.resize(nRowCount);
3294 297 : break;
3295 :
3296 23 : case GFT_Boolean:
3297 23 : aoFields[iNewField].abValues.resize(nRowCount);
3298 23 : break;
3299 :
3300 18 : case GFT_DateTime:
3301 18 : aoFields[iNewField].asDateTimeValues.resize(nRowCount);
3302 18 : break;
3303 :
3304 16 : case GFT_WKBGeometry:
3305 16 : aoFields[iNewField].aabyWKBGeometryValues.resize(nRowCount);
3306 16 : break;
3307 : }
3308 1027 : return CE_None;
3309 : }
3310 :
3311 : /************************************************************************/
3312 : /* RemoveStatistics() */
3313 : /************************************************************************/
3314 :
3315 : /**
3316 : * \brief Remove Statistics from RAT
3317 : *
3318 : * Remove statistics (such as histogram) from the RAT. This is important
3319 : * if these have been invalidated, for example by cropping the image.
3320 : *
3321 : * This method is the same as the C function GDALRATRemoveStatistics().
3322 : *
3323 : */
3324 :
3325 2 : void GDALDefaultRasterAttributeTable::RemoveStatistics()
3326 :
3327 : {
3328 : // since we are storing the fields in a vector it will generally
3329 : // be faster to create a new vector and replace the old one
3330 : // rather than actually erasing columns.
3331 4 : std::vector<GDALRasterAttributeField> aoNewFields;
3332 4 : for (const auto &field : aoFields)
3333 : {
3334 2 : switch (field.eUsage)
3335 : {
3336 1 : case GFU_PixelCount:
3337 : case GFU_Min:
3338 : case GFU_Max:
3339 : case GFU_RedMin:
3340 : case GFU_GreenMin:
3341 : case GFU_BlueMin:
3342 : case GFU_AlphaMin:
3343 : case GFU_RedMax:
3344 : case GFU_GreenMax:
3345 : case GFU_BlueMax:
3346 : case GFU_AlphaMax:
3347 : {
3348 1 : break;
3349 : }
3350 :
3351 1 : default:
3352 1 : if (field.sName != "Histogram")
3353 : {
3354 1 : aoNewFields.push_back(field);
3355 : }
3356 : }
3357 : }
3358 2 : aoFields = std::move(aoNewFields);
3359 2 : }
3360 :
3361 : /************************************************************************/
3362 : /* Clone() */
3363 : /************************************************************************/
3364 :
3365 68 : GDALDefaultRasterAttributeTable *GDALDefaultRasterAttributeTable::Clone() const
3366 :
3367 : {
3368 68 : return new GDALDefaultRasterAttributeTable(*this);
3369 : }
3370 :
3371 : /************************************************************************/
3372 : /* GDALRATClone() */
3373 : /************************************************************************/
3374 :
3375 : /**
3376 : * \brief Copy Raster Attribute Table
3377 : *
3378 : * This function is the same as the C++ method GDALRasterAttributeTable::Clone()
3379 : */
3380 : GDALRasterAttributeTableH CPL_STDCALL
3381 6 : GDALRATClone(const GDALRasterAttributeTableH hRAT)
3382 :
3383 : {
3384 6 : VALIDATE_POINTER1(hRAT, "GDALRATClone", nullptr);
3385 :
3386 6 : return GDALRasterAttributeTable::FromHandle(hRAT)->Clone();
3387 : }
3388 :
3389 : /************************************************************************/
3390 : /* GDALRATSerializeJSON() */
3391 : /************************************************************************/
3392 :
3393 : /**
3394 : * \brief Serialize Raster Attribute Table in Json format
3395 : *
3396 : * This function is the same as the C++ method
3397 : * GDALRasterAttributeTable::SerializeJSON()
3398 : */
3399 9 : void *CPL_STDCALL GDALRATSerializeJSON(GDALRasterAttributeTableH hRAT)
3400 :
3401 : {
3402 9 : VALIDATE_POINTER1(hRAT, "GDALRATSerializeJSON", nullptr);
3403 :
3404 9 : return GDALRasterAttributeTable::FromHandle(hRAT)->SerializeJSON();
3405 : }
3406 :
3407 : /************************************************************************/
3408 : /* GDALRATRemoveStatistics() */
3409 : /************************************************************************/
3410 :
3411 : /**
3412 : * \brief Remove Statistics from RAT
3413 : *
3414 : * This function is the same as the C++ method
3415 : * GDALRasterAttributeTable::RemoveStatistics()
3416 : *
3417 : */
3418 1 : void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
3419 :
3420 : {
3421 1 : VALIDATE_POINTER0(hRAT, "GDALRATRemoveStatistics");
3422 :
3423 1 : GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
3424 : }
3425 :
3426 : /************************************************************************/
3427 : /* GDALLoadEsriCLRAsRAT() */
3428 : /************************************************************************/
3429 :
3430 : /**
3431 : * \brief Load a Esri .clr as a RAT.
3432 : *
3433 : * @param pszFilename .clr filename
3434 : *
3435 : * @return a new RAT, or nullptr in case of error.
3436 : *
3437 : * @since GDAL 3.14
3438 : */
3439 : std::unique_ptr<GDALRasterAttributeTable>
3440 88 : GDALLoadEsriCLRAsRAT(const char *pszFilename)
3441 : {
3442 176 : auto fp = VSIFilesystemHandler::OpenStatic(pszFilename, "rb");
3443 88 : if (!fp)
3444 80 : return nullptr;
3445 :
3446 16 : auto poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
3447 8 : poRAT->CreateColumn("Value", GFT_Integer, GFU_Generic);
3448 8 : poRAT->CreateColumn("Red", GFT_Integer, GFU_Red);
3449 8 : poRAT->CreateColumn("Green", GFT_Integer, GFU_Green);
3450 8 : poRAT->CreateColumn("Blue", GFT_Integer, GFU_Blue);
3451 :
3452 8 : int nRatRow = 0;
3453 :
3454 8 : constexpr int MAX_LINE_SIZE = 1000; // Arbitary
3455 : while (const char *pszLine =
3456 120 : CPLReadLine2L(fp.get(), MAX_LINE_SIZE, nullptr))
3457 : {
3458 112 : if (*pszLine == '#' || *pszLine == '!')
3459 0 : continue;
3460 :
3461 : const CPLStringList aosTokens(
3462 224 : CSLTokenizeString2(pszLine, "\t ", CSLT_HONOURSTRINGS));
3463 :
3464 112 : if (aosTokens.size() >= 4)
3465 : {
3466 112 : const int nIndex = atoi(aosTokens[0]);
3467 112 : poRAT->SetValue(nRatRow, 0, nIndex);
3468 112 : poRAT->SetValue(nRatRow, 1, atoi(aosTokens[1]));
3469 112 : poRAT->SetValue(nRatRow, 2, atoi(aosTokens[2]));
3470 112 : poRAT->SetValue(nRatRow, 3, atoi(aosTokens[3]));
3471 112 : nRatRow++;
3472 : }
3473 112 : }
3474 :
3475 8 : return poRAT;
3476 : }
|