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