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 : /**
44 : * \class GDALRasterAttributeTable
45 : *
46 : * The GDALRasterAttributeTable (or RAT) class is used to encapsulate a table
47 : * used to provide attribute information about pixel values. Each row
48 : * in the table applies to a range of pixel values (or a single value in
49 : * some cases), and might have attributes such as the histogram count for
50 : * that range, the color pixels of that range should be drawn names of classes
51 : * or any other generic information.
52 : *
53 : * Raster attribute tables can be used to represent histograms, color tables,
54 : * and classification information.
55 : *
56 : * Each column in a raster attribute table has a name, a type (integer,
57 : * floating point or string), and a GDALRATFieldUsage. The usage distinguishes
58 : * columns with particular understood purposes (such as color, histogram
59 : * count, name) and columns that have specific purposes not understood by
60 : * the library (long label, suitability_for_growing_wheat, etc).
61 : *
62 : * In the general case each row has a column indicating the minimum pixel
63 : * values falling into that category, and a column indicating the maximum
64 : * pixel value. These are indicated with usage values of GFU_Min, and
65 : * GFU_Max. In other cases where each row is a discrete pixel value, one
66 : * column of usage GFU_MinMax can be used.
67 : *
68 : * In other cases all the categories are of equal size and regularly spaced
69 : * and the categorization information can be determined just by knowing the
70 : * value at which the categories start, and the size of a category. This
71 : * is called "Linear Binning" and the information is kept specially on
72 : * the raster attribute table as a whole.
73 : *
74 : * RATs are normally associated with GDALRasterBands and can be queried
75 : * using the GDALRasterBand::GetDefaultRAT() method.
76 : */
77 :
78 : /************************************************************************/
79 : /* ~GDALRasterAttributeTable() */
80 : /* */
81 : /* Virtual Destructor */
82 : /************************************************************************/
83 :
84 : GDALRasterAttributeTable::~GDALRasterAttributeTable() = default;
85 :
86 : /************************************************************************/
87 : /* ValuesIO() */
88 : /* */
89 : /* Default Implementations */
90 : /************************************************************************/
91 :
92 : /**
93 : * \brief Read or Write a block of doubles to/from the Attribute Table.
94 : *
95 : * This method is the same as the C function GDALRATValuesIOAsDouble().
96 : *
97 : * @param eRWFlag Either GF_Read or GF_Write
98 : * @param iField column of the Attribute Table
99 : * @param iStartRow start row to start reading/writing (zero based)
100 : * @param iLength number of rows to read or write
101 : * @param pdfData pointer to array of doubles to read/write. Should be at least
102 : * iLength long.
103 : *
104 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
105 : * rows in table.
106 : */
107 :
108 6 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
109 : int iStartRow, int iLength,
110 : double *pdfData)
111 : {
112 6 : if ((iStartRow + iLength) > GetRowCount())
113 : {
114 0 : return CE_Failure;
115 : }
116 :
117 6 : CPLErr eErr = CE_None;
118 6 : if (eRWFlag == GF_Read)
119 : {
120 28 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
121 : {
122 22 : pdfData[iIndex - iStartRow] = GetValueAsDouble(iIndex, iField);
123 : }
124 : }
125 : else
126 : {
127 0 : for (int iIndex = iStartRow;
128 0 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
129 : {
130 0 : eErr = SetValue(iIndex, iField, pdfData[iIndex - iStartRow]);
131 : }
132 : }
133 6 : return eErr;
134 : }
135 :
136 : /************************************************************************/
137 : /* GDALRATValuesIOAsDouble() */
138 : /************************************************************************/
139 :
140 : /**
141 : * \brief Read or Write a block of doubles to/from the Attribute Table.
142 : *
143 : * This function is the same as the C++ method
144 : * GDALRasterAttributeTable::ValuesIO()
145 : */
146 28 : CPLErr CPL_STDCALL GDALRATValuesIOAsDouble(GDALRasterAttributeTableH hRAT,
147 : GDALRWFlag eRWFlag, int iField,
148 : int iStartRow, int iLength,
149 : double *pdfData)
150 :
151 : {
152 28 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDouble", CE_Failure);
153 :
154 56 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
155 28 : eRWFlag, iField, iStartRow, iLength, pdfData);
156 : }
157 :
158 : /**
159 : * \brief Read or Write a block of integers to/from the Attribute Table.
160 : *
161 : * This method is the same as the C function GDALRATValuesIOAsInteger().
162 : *
163 : * @param eRWFlag Either GF_Read or GF_Write
164 : * @param iField column of the Attribute Table
165 : * @param iStartRow start row to start reading/writing (zero based)
166 : * @param iLength number of rows to read or write
167 : * @param pnData pointer to array of ints to read/write. Should be at least
168 : * iLength long.
169 : *
170 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
171 : * rows in table.
172 : */
173 :
174 11 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
175 : int iStartRow, int iLength,
176 : int *pnData)
177 : {
178 11 : if ((iStartRow + iLength) > GetRowCount())
179 : {
180 1 : return CE_Failure;
181 : }
182 :
183 10 : CPLErr eErr = CE_None;
184 10 : if (eRWFlag == GF_Read)
185 : {
186 52 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
187 : {
188 42 : pnData[iIndex - iStartRow] = GetValueAsInt(iIndex, iField);
189 : }
190 : }
191 : else
192 : {
193 0 : for (int iIndex = iStartRow;
194 0 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
195 : {
196 0 : eErr = SetValue(iIndex, iField, pnData[iIndex - iStartRow]);
197 : }
198 : }
199 10 : return eErr;
200 : }
201 :
202 : /************************************************************************/
203 : /* GDALRATValuesIOAsInteger() */
204 : /************************************************************************/
205 :
206 : /**
207 : * \brief Read or Write a block of ints to/from the Attribute Table.
208 : *
209 : * This function is the same as the C++ method
210 : * GDALRasterAttributeTable::ValuesIO()
211 : */
212 33 : CPLErr CPL_STDCALL GDALRATValuesIOAsInteger(GDALRasterAttributeTableH hRAT,
213 : GDALRWFlag eRWFlag, int iField,
214 : int iStartRow, int iLength,
215 : int *pnData)
216 :
217 : {
218 33 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsInteger", CE_Failure);
219 :
220 66 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
221 33 : eRWFlag, iField, iStartRow, iLength, pnData);
222 : }
223 :
224 : /**
225 : * \brief Read or Write a block of strings to/from the Attribute Table.
226 : *
227 : * This method is the same as the C function GDALRATValuesIOAsString().
228 : * When reading, papszStrList must be already allocated to the correct size.
229 : * The caller is expected to call CPLFree on each read string.
230 : *
231 : * @param eRWFlag Either GF_Read or GF_Write
232 : * @param iField column of the Attribute Table
233 : * @param iStartRow start row to start reading/writing (zero based)
234 : * @param iLength number of rows to read or write
235 : * @param papszStrList pointer to array of strings to read/write. Should be at
236 : * least iLength long.
237 : *
238 : * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
239 : * rows in table.
240 : */
241 :
242 6 : CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
243 : int iStartRow, int iLength,
244 : char **papszStrList)
245 : {
246 6 : if ((iStartRow + iLength) > GetRowCount())
247 : {
248 0 : return CE_Failure;
249 : }
250 :
251 6 : CPLErr eErr = CE_None;
252 6 : if (eRWFlag == GF_Read)
253 : {
254 28 : for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
255 : {
256 44 : papszStrList[iIndex - iStartRow] =
257 22 : VSIStrdup(GetValueAsString(iIndex, iField));
258 : }
259 : }
260 : else
261 : {
262 0 : for (int iIndex = iStartRow;
263 0 : eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
264 : {
265 0 : eErr = SetValue(iIndex, iField, papszStrList[iIndex - iStartRow]);
266 : }
267 : }
268 6 : return eErr;
269 : }
270 :
271 : /************************************************************************/
272 : /* GDALRATValuesIOAsString() */
273 : /************************************************************************/
274 :
275 : /**
276 : * \brief Read or Write a block of strings to/from the Attribute Table.
277 : *
278 : * This function is the same as the C++ method
279 : * GDALRasterAttributeTable::ValuesIO()
280 : */
281 30 : CPLErr CPL_STDCALL GDALRATValuesIOAsString(GDALRasterAttributeTableH hRAT,
282 : GDALRWFlag eRWFlag, int iField,
283 : int iStartRow, int iLength,
284 : char **papszStrList)
285 :
286 : {
287 30 : VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsString", CE_Failure);
288 :
289 60 : return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
290 30 : eRWFlag, iField, iStartRow, iLength, papszStrList);
291 : }
292 :
293 : /************************************************************************/
294 : /* SetRowCount() */
295 : /************************************************************************/
296 :
297 : /**
298 : * \brief Set row count.
299 : *
300 : * Resizes the table to include the indicated number of rows. Newly created
301 : * rows will be initialized to their default values - "" for strings,
302 : * and zero for numeric fields.
303 : *
304 : * This method is the same as the C function GDALRATSetRowCount().
305 : *
306 : * @param nNewCount the new number of rows.
307 : */
308 :
309 0 : void GDALRasterAttributeTable::SetRowCount(CPL_UNUSED int nNewCount)
310 : {
311 0 : }
312 :
313 : /************************************************************************/
314 : /* GDALRATSetRowCount() */
315 : /************************************************************************/
316 :
317 : /**
318 : * \brief Set row count.
319 : *
320 : * This function is the same as the C++ method
321 : * GDALRasterAttributeTable::SetRowCount()
322 : *
323 : * @param hRAT RAT handle.
324 : * @param nNewCount the new number of rows.
325 : */
326 7 : void CPL_STDCALL GDALRATSetRowCount(GDALRasterAttributeTableH hRAT,
327 : int nNewCount)
328 :
329 : {
330 7 : VALIDATE_POINTER0(hRAT, "GDALRATSetRowCount");
331 :
332 7 : GDALRasterAttributeTable::FromHandle(hRAT)->SetRowCount(nNewCount);
333 : }
334 :
335 : /************************************************************************/
336 : /* GetRowOfValue() */
337 : /************************************************************************/
338 :
339 : /**
340 : * \fn GDALRasterAttributeTable::GetRowOfValue(double) const
341 : * \brief Get row for pixel value.
342 : *
343 : * Given a raw pixel value, the raster attribute table is scanned to
344 : * determine which row in the table applies to the pixel value. The
345 : * row index is returned.
346 : *
347 : * This method is the same as the C function GDALRATGetRowOfValue().
348 : *
349 : * @param dfValue the pixel value.
350 : *
351 : * @return the row index or -1 if no row is appropriate.
352 : */
353 :
354 : /**/
355 : /**/
356 :
357 0 : int GDALRasterAttributeTable::GetRowOfValue(double /* dfValue */) const
358 : {
359 0 : return -1;
360 : }
361 :
362 : /************************************************************************/
363 : /* GDALRATGetRowOfValue() */
364 : /************************************************************************/
365 :
366 : /**
367 : * \brief Get row for pixel value.
368 : *
369 : * This function is the same as the C++ method
370 : * GDALRasterAttributeTable::GetRowOfValue()
371 : */
372 3 : int CPL_STDCALL GDALRATGetRowOfValue(GDALRasterAttributeTableH hRAT,
373 : double dfValue)
374 :
375 : {
376 3 : VALIDATE_POINTER1(hRAT, "GDALRATGetRowOfValue", 0);
377 :
378 3 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowOfValue(dfValue);
379 : }
380 :
381 : /************************************************************************/
382 : /* GetRowOfValue() */
383 : /************************************************************************/
384 :
385 : /**
386 : * \brief Get row for pixel value.
387 : *
388 : * Given a raw pixel value, the raster attribute table is scanned to
389 : * determine which row in the table applies to the pixel value. The
390 : * row index is returned.
391 : *
392 : * Int arg for now just converted to double. Perhaps we will
393 : * handle this in a special way some day?
394 : *
395 : * This method is the same as the C function GDALRATGetRowOfValue().
396 : *
397 : * @param nValue the pixel value.
398 : *
399 : * @return the row index or -1 if no row is appropriate.
400 : */
401 :
402 0 : int GDALRasterAttributeTable::GetRowOfValue(int nValue) const
403 :
404 : {
405 0 : return GetRowOfValue(static_cast<double>(nValue));
406 : }
407 :
408 : /************************************************************************/
409 : /* CreateColumn() */
410 : /************************************************************************/
411 :
412 : /**
413 : * \fn GDALRasterAttributeTable::CreateColumn(const char*, GDALRATFieldType,
414 : * GDALRATFieldUsage) \brief Create new column.
415 : *
416 : * If the table already has rows, all row values for the new column will
417 : * be initialized to the default value ("", or zero). The new column is
418 : * always created as the last column, and will be column (field)
419 : * "GetColumnCount()-1" after CreateColumn() has completed successfully.
420 : *
421 : * This method is the same as the C function GDALRATCreateColumn().
422 : *
423 : * @param pszFieldName the name of the field to create.
424 : * @param eFieldType the field type (integer, double or string).
425 : * @param eFieldUsage the field usage, GFU_Generic if not known.
426 : *
427 : * @return CE_None on success or CE_Failure if something goes wrong.
428 : */
429 :
430 : /**/
431 : /**/
432 :
433 : CPLErr
434 0 : GDALRasterAttributeTable::CreateColumn(const char * /* pszFieldName */,
435 : GDALRATFieldType /* eFieldType */,
436 : GDALRATFieldUsage /* eFieldUsage */)
437 : {
438 0 : return CE_Failure;
439 : }
440 :
441 : /************************************************************************/
442 : /* GDALRATCreateColumn() */
443 : /************************************************************************/
444 :
445 : /**
446 : * \brief Create new column.
447 : *
448 : * This function is the same as the C++ method
449 : * GDALRasterAttributeTable::CreateColumn()
450 : */
451 31 : CPLErr CPL_STDCALL GDALRATCreateColumn(GDALRasterAttributeTableH hRAT,
452 : const char *pszFieldName,
453 : GDALRATFieldType eFieldType,
454 : GDALRATFieldUsage eFieldUsage)
455 :
456 : {
457 31 : VALIDATE_POINTER1(hRAT, "GDALRATCreateColumn", CE_Failure);
458 :
459 62 : return GDALRasterAttributeTable::FromHandle(hRAT)->CreateColumn(
460 31 : pszFieldName, eFieldType, eFieldUsage);
461 : }
462 :
463 : /************************************************************************/
464 : /* SetLinearBinning() */
465 : /************************************************************************/
466 :
467 : /**
468 : * \brief Set linear binning information.
469 : *
470 : * For RATs with equal sized categories (in pixel value space) that are
471 : * evenly spaced, this method may be used to associate the linear binning
472 : * information with the table.
473 : *
474 : * This method is the same as the C function GDALRATSetLinearBinning().
475 : *
476 : * @param dfRow0MinIn the lower bound (pixel value) of the first category.
477 : * @param dfBinSizeIn the width of each category (in pixel value units).
478 : *
479 : * @return CE_None on success or CE_Failure on failure.
480 : */
481 :
482 0 : CPLErr GDALRasterAttributeTable::SetLinearBinning(CPL_UNUSED double dfRow0MinIn,
483 : CPL_UNUSED double dfBinSizeIn)
484 : {
485 0 : return CE_Failure;
486 : }
487 :
488 : /************************************************************************/
489 : /* GDALRATSetLinearBinning() */
490 : /************************************************************************/
491 :
492 : /**
493 : * \brief Set linear binning information.
494 : *
495 : * This function is the same as the C++ method
496 : * GDALRasterAttributeTable::SetLinearBinning()
497 : */
498 1 : CPLErr CPL_STDCALL GDALRATSetLinearBinning(GDALRasterAttributeTableH hRAT,
499 : double dfRow0Min, double dfBinSize)
500 :
501 : {
502 1 : VALIDATE_POINTER1(hRAT, "GDALRATSetLinearBinning", CE_Failure);
503 :
504 2 : return GDALRasterAttributeTable::FromHandle(hRAT)->SetLinearBinning(
505 1 : dfRow0Min, dfBinSize);
506 : }
507 :
508 : /************************************************************************/
509 : /* GetLinearBinning() */
510 : /************************************************************************/
511 :
512 : /**
513 : * \brief Get linear binning information.
514 : *
515 : * Returns linear binning information if any is associated with the RAT.
516 : *
517 : * This method is the same as the C function GDALRATGetLinearBinning().
518 : *
519 : * @param pdfRow0Min (out) the lower bound (pixel value) of the first category.
520 : * @param pdfBinSize (out) the width of each category (in pixel value units).
521 : *
522 : * @return TRUE if linear binning information exists or FALSE if there is none.
523 : */
524 :
525 0 : int GDALRasterAttributeTable::GetLinearBinning(
526 : CPL_UNUSED double *pdfRow0Min, CPL_UNUSED double *pdfBinSize) const
527 : {
528 0 : return false;
529 : }
530 :
531 : /************************************************************************/
532 : /* GDALRATGetLinearBinning() */
533 : /************************************************************************/
534 :
535 : /**
536 : * \brief Get linear binning information.
537 : *
538 : * This function is the same as the C++ method
539 : * GDALRasterAttributeTable::GetLinearBinning()
540 : */
541 1 : int CPL_STDCALL GDALRATGetLinearBinning(GDALRasterAttributeTableH hRAT,
542 : double *pdfRow0Min, double *pdfBinSize)
543 :
544 : {
545 1 : VALIDATE_POINTER1(hRAT, "GDALRATGetLinearBinning", 0);
546 :
547 2 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetLinearBinning(
548 1 : pdfRow0Min, pdfBinSize);
549 : }
550 :
551 : /************************************************************************/
552 : /* GDALRATGetTableType() */
553 : /************************************************************************/
554 :
555 : /**
556 : * \brief Get Rat Table Type
557 : *
558 : * @since GDAL 2.4
559 : *
560 : * This function is the same as the C++ method
561 : * GDALRasterAttributeTable::GetTableType()
562 : */
563 10 : GDALRATTableType CPL_STDCALL GDALRATGetTableType(GDALRasterAttributeTableH hRAT)
564 : {
565 10 : VALIDATE_POINTER1(hRAT, "GDALRATGetTableType", GRTT_THEMATIC);
566 :
567 10 : return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->GetTableType();
568 : }
569 :
570 : /************************************************************************/
571 : /* GDALRATSetTableType() */
572 : /************************************************************************/
573 :
574 : /**
575 : * \brief Set RAT Table Type
576 : *
577 : * @since GDAL 2.4
578 : *
579 : * This function is the same as the C++ method
580 : * GDALRasterAttributeTable::SetTableType()
581 : */
582 3 : CPLErr CPL_STDCALL GDALRATSetTableType(GDALRasterAttributeTableH hRAT,
583 : const GDALRATTableType eInTableType)
584 :
585 : {
586 3 : VALIDATE_POINTER1(hRAT, "GDALRATSetTableType", CE_Failure);
587 :
588 6 : return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->SetTableType(
589 3 : eInTableType);
590 : }
591 :
592 : /************************************************************************/
593 : /* Serialize() */
594 : /************************************************************************/
595 :
596 : /** Serialize as a XML tree.
597 : * @return XML tree.
598 : */
599 12 : CPLXMLNode *GDALRasterAttributeTable::Serialize() const
600 :
601 : {
602 12 : if ((GetColumnCount() == 0) && (GetRowCount() == 0))
603 1 : return nullptr;
604 :
605 : CPLXMLNode *psTree =
606 11 : CPLCreateXMLNode(nullptr, CXT_Element, "GDALRasterAttributeTable");
607 :
608 : /* -------------------------------------------------------------------- */
609 : /* Add attributes with regular binning info if appropriate. */
610 : /* -------------------------------------------------------------------- */
611 11 : char szValue[128] = {'\0'};
612 11 : double dfRow0Min = 0.0;
613 11 : double dfBinSize = 0.0;
614 :
615 11 : if (GetLinearBinning(&dfRow0Min, &dfBinSize))
616 : {
617 4 : CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfRow0Min);
618 4 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "Row0Min"),
619 : CXT_Text, szValue);
620 :
621 4 : CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfBinSize);
622 4 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "BinSize"),
623 : CXT_Text, szValue);
624 : }
625 :
626 : /* -------------------------------------------------------------------- */
627 : /* Store table type */
628 : /* -------------------------------------------------------------------- */
629 11 : const GDALRATTableType tableType = GetTableType();
630 11 : if (tableType == GRTT_ATHEMATIC)
631 : {
632 3 : CPLsnprintf(szValue, sizeof(szValue), "athematic");
633 : }
634 : else
635 : {
636 8 : CPLsnprintf(szValue, sizeof(szValue), "thematic");
637 : }
638 11 : CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "tableType"),
639 : CXT_Text, szValue);
640 :
641 : /* -------------------------------------------------------------------- */
642 : /* Define each column. */
643 : /* -------------------------------------------------------------------- */
644 11 : const int iColCount = GetColumnCount();
645 :
646 25 : for (int iCol = 0; iCol < iColCount; iCol++)
647 : {
648 14 : CPLXMLNode *psCol = CPLCreateXMLNode(psTree, CXT_Element, "FieldDefn");
649 :
650 14 : snprintf(szValue, sizeof(szValue), "%d", iCol);
651 14 : CPLCreateXMLNode(CPLCreateXMLNode(psCol, CXT_Attribute, "index"),
652 : CXT_Text, szValue);
653 :
654 14 : CPLCreateXMLElementAndValue(psCol, "Name", GetNameOfCol(iCol));
655 :
656 14 : snprintf(szValue, sizeof(szValue), "%d",
657 14 : static_cast<int>(GetTypeOfCol(iCol)));
658 : CPLXMLNode *psType =
659 14 : CPLCreateXMLElementAndValue(psCol, "Type", szValue);
660 14 : const char *pszTypeStr = "String";
661 14 : switch (GetTypeOfCol(iCol))
662 : {
663 8 : case GFT_Integer:
664 8 : pszTypeStr = "Integer";
665 8 : break;
666 4 : case GFT_Real:
667 4 : pszTypeStr = "Real";
668 4 : break;
669 2 : case GFT_String:
670 2 : break;
671 : }
672 14 : CPLAddXMLAttributeAndValue(psType, "typeAsString", pszTypeStr);
673 :
674 14 : snprintf(szValue, sizeof(szValue), "%d",
675 14 : static_cast<int>(GetUsageOfCol(iCol)));
676 : CPLXMLNode *psUsage =
677 14 : CPLCreateXMLElementAndValue(psCol, "Usage", szValue);
678 14 : const char *pszUsageStr = "";
679 :
680 : #define USAGE_STR(x) \
681 : case GFU_##x: \
682 : pszUsageStr = #x; \
683 : break
684 14 : switch (GetUsageOfCol(iCol))
685 : {
686 4 : USAGE_STR(Generic);
687 5 : USAGE_STR(PixelCount);
688 2 : USAGE_STR(Name);
689 0 : USAGE_STR(Min);
690 0 : USAGE_STR(Max);
691 3 : USAGE_STR(MinMax);
692 0 : USAGE_STR(Red);
693 0 : USAGE_STR(Green);
694 0 : USAGE_STR(Blue);
695 0 : USAGE_STR(Alpha);
696 0 : USAGE_STR(RedMin);
697 0 : USAGE_STR(GreenMin);
698 0 : USAGE_STR(BlueMin);
699 0 : USAGE_STR(AlphaMin);
700 0 : USAGE_STR(RedMax);
701 0 : USAGE_STR(GreenMax);
702 0 : USAGE_STR(BlueMax);
703 0 : USAGE_STR(AlphaMax);
704 0 : case GFU_MaxCount:
705 0 : break;
706 : }
707 : #undef USAGE_STR
708 14 : CPLAddXMLAttributeAndValue(psUsage, "usageAsString", pszUsageStr);
709 : }
710 :
711 : /* -------------------------------------------------------------------- */
712 : /* Write out each row. */
713 : /* -------------------------------------------------------------------- */
714 11 : const int iRowCount = GetRowCount();
715 11 : CPLXMLNode *psTail = nullptr;
716 11 : CPLXMLNode *psRow = nullptr;
717 :
718 1001 : for (int iRow = 0; iRow < iRowCount; iRow++)
719 : {
720 990 : psRow = CPLCreateXMLNode(nullptr, CXT_Element, "Row");
721 990 : if (psTail == nullptr)
722 7 : CPLAddXMLChild(psTree, psRow);
723 : else
724 983 : psTail->psNext = psRow;
725 990 : psTail = psRow;
726 :
727 990 : snprintf(szValue, sizeof(szValue), "%d", iRow);
728 990 : CPLCreateXMLNode(CPLCreateXMLNode(psRow, CXT_Attribute, "index"),
729 : CXT_Text, szValue);
730 :
731 1985 : for (int iCol = 0; iCol < iColCount; iCol++)
732 : {
733 995 : const char *pszValue = szValue;
734 :
735 995 : if (GetTypeOfCol(iCol) == GFT_Integer)
736 8 : snprintf(szValue, sizeof(szValue), "%d",
737 8 : GetValueAsInt(iRow, iCol));
738 987 : else if (GetTypeOfCol(iCol) == GFT_Real)
739 985 : CPLsnprintf(szValue, sizeof(szValue), "%.16g",
740 985 : GetValueAsDouble(iRow, iCol));
741 : else
742 2 : pszValue = GetValueAsString(iRow, iCol);
743 :
744 995 : CPLCreateXMLElementAndValue(psRow, "F", pszValue);
745 : }
746 : }
747 :
748 11 : return psTree;
749 : }
750 :
751 : /************************************************************************/
752 : /* SerializeJSON() */
753 : /************************************************************************/
754 :
755 : /** Serialize as a JSON object.
756 : * @return JSON object (of type json_object*)
757 : */
758 4 : void *GDALRasterAttributeTable::SerializeJSON() const
759 :
760 : {
761 4 : json_object *poRAT = json_object_new_object();
762 :
763 4 : if ((GetColumnCount() == 0) && (GetRowCount() == 0))
764 0 : return poRAT;
765 :
766 : /* -------------------------------------------------------------------- */
767 : /* Add attributes with regular binning info if appropriate. */
768 : /* -------------------------------------------------------------------- */
769 4 : double dfRow0Min = 0.0;
770 4 : double dfBinSize = 0.0;
771 4 : json_object *poRow0Min = nullptr;
772 4 : json_object *poBinSize = nullptr;
773 4 : json_object *poTableType = nullptr;
774 :
775 4 : if (GetLinearBinning(&dfRow0Min, &dfBinSize))
776 : {
777 2 : poRow0Min = json_object_new_double_with_precision(dfRow0Min, 16);
778 2 : json_object_object_add(poRAT, "row0Min", poRow0Min);
779 :
780 2 : poBinSize = json_object_new_double_with_precision(dfBinSize, 16);
781 2 : json_object_object_add(poRAT, "binSize", poBinSize);
782 : }
783 :
784 : /* -------------------------------------------------------------------- */
785 : /* Table Type */
786 : /* -------------------------------------------------------------------- */
787 4 : const GDALRATTableType tableType = GetTableType();
788 4 : if (tableType == GRTT_ATHEMATIC)
789 : {
790 1 : poTableType = json_object_new_string("athematic");
791 : }
792 : else
793 : {
794 3 : poTableType = json_object_new_string("thematic");
795 : }
796 4 : json_object_object_add(poRAT, "tableType", poTableType);
797 :
798 : /* -------------------------------------------------------------------- */
799 : /* Define each column. */
800 : /* -------------------------------------------------------------------- */
801 4 : const int iColCount = GetColumnCount();
802 4 : json_object *poFieldDefnArray = json_object_new_array();
803 :
804 29 : for (int iCol = 0; iCol < iColCount; iCol++)
805 : {
806 25 : json_object *const poFieldDefn = json_object_new_object();
807 :
808 25 : json_object *const poColumnIndex = json_object_new_int(iCol);
809 25 : json_object_object_add(poFieldDefn, "index", poColumnIndex);
810 :
811 25 : json_object *const poName = json_object_new_string(GetNameOfCol(iCol));
812 25 : json_object_object_add(poFieldDefn, "name", poName);
813 :
814 : json_object *const poType =
815 25 : json_object_new_int(static_cast<int>(GetTypeOfCol(iCol)));
816 25 : json_object_object_add(poFieldDefn, "type", poType);
817 :
818 : json_object *const poUsage =
819 25 : json_object_new_int(static_cast<int>(GetUsageOfCol(iCol)));
820 25 : json_object_object_add(poFieldDefn, "usage", poUsage);
821 :
822 25 : json_object_array_add(poFieldDefnArray, poFieldDefn);
823 : }
824 :
825 4 : json_object_object_add(poRAT, "fieldDefn", poFieldDefnArray);
826 :
827 : /* -------------------------------------------------------------------- */
828 : /* Write out each row. */
829 : /* -------------------------------------------------------------------- */
830 4 : const int iRowCount = GetRowCount();
831 4 : json_object *poRowArray = json_object_new_array();
832 :
833 928 : for (int iRow = 0; iRow < iRowCount; iRow++)
834 : {
835 924 : json_object *const poRow = json_object_new_object();
836 :
837 924 : json_object *const poRowIndex = json_object_new_int(iRow);
838 924 : json_object_object_add(poRow, "index", poRowIndex);
839 :
840 924 : json_object *const poFArray = json_object_new_array();
841 :
842 3993 : for (int iCol = 0; iCol < iColCount; iCol++)
843 : {
844 3069 : json_object *poF = nullptr;
845 3069 : if (GetTypeOfCol(iCol) == GFT_Integer)
846 2840 : poF = json_object_new_int(GetValueAsInt(iRow, iCol));
847 229 : else if (GetTypeOfCol(iCol) == GFT_Real)
848 221 : poF = json_object_new_double_with_precision(
849 221 : GetValueAsDouble(iRow, iCol), 16);
850 : else
851 8 : poF = json_object_new_string(GetValueAsString(iRow, iCol));
852 :
853 3069 : json_object_array_add(poFArray, poF);
854 : }
855 924 : json_object_object_add(poRow, "f", poFArray);
856 924 : json_object_array_add(poRowArray, poRow);
857 : }
858 4 : json_object_object_add(poRAT, "row", poRowArray);
859 :
860 4 : return poRAT;
861 : }
862 :
863 : /************************************************************************/
864 : /* XMLInit() */
865 : /************************************************************************/
866 :
867 : /** Deserialize from XML.
868 : * @param psTree XML tree
869 : * @return error code.
870 : */
871 13 : CPLErr GDALRasterAttributeTable::XMLInit(const CPLXMLNode *psTree,
872 : const char * /*pszVRTPath*/)
873 :
874 : {
875 13 : CPLAssert(GetRowCount() == 0 && GetColumnCount() == 0);
876 :
877 : /* -------------------------------------------------------------------- */
878 : /* Linear binning. */
879 : /* -------------------------------------------------------------------- */
880 18 : if (CPLGetXMLValue(psTree, "Row0Min", nullptr) &&
881 5 : CPLGetXMLValue(psTree, "BinSize", nullptr))
882 : {
883 5 : SetLinearBinning(CPLAtof(CPLGetXMLValue(psTree, "Row0Min", "")),
884 5 : CPLAtof(CPLGetXMLValue(psTree, "BinSize", "")));
885 : }
886 :
887 : /* -------------------------------------------------------------------- */
888 : /* Table Type */
889 : /* -------------------------------------------------------------------- */
890 13 : if (CPLGetXMLValue(psTree, "tableType", nullptr))
891 : {
892 11 : const char *pszValue = CPLGetXMLValue(psTree, "tableType", "thematic");
893 11 : if (EQUAL(pszValue, "athematic"))
894 : {
895 3 : SetTableType(GRTT_ATHEMATIC);
896 : }
897 : else
898 : {
899 8 : SetTableType(GRTT_THEMATIC);
900 : }
901 : }
902 :
903 : /* -------------------------------------------------------------------- */
904 : /* Column definitions */
905 : /* -------------------------------------------------------------------- */
906 :
907 1335 : for (CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
908 1322 : psChild = psChild->psNext)
909 : {
910 1322 : if (psChild->eType == CXT_Element &&
911 1301 : EQUAL(psChild->pszValue, "FieldDefn"))
912 : {
913 15 : CreateColumn(CPLGetXMLValue(psChild, "Name", ""),
914 : static_cast<GDALRATFieldType>(
915 15 : atoi(CPLGetXMLValue(psChild, "Type", "1"))),
916 : static_cast<GDALRATFieldUsage>(
917 15 : atoi(CPLGetXMLValue(psChild, "Usage", "0"))));
918 : }
919 : }
920 :
921 : /* -------------------------------------------------------------------- */
922 : /* Row data. */
923 : /* -------------------------------------------------------------------- */
924 1335 : for (const CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
925 1322 : psChild = psChild->psNext)
926 : {
927 1322 : if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue, "Row"))
928 : {
929 1286 : const int iRow = atoi(CPLGetXMLValue(psChild, "index", "0"));
930 1286 : int iField = 0;
931 :
932 3864 : for (CPLXMLNode *psF = psChild->psChild; psF != nullptr;
933 2578 : psF = psF->psNext)
934 : {
935 2578 : if (psF->eType != CXT_Element || !EQUAL(psF->pszValue, "F"))
936 1286 : continue;
937 :
938 1292 : if (psF->psChild != nullptr && psF->psChild->eType == CXT_Text)
939 1292 : SetValue(iRow, iField++, psF->psChild->pszValue);
940 : else
941 0 : SetValue(iRow, iField++, "");
942 : }
943 : }
944 : }
945 :
946 13 : return CE_None;
947 : }
948 :
949 : /************************************************************************/
950 : /* InitializeFromColorTable() */
951 : /************************************************************************/
952 :
953 : /**
954 : * \brief Initialize from color table.
955 : *
956 : * This method will setup a whole raster attribute table based on the
957 : * contents of the passed color table. The Value (GFU_MinMax),
958 : * Red (GFU_Red), Green (GFU_Green), Blue (GFU_Blue), and Alpha (GFU_Alpha)
959 : * fields are created, and a row is set for each entry in the color table.
960 : *
961 : * The raster attribute table must be empty before calling
962 : * InitializeFromColorTable().
963 : *
964 : * The Value fields are set based on the implicit assumption with color
965 : * tables that entry 0 applies to pixel value 0, 1 to 1, etc.
966 : *
967 : * This method is the same as the C function GDALRATInitializeFromColorTable().
968 : *
969 : * @param poTable the color table to copy from.
970 : *
971 : * @return CE_None on success or CE_Failure if something goes wrong.
972 : */
973 :
974 0 : CPLErr GDALRasterAttributeTable::InitializeFromColorTable(
975 : const GDALColorTable *poTable)
976 :
977 : {
978 0 : if (GetRowCount() > 0 || GetColumnCount() > 0)
979 : {
980 0 : CPLError(CE_Failure, CPLE_AppDefined,
981 : "Raster Attribute Table not empty in "
982 : "InitializeFromColorTable()");
983 0 : return CE_Failure;
984 : }
985 :
986 0 : SetLinearBinning(0.0, 1.0);
987 0 : CreateColumn("Value", GFT_Integer, GFU_MinMax);
988 0 : CreateColumn("Red", GFT_Integer, GFU_Red);
989 0 : CreateColumn("Green", GFT_Integer, GFU_Green);
990 0 : CreateColumn("Blue", GFT_Integer, GFU_Blue);
991 0 : CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
992 :
993 0 : SetRowCount(poTable->GetColorEntryCount());
994 :
995 0 : for (int iRow = 0; iRow < poTable->GetColorEntryCount(); iRow++)
996 : {
997 : GDALColorEntry sEntry;
998 :
999 0 : poTable->GetColorEntryAsRGB(iRow, &sEntry);
1000 :
1001 0 : SetValue(iRow, 0, iRow);
1002 0 : SetValue(iRow, 1, sEntry.c1);
1003 0 : SetValue(iRow, 2, sEntry.c2);
1004 0 : SetValue(iRow, 3, sEntry.c3);
1005 0 : SetValue(iRow, 4, sEntry.c4);
1006 : }
1007 :
1008 0 : return CE_None;
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* GDALRATInitializeFromColorTable() */
1013 : /************************************************************************/
1014 :
1015 : /**
1016 : * \brief Initialize from color table.
1017 : *
1018 : * This function is the same as the C++ method
1019 : * GDALRasterAttributeTable::InitializeFromColorTable()
1020 : */
1021 0 : CPLErr CPL_STDCALL GDALRATInitializeFromColorTable(
1022 : GDALRasterAttributeTableH hRAT, GDALColorTableH hCT)
1023 :
1024 : {
1025 0 : VALIDATE_POINTER1(hRAT, "GDALRATInitializeFromColorTable", CE_Failure);
1026 :
1027 0 : return GDALRasterAttributeTable::FromHandle(hRAT)->InitializeFromColorTable(
1028 0 : GDALColorTable::FromHandle(hCT));
1029 : }
1030 :
1031 : /************************************************************************/
1032 : /* TranslateToColorTable() */
1033 : /************************************************************************/
1034 :
1035 : /**
1036 : * \brief Translate to a color table.
1037 : *
1038 : * This method will attempt to create a corresponding GDALColorTable from
1039 : * this raster attribute table.
1040 : *
1041 : * This method is the same as the C function GDALRATTranslateToColorTable().
1042 : *
1043 : * @param nEntryCount The number of entries to produce (0 to nEntryCount-1),
1044 : * or -1 to auto-determine the number of entries.
1045 : *
1046 : * @return the generated color table or NULL on failure.
1047 : */
1048 :
1049 0 : GDALColorTable *GDALRasterAttributeTable::TranslateToColorTable(int nEntryCount)
1050 :
1051 : {
1052 : /* -------------------------------------------------------------------- */
1053 : /* Establish which fields are red, green, blue and alpha. */
1054 : /* -------------------------------------------------------------------- */
1055 0 : const int iRed = GetColOfUsage(GFU_Red);
1056 0 : const int iGreen = GetColOfUsage(GFU_Green);
1057 0 : const int iBlue = GetColOfUsage(GFU_Blue);
1058 :
1059 0 : if (iRed == -1 || iGreen == -1 || iBlue == -1)
1060 0 : return nullptr;
1061 :
1062 0 : const int iAlpha = GetColOfUsage(GFU_Alpha);
1063 :
1064 : /* -------------------------------------------------------------------- */
1065 : /* If we aren't given an explicit number of values to scan for, */
1066 : /* search for the maximum "max" value. */
1067 : /* -------------------------------------------------------------------- */
1068 0 : if (nEntryCount == -1)
1069 : {
1070 0 : int iMaxCol = GetColOfUsage(GFU_Max);
1071 0 : if (iMaxCol == -1)
1072 0 : iMaxCol = GetColOfUsage(GFU_MinMax);
1073 :
1074 0 : if (iMaxCol == -1 || GetRowCount() == 0)
1075 0 : return nullptr;
1076 :
1077 0 : for (int iRow = 0; iRow < GetRowCount(); iRow++)
1078 : {
1079 0 : nEntryCount = std::max(
1080 0 : nEntryCount, std::min(65535, GetValueAsInt(iRow, iMaxCol)) + 1);
1081 : }
1082 :
1083 0 : if (nEntryCount < 0)
1084 0 : return nullptr;
1085 :
1086 : // Restrict our number of entries to something vaguely sensible.
1087 0 : nEntryCount = std::min(65535, nEntryCount);
1088 : }
1089 :
1090 : /* -------------------------------------------------------------------- */
1091 : /* Assign values to color table. */
1092 : /* -------------------------------------------------------------------- */
1093 0 : GDALColorTable *poCT = new GDALColorTable();
1094 :
1095 0 : for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
1096 : {
1097 0 : GDALColorEntry sColor = {0, 0, 0, 0};
1098 0 : const int iRow = GetRowOfValue(iEntry);
1099 :
1100 0 : if (iRow != -1)
1101 : {
1102 0 : sColor.c1 = static_cast<short>(GetValueAsInt(iRow, iRed));
1103 0 : sColor.c2 = static_cast<short>(GetValueAsInt(iRow, iGreen));
1104 0 : sColor.c3 = static_cast<short>(GetValueAsInt(iRow, iBlue));
1105 0 : if (iAlpha == -1)
1106 0 : sColor.c4 = 255;
1107 : else
1108 0 : sColor.c4 = static_cast<short>(GetValueAsInt(iRow, iAlpha));
1109 : }
1110 :
1111 0 : poCT->SetColorEntry(iEntry, &sColor);
1112 : }
1113 :
1114 0 : return poCT;
1115 : }
1116 :
1117 : /************************************************************************/
1118 : /* GDALRATInitializeFromColorTable() */
1119 : /************************************************************************/
1120 :
1121 : /**
1122 : * \brief Translate to a color table.
1123 : *
1124 : * This function is the same as the C++ method
1125 : * GDALRasterAttributeTable::TranslateToColorTable()
1126 : */
1127 : GDALColorTableH CPL_STDCALL
1128 0 : GDALRATTranslateToColorTable(GDALRasterAttributeTableH hRAT, int nEntryCount)
1129 :
1130 : {
1131 0 : VALIDATE_POINTER1(hRAT, "GDALRATTranslateToColorTable", nullptr);
1132 :
1133 0 : return GDALRasterAttributeTable::FromHandle(hRAT)->TranslateToColorTable(
1134 0 : nEntryCount);
1135 : }
1136 :
1137 : /************************************************************************/
1138 : /* DumpReadable() */
1139 : /************************************************************************/
1140 :
1141 : /**
1142 : * \brief Dump RAT in readable form.
1143 : *
1144 : * Currently the readable form is the XML encoding ... only barely
1145 : * readable.
1146 : *
1147 : * This method is the same as the C function GDALRATDumpReadable().
1148 : *
1149 : * @param fp file to dump to or NULL for stdout.
1150 : */
1151 :
1152 0 : void GDALRasterAttributeTable::DumpReadable(FILE *fp)
1153 :
1154 : {
1155 0 : CPLXMLNode *psTree = Serialize();
1156 0 : char *const pszXMLText = CPLSerializeXMLTree(psTree);
1157 :
1158 0 : CPLDestroyXMLNode(psTree);
1159 :
1160 0 : if (fp == nullptr)
1161 0 : fp = stdout;
1162 :
1163 0 : fprintf(fp, "%s\n", pszXMLText);
1164 :
1165 0 : CPLFree(pszXMLText);
1166 0 : }
1167 :
1168 : /************************************************************************/
1169 : /* GDALRATDumpReadable() */
1170 : /************************************************************************/
1171 :
1172 : /**
1173 : * \brief Dump RAT in readable form.
1174 : *
1175 : * This function is the same as the C++ method
1176 : * GDALRasterAttributeTable::DumpReadable()
1177 : */
1178 0 : void CPL_STDCALL GDALRATDumpReadable(GDALRasterAttributeTableH hRAT, FILE *fp)
1179 :
1180 : {
1181 0 : VALIDATE_POINTER0(hRAT, "GDALRATDumpReadable");
1182 :
1183 0 : GDALRasterAttributeTable::FromHandle(hRAT)->DumpReadable(fp);
1184 : }
1185 :
1186 : /* \class GDALDefaultRasterAttributeTable
1187 : *
1188 : * An implementation of GDALRasterAttributeTable that keeps
1189 : * all data in memory. This is the same as the implementation
1190 : * of GDALRasterAttributeTable in GDAL <= 1.10.
1191 : */
1192 :
1193 : /************************************************************************/
1194 : /* GDALDefaultRasterAttributeTable() */
1195 : /* */
1196 : /* Simple initialization constructor. */
1197 : /************************************************************************/
1198 :
1199 : //! Construct empty table.
1200 :
1201 : GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable() = default;
1202 :
1203 : /************************************************************************/
1204 : /* GDALCreateRasterAttributeTable() */
1205 : /************************************************************************/
1206 :
1207 : /**
1208 : * \brief Construct empty table.
1209 : *
1210 : * This function is the same as the C++ method
1211 : * GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable()
1212 : */
1213 12 : GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
1214 :
1215 : {
1216 12 : return new GDALDefaultRasterAttributeTable();
1217 : }
1218 :
1219 : /************************************************************************/
1220 : /* ~GDALDefaultRasterAttributeTable() */
1221 : /* */
1222 : /* All magic done by magic by the container destructors. */
1223 : /************************************************************************/
1224 :
1225 : GDALDefaultRasterAttributeTable::~GDALDefaultRasterAttributeTable() = default;
1226 :
1227 : /************************************************************************/
1228 : /* GDALDestroyRasterAttributeTable() */
1229 : /************************************************************************/
1230 :
1231 : /**
1232 : * \brief Destroys a RAT.
1233 : *
1234 : * This function is the same as the C++ method
1235 : * GDALRasterAttributeTable::~GDALRasterAttributeTable()
1236 : */
1237 19 : void CPL_STDCALL GDALDestroyRasterAttributeTable(GDALRasterAttributeTableH hRAT)
1238 :
1239 : {
1240 19 : if (hRAT != nullptr)
1241 19 : delete GDALRasterAttributeTable::FromHandle(hRAT);
1242 19 : }
1243 :
1244 : /************************************************************************/
1245 : /* AnalyseColumns() */
1246 : /* */
1247 : /* Internal method to work out which column to use for various */
1248 : /* tasks. */
1249 : /************************************************************************/
1250 :
1251 2 : void GDALDefaultRasterAttributeTable::AnalyseColumns()
1252 :
1253 : {
1254 2 : bColumnsAnalysed = true;
1255 :
1256 2 : nMinCol = GetColOfUsage(GFU_Min);
1257 2 : if (nMinCol == -1)
1258 2 : nMinCol = GetColOfUsage(GFU_MinMax);
1259 :
1260 2 : nMaxCol = GetColOfUsage(GFU_Max);
1261 2 : if (nMaxCol == -1)
1262 2 : nMaxCol = GetColOfUsage(GFU_MinMax);
1263 2 : }
1264 :
1265 : /************************************************************************/
1266 : /* GetColumnCount() */
1267 : /************************************************************************/
1268 :
1269 107 : int GDALDefaultRasterAttributeTable::GetColumnCount() const
1270 :
1271 : {
1272 107 : return static_cast<int>(aoFields.size());
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALRATGetColumnCount() */
1277 : /************************************************************************/
1278 :
1279 : /**
1280 : * \brief Fetch table column count.
1281 : *
1282 : * This function is the same as the C++ method
1283 : * GDALRasterAttributeTable::GetColumnCount()
1284 : */
1285 48 : int CPL_STDCALL GDALRATGetColumnCount(GDALRasterAttributeTableH hRAT)
1286 :
1287 : {
1288 48 : VALIDATE_POINTER1(hRAT, "GDALRATGetColumnCount", 0);
1289 :
1290 48 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetColumnCount();
1291 : }
1292 :
1293 : /************************************************************************/
1294 : /* GetNameOfCol() */
1295 : /************************************************************************/
1296 :
1297 : /** \brief Fetch name of indicated column.
1298 : * @param iCol column index.
1299 : * @return name.
1300 : */
1301 149 : const char *GDALDefaultRasterAttributeTable::GetNameOfCol(int iCol) const
1302 :
1303 : {
1304 149 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1305 0 : return "";
1306 :
1307 149 : return aoFields[iCol].sName;
1308 : }
1309 :
1310 : /************************************************************************/
1311 : /* GDALRATGetNameOfCol() */
1312 : /************************************************************************/
1313 :
1314 : /**
1315 : * \brief Fetch name of indicated column.
1316 : *
1317 : * This function is the same as the C++ method
1318 : * GDALRasterAttributeTable::GetNameOfCol()
1319 : * @param hRAT RAT handle.
1320 : * @param iCol column index.
1321 : * @return name.
1322 : */
1323 118 : const char *CPL_STDCALL GDALRATGetNameOfCol(GDALRasterAttributeTableH hRAT,
1324 : int iCol)
1325 :
1326 : {
1327 118 : VALIDATE_POINTER1(hRAT, "GDALRATGetNameOfCol", nullptr);
1328 :
1329 118 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetNameOfCol(iCol);
1330 : }
1331 :
1332 : /************************************************************************/
1333 : /* GetUsageOfCol() */
1334 : /************************************************************************/
1335 :
1336 : /**
1337 : * \brief Fetch column usage value.
1338 : *
1339 : * @param iCol column index.
1340 : * @return usage.
1341 : */
1342 92 : GDALRATFieldUsage GDALDefaultRasterAttributeTable::GetUsageOfCol(int iCol) const
1343 :
1344 : {
1345 92 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1346 0 : return GFU_Generic;
1347 :
1348 92 : return aoFields[iCol].eUsage;
1349 : }
1350 :
1351 : /************************************************************************/
1352 : /* GDALRATGetUsageOfCol() */
1353 : /************************************************************************/
1354 :
1355 : /**
1356 : * \brief Fetch column usage value.
1357 : *
1358 : * This function is the same as the C++ method
1359 : * GDALRasterAttributeTable::GetUsageOfCol()
1360 : * @param hRAT RAT handle.
1361 : * @param iCol column index.
1362 : * @return usage.
1363 : */
1364 : GDALRATFieldUsage CPL_STDCALL
1365 61 : GDALRATGetUsageOfCol(GDALRasterAttributeTableH hRAT, int iCol)
1366 :
1367 : {
1368 61 : VALIDATE_POINTER1(hRAT, "GDALRATGetUsageOfCol", GFU_Generic);
1369 :
1370 61 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetUsageOfCol(iCol);
1371 : }
1372 :
1373 : /************************************************************************/
1374 : /* GetTypeOfCol() */
1375 : /************************************************************************/
1376 :
1377 : /**
1378 : * \brief Fetch column type.
1379 : *
1380 : * @param iCol column index.
1381 : * @return type.
1382 : */
1383 2181 : GDALRATFieldType GDALDefaultRasterAttributeTable::GetTypeOfCol(int iCol) const
1384 :
1385 : {
1386 2181 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1387 2 : return GFT_Integer;
1388 :
1389 2179 : return aoFields[iCol].eType;
1390 : }
1391 :
1392 : /************************************************************************/
1393 : /* GDALRATGetTypeOfCol() */
1394 : /************************************************************************/
1395 :
1396 : /**
1397 : * \brief Fetch column type.
1398 : *
1399 : * This function is the same as the C++ method
1400 : * GDALRasterAttributeTable::GetTypeOfCol()
1401 : * @param hRAT RAT handle.
1402 : * @param iCol column index.
1403 : * @return type.
1404 : */
1405 306 : GDALRATFieldType CPL_STDCALL GDALRATGetTypeOfCol(GDALRasterAttributeTableH hRAT,
1406 : int iCol)
1407 :
1408 : {
1409 306 : VALIDATE_POINTER1(hRAT, "GDALRATGetTypeOfCol", GFT_Integer);
1410 :
1411 306 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetTypeOfCol(iCol);
1412 : }
1413 :
1414 : /************************************************************************/
1415 : /* GetColOfUsage() */
1416 : /************************************************************************/
1417 :
1418 : /** Return the index of the column that corresponds to the passed usage.
1419 : * @param eUsage usage.
1420 : * @return column index, or -1 in case of error.
1421 : */
1422 8 : int GDALDefaultRasterAttributeTable::GetColOfUsage(
1423 : GDALRATFieldUsage eUsage) const
1424 :
1425 : {
1426 16 : for (unsigned int i = 0; i < aoFields.size(); i++)
1427 : {
1428 12 : if (aoFields[i].eUsage == eUsage)
1429 4 : return i;
1430 : }
1431 :
1432 4 : return -1;
1433 : }
1434 :
1435 : /************************************************************************/
1436 : /* GDALRATGetColOfUsage() */
1437 : /************************************************************************/
1438 :
1439 : /**
1440 : * \brief Fetch column index for given usage.
1441 : *
1442 : * This function is the same as the C++ method
1443 : * GDALRasterAttributeTable::GetColOfUsage()
1444 : */
1445 13 : int CPL_STDCALL GDALRATGetColOfUsage(GDALRasterAttributeTableH hRAT,
1446 : GDALRATFieldUsage eUsage)
1447 :
1448 : {
1449 13 : VALIDATE_POINTER1(hRAT, "GDALRATGetColOfUsage", 0);
1450 :
1451 13 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetColOfUsage(eUsage);
1452 : }
1453 :
1454 : /************************************************************************/
1455 : /* GetRowCount() */
1456 : /************************************************************************/
1457 :
1458 314 : int GDALDefaultRasterAttributeTable::GetRowCount() const
1459 :
1460 : {
1461 314 : return static_cast<int>(nRowCount);
1462 : }
1463 :
1464 : /************************************************************************/
1465 : /* GDALRATGetUsageOfCol() */
1466 : /************************************************************************/
1467 : /**
1468 : * \brief Fetch row count.
1469 : *
1470 : * This function is the same as the C++ method
1471 : * GDALRasterAttributeTable::GetRowCount()
1472 : */
1473 235 : int CPL_STDCALL GDALRATGetRowCount(GDALRasterAttributeTableH hRAT)
1474 :
1475 : {
1476 235 : VALIDATE_POINTER1(hRAT, "GDALRATGetRowCount", 0);
1477 :
1478 235 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowCount();
1479 : }
1480 :
1481 : /************************************************************************/
1482 : /* GetValueAsString() */
1483 : /************************************************************************/
1484 :
1485 101 : const char *GDALDefaultRasterAttributeTable::GetValueAsString(int iRow,
1486 : int iField) const
1487 :
1488 : {
1489 101 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1490 : {
1491 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1492 : iField);
1493 :
1494 0 : return "";
1495 : }
1496 :
1497 101 : if (iRow < 0 || iRow >= nRowCount)
1498 : {
1499 2 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1500 :
1501 2 : return "";
1502 : }
1503 :
1504 99 : switch (aoFields[iField].eType)
1505 : {
1506 0 : case GFT_Integer:
1507 : {
1508 : const_cast<GDALDefaultRasterAttributeTable *>(this)
1509 0 : ->osWorkingResult.Printf("%d", aoFields[iField].anValues[iRow]);
1510 0 : return osWorkingResult;
1511 : }
1512 :
1513 0 : case GFT_Real:
1514 : {
1515 : const_cast<GDALDefaultRasterAttributeTable *>(this)
1516 : ->osWorkingResult.Printf("%.16g",
1517 0 : aoFields[iField].adfValues[iRow]);
1518 0 : return osWorkingResult;
1519 : }
1520 :
1521 99 : case GFT_String:
1522 : {
1523 99 : return aoFields[iField].aosValues[iRow];
1524 : }
1525 : }
1526 :
1527 0 : return "";
1528 : }
1529 :
1530 : /************************************************************************/
1531 : /* GDALRATGetValueAsString() */
1532 : /************************************************************************/
1533 : /**
1534 : * \brief Fetch field value as a string.
1535 : *
1536 : * This function is the same as the C++ method
1537 : * GDALRasterAttributeTable::GetValueAsString()
1538 : */
1539 90 : const char *CPL_STDCALL GDALRATGetValueAsString(GDALRasterAttributeTableH hRAT,
1540 : int iRow, int iField)
1541 :
1542 : {
1543 90 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsString", nullptr);
1544 :
1545 180 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsString(iRow,
1546 90 : iField);
1547 : }
1548 :
1549 : /************************************************************************/
1550 : /* GetValueAsInt() */
1551 : /************************************************************************/
1552 :
1553 330 : int GDALDefaultRasterAttributeTable::GetValueAsInt(int iRow, int iField) const
1554 :
1555 : {
1556 330 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1557 : {
1558 20 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1559 : iField);
1560 :
1561 20 : return 0;
1562 : }
1563 :
1564 310 : if (iRow < 0 || iRow >= nRowCount)
1565 : {
1566 2 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1567 :
1568 2 : return 0;
1569 : }
1570 :
1571 308 : switch (aoFields[iField].eType)
1572 : {
1573 308 : case GFT_Integer:
1574 308 : return aoFields[iField].anValues[iRow];
1575 :
1576 0 : case GFT_Real:
1577 0 : return static_cast<int>(aoFields[iField].adfValues[iRow]);
1578 :
1579 0 : case GFT_String:
1580 0 : return atoi(aoFields[iField].aosValues[iRow].c_str());
1581 : }
1582 :
1583 0 : return 0;
1584 : }
1585 :
1586 : /************************************************************************/
1587 : /* GDALRATGetValueAsInt() */
1588 : /************************************************************************/
1589 :
1590 : /**
1591 : * \brief Fetch field value as a integer.
1592 : *
1593 : * This function is the same as the C++ method
1594 : * GDALRasterAttributeTable::GetValueAsInt()
1595 : */
1596 166 : int CPL_STDCALL GDALRATGetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
1597 : int iField)
1598 :
1599 : {
1600 166 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsInt", 0);
1601 :
1602 332 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsInt(iRow,
1603 166 : iField);
1604 : }
1605 :
1606 : /************************************************************************/
1607 : /* GetValueAsDouble() */
1608 : /************************************************************************/
1609 :
1610 1116 : double GDALDefaultRasterAttributeTable::GetValueAsDouble(int iRow,
1611 : int iField) const
1612 :
1613 : {
1614 1116 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1615 : {
1616 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1617 : iField);
1618 :
1619 0 : return 0;
1620 : }
1621 :
1622 1116 : if (iRow < 0 || iRow >= nRowCount)
1623 : {
1624 2 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1625 :
1626 2 : return 0;
1627 : }
1628 :
1629 1114 : switch (aoFields[iField].eType)
1630 : {
1631 0 : case GFT_Integer:
1632 0 : return aoFields[iField].anValues[iRow];
1633 :
1634 1114 : case GFT_Real:
1635 1114 : return aoFields[iField].adfValues[iRow];
1636 :
1637 0 : case GFT_String:
1638 0 : return CPLAtof(aoFields[iField].aosValues[iRow].c_str());
1639 : }
1640 :
1641 0 : return 0;
1642 : }
1643 :
1644 : /************************************************************************/
1645 : /* GDALRATGetValueAsDouble() */
1646 : /************************************************************************/
1647 :
1648 : /**
1649 : * \brief Fetch field value as a double.
1650 : *
1651 : * This function is the same as the C++ method
1652 : * GDALRasterAttributeTable::GetValueAsDouble()
1653 : */
1654 92 : double CPL_STDCALL GDALRATGetValueAsDouble(GDALRasterAttributeTableH hRAT,
1655 : int iRow, int iField)
1656 :
1657 : {
1658 92 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsDouble", 0);
1659 :
1660 184 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDouble(iRow,
1661 92 : iField);
1662 : }
1663 :
1664 : /************************************************************************/
1665 : /* SetRowCount() */
1666 : /************************************************************************/
1667 :
1668 : /** Set row count.
1669 : * @param nNewCount new count.
1670 : */
1671 1728 : void GDALDefaultRasterAttributeTable::SetRowCount(int nNewCount)
1672 :
1673 : {
1674 1728 : if (nNewCount == nRowCount)
1675 20 : return;
1676 :
1677 4650 : for (auto &oField : aoFields)
1678 : {
1679 2942 : switch (oField.eType)
1680 : {
1681 813 : case GFT_Integer:
1682 813 : oField.anValues.resize(nNewCount);
1683 813 : break;
1684 :
1685 1495 : case GFT_Real:
1686 1495 : oField.adfValues.resize(nNewCount);
1687 1495 : break;
1688 :
1689 634 : case GFT_String:
1690 634 : oField.aosValues.resize(nNewCount);
1691 634 : break;
1692 : }
1693 : }
1694 :
1695 1708 : nRowCount = nNewCount;
1696 : }
1697 :
1698 : /************************************************************************/
1699 : /* SetValue() */
1700 : /************************************************************************/
1701 :
1702 : /** Set value
1703 : * @param iRow row index.
1704 : * @param iField field index.
1705 : * @param pszValue value.
1706 : */
1707 2750 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1708 : const char *pszValue)
1709 :
1710 : {
1711 2750 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1712 : {
1713 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1714 : iField);
1715 :
1716 0 : return CE_Failure;
1717 : }
1718 :
1719 2750 : if (iRow == nRowCount)
1720 1381 : SetRowCount(nRowCount + 1);
1721 :
1722 2750 : if (iRow < 0 || iRow >= nRowCount)
1723 : {
1724 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1725 :
1726 0 : return CE_Failure;
1727 : }
1728 :
1729 2750 : switch (aoFields[iField].eType)
1730 : {
1731 129 : case GFT_Integer:
1732 129 : aoFields[iField].anValues[iRow] = atoi(pszValue);
1733 129 : break;
1734 :
1735 1400 : case GFT_Real:
1736 1400 : aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
1737 1400 : break;
1738 :
1739 1221 : case GFT_String:
1740 1221 : aoFields[iField].aosValues[iRow] = pszValue;
1741 1221 : break;
1742 : }
1743 :
1744 2750 : return CE_None;
1745 : }
1746 :
1747 : /************************************************************************/
1748 : /* GDALRATSetValueAsString() */
1749 : /************************************************************************/
1750 :
1751 : /**
1752 : * \brief Set field value from string.
1753 : *
1754 : * This function is the same as the C++ method
1755 : * GDALRasterAttributeTable::SetValue()
1756 : * @param hRAT RAT handle.
1757 : * @param iRow row index.
1758 : * @param iField field index.
1759 : * @param pszValue value.
1760 : */
1761 37 : void CPL_STDCALL GDALRATSetValueAsString(GDALRasterAttributeTableH hRAT,
1762 : int iRow, int iField,
1763 : const char *pszValue)
1764 :
1765 : {
1766 37 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsString");
1767 :
1768 37 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
1769 37 : pszValue);
1770 : }
1771 :
1772 : /************************************************************************/
1773 : /* SetValue() */
1774 : /************************************************************************/
1775 :
1776 1221 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1777 : int nValue)
1778 :
1779 : {
1780 1221 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1781 : {
1782 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1783 : iField);
1784 :
1785 0 : return CE_Failure;
1786 : }
1787 :
1788 1221 : if (iRow == nRowCount)
1789 298 : SetRowCount(nRowCount + 1);
1790 :
1791 1221 : if (iRow < 0 || iRow >= nRowCount)
1792 : {
1793 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1794 :
1795 0 : return CE_Failure;
1796 : }
1797 :
1798 1221 : switch (aoFields[iField].eType)
1799 : {
1800 1209 : case GFT_Integer:
1801 1209 : aoFields[iField].anValues[iRow] = nValue;
1802 1209 : break;
1803 :
1804 12 : case GFT_Real:
1805 12 : aoFields[iField].adfValues[iRow] = nValue;
1806 12 : break;
1807 :
1808 0 : case GFT_String:
1809 : {
1810 : char szValue[100];
1811 :
1812 0 : snprintf(szValue, sizeof(szValue), "%d", nValue);
1813 0 : aoFields[iField].aosValues[iRow] = szValue;
1814 : }
1815 0 : break;
1816 : }
1817 :
1818 1221 : return CE_None;
1819 : }
1820 :
1821 : /************************************************************************/
1822 : /* GDALRATSetValueAsInt() */
1823 : /************************************************************************/
1824 :
1825 : /**
1826 : * \brief Set field value from integer.
1827 : *
1828 : * This function is the same as the C++ method
1829 : * GDALRasterAttributeTable::SetValue()
1830 : */
1831 49 : void CPL_STDCALL GDALRATSetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
1832 : int iField, int nValue)
1833 :
1834 : {
1835 49 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsInt");
1836 :
1837 49 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, nValue);
1838 : }
1839 :
1840 : /************************************************************************/
1841 : /* SetValue() */
1842 : /************************************************************************/
1843 :
1844 6256 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1845 : double dfValue)
1846 :
1847 : {
1848 6256 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1849 : {
1850 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1851 : iField);
1852 :
1853 0 : return CE_Failure;
1854 : }
1855 :
1856 6256 : if (iRow == nRowCount)
1857 0 : SetRowCount(nRowCount + 1);
1858 :
1859 6256 : if (iRow < 0 || iRow >= nRowCount)
1860 : {
1861 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1862 :
1863 0 : return CE_Failure;
1864 : }
1865 :
1866 6256 : switch (aoFields[iField].eType)
1867 : {
1868 1608 : case GFT_Integer:
1869 1608 : aoFields[iField].anValues[iRow] = static_cast<int>(dfValue);
1870 1608 : break;
1871 :
1872 4648 : case GFT_Real:
1873 4648 : aoFields[iField].adfValues[iRow] = dfValue;
1874 4648 : break;
1875 :
1876 0 : case GFT_String:
1877 : {
1878 0 : char szValue[100] = {'\0'};
1879 :
1880 0 : CPLsnprintf(szValue, sizeof(szValue), "%.15g", dfValue);
1881 0 : aoFields[iField].aosValues[iRow] = szValue;
1882 : }
1883 0 : break;
1884 : }
1885 :
1886 6256 : return CE_None;
1887 : }
1888 :
1889 : /************************************************************************/
1890 : /* GDALRATSetValueAsDouble() */
1891 : /************************************************************************/
1892 :
1893 : /**
1894 : * \brief Set field value from double.
1895 : *
1896 : * This function is the same as the C++ method
1897 : * GDALRasterAttributeTable::SetValue()
1898 : */
1899 35 : void CPL_STDCALL GDALRATSetValueAsDouble(GDALRasterAttributeTableH hRAT,
1900 : int iRow, int iField, double dfValue)
1901 :
1902 : {
1903 35 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsDouble");
1904 :
1905 35 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, dfValue);
1906 : }
1907 :
1908 : /************************************************************************/
1909 : /* ChangesAreWrittenToFile() */
1910 : /************************************************************************/
1911 :
1912 0 : int GDALDefaultRasterAttributeTable::ChangesAreWrittenToFile()
1913 : {
1914 : // GDALRasterBand.SetDefaultRAT needs to be called on instances of
1915 : // GDALDefaultRasterAttributeTable since changes are just in-memory
1916 0 : return false;
1917 : }
1918 :
1919 : /************************************************************************/
1920 : /* GDALRATChangesAreWrittenToFile() */
1921 : /************************************************************************/
1922 :
1923 : /**
1924 : * \brief Determine whether changes made to this RAT are reflected directly in
1925 : * the dataset
1926 : *
1927 : * This function is the same as the C++ method
1928 : * GDALRasterAttributeTable::ChangesAreWrittenToFile()
1929 : */
1930 2 : int CPL_STDCALL GDALRATChangesAreWrittenToFile(GDALRasterAttributeTableH hRAT)
1931 : {
1932 2 : VALIDATE_POINTER1(hRAT, "GDALRATChangesAreWrittenToFile", false);
1933 :
1934 2 : return GDALRasterAttributeTable::FromHandle(hRAT)
1935 2 : ->ChangesAreWrittenToFile();
1936 : }
1937 :
1938 : /************************************************************************/
1939 : /* GetRowOfValue() */
1940 : /************************************************************************/
1941 :
1942 2 : int GDALDefaultRasterAttributeTable::GetRowOfValue(double dfValue) const
1943 :
1944 : {
1945 : /* -------------------------------------------------------------------- */
1946 : /* Handle case of regular binning. */
1947 : /* -------------------------------------------------------------------- */
1948 2 : if (bLinearBinning)
1949 : {
1950 0 : const int iBin =
1951 0 : static_cast<int>(floor((dfValue - dfRow0Min) / dfBinSize));
1952 0 : if (iBin < 0 || iBin >= nRowCount)
1953 0 : return -1;
1954 :
1955 0 : return iBin;
1956 : }
1957 :
1958 : /* -------------------------------------------------------------------- */
1959 : /* Do we have any information? */
1960 : /* -------------------------------------------------------------------- */
1961 2 : if (!bColumnsAnalysed)
1962 2 : const_cast<GDALDefaultRasterAttributeTable *>(this)->AnalyseColumns();
1963 :
1964 2 : if (nMinCol == -1 && nMaxCol == -1)
1965 0 : return -1;
1966 :
1967 2 : const GDALRasterAttributeField *poMin = nullptr;
1968 2 : if (nMinCol != -1)
1969 2 : poMin = &(aoFields[nMinCol]);
1970 : else
1971 0 : poMin = nullptr;
1972 :
1973 2 : const GDALRasterAttributeField *poMax = nullptr;
1974 2 : if (nMaxCol != -1)
1975 2 : poMax = &(aoFields[nMaxCol]);
1976 : else
1977 0 : poMax = nullptr;
1978 :
1979 : /* -------------------------------------------------------------------- */
1980 : /* Search through rows for match. */
1981 : /* -------------------------------------------------------------------- */
1982 4 : for (int iRow = 0; iRow < nRowCount; iRow++)
1983 : {
1984 4 : if (poMin != nullptr)
1985 : {
1986 4 : if (poMin->eType == GFT_Integer)
1987 : {
1988 4 : while (iRow < nRowCount && dfValue < poMin->anValues[iRow])
1989 0 : iRow++;
1990 : }
1991 0 : else if (poMin->eType == GFT_Real)
1992 : {
1993 0 : while (iRow < nRowCount && dfValue < poMin->adfValues[iRow])
1994 0 : iRow++;
1995 : }
1996 :
1997 4 : if (iRow == nRowCount)
1998 0 : break;
1999 : }
2000 :
2001 4 : if (poMax != nullptr)
2002 : {
2003 14 : if ((poMax->eType == GFT_Integer &&
2004 6 : dfValue > poMax->anValues[iRow]) ||
2005 2 : (poMax->eType == GFT_Real && dfValue > poMax->adfValues[iRow]))
2006 2 : continue;
2007 : }
2008 :
2009 2 : return iRow;
2010 : }
2011 :
2012 0 : return -1;
2013 : }
2014 :
2015 : /************************************************************************/
2016 : /* GetRowOfValue() */
2017 : /* */
2018 : /* Int arg for now just converted to double. Perhaps we will */
2019 : /* handle this in a special way some day? */
2020 : /************************************************************************/
2021 :
2022 0 : int GDALDefaultRasterAttributeTable::GetRowOfValue(int nValue) const
2023 :
2024 : {
2025 0 : return GetRowOfValue(static_cast<double>(nValue));
2026 : }
2027 :
2028 : /************************************************************************/
2029 : /* SetLinearBinning() */
2030 : /************************************************************************/
2031 :
2032 16 : CPLErr GDALDefaultRasterAttributeTable::SetLinearBinning(double dfRow0MinIn,
2033 : double dfBinSizeIn)
2034 :
2035 : {
2036 16 : bLinearBinning = true;
2037 16 : dfRow0Min = dfRow0MinIn;
2038 16 : dfBinSize = dfBinSizeIn;
2039 :
2040 16 : return CE_None;
2041 : }
2042 :
2043 : /************************************************************************/
2044 : /* GetLinearBinning() */
2045 : /************************************************************************/
2046 :
2047 13 : int GDALDefaultRasterAttributeTable::GetLinearBinning(double *pdfRow0Min,
2048 : double *pdfBinSize) const
2049 :
2050 : {
2051 13 : if (!bLinearBinning)
2052 9 : return false;
2053 :
2054 4 : *pdfRow0Min = dfRow0Min;
2055 4 : *pdfBinSize = dfBinSize;
2056 :
2057 4 : return true;
2058 : }
2059 :
2060 : /************************************************************************/
2061 : /* GetTableType() */
2062 : /************************************************************************/
2063 :
2064 : /**
2065 : * \brief Get RAT Table Type
2066 : *
2067 : * Returns whether table type is thematic or athematic
2068 : *
2069 : * This method is the same as the C function GDALRATGetTableType().
2070 : *
2071 : * @since GDAL 2.4
2072 : *
2073 : * @return GRTT_THEMATIC or GRTT_ATHEMATIC
2074 : */
2075 :
2076 15 : GDALRATTableType GDALDefaultRasterAttributeTable::GetTableType() const
2077 : {
2078 15 : return eTableType;
2079 : }
2080 :
2081 : /************************************************************************/
2082 : /* SetTableType() */
2083 : /************************************************************************/
2084 :
2085 : /**
2086 : * \brief Set RAT Table Type
2087 : *
2088 : * Set whether table type is thematic or athematic
2089 : *
2090 : * This method is the same as the C function GDALRATSetTableType().
2091 : *
2092 : * @param eInTableType the new RAT table type (GRTT_THEMATIC or GRTT_ATHEMATIC)
2093 : *
2094 : * @since GDAL 2.4
2095 : *
2096 : * @return CE_None on success or CE_Failure on failure.
2097 : */
2098 :
2099 40 : CPLErr GDALDefaultRasterAttributeTable::SetTableType(
2100 : const GDALRATTableType eInTableType)
2101 : {
2102 40 : eTableType = eInTableType;
2103 40 : return CE_None;
2104 : }
2105 :
2106 : /************************************************************************/
2107 : /* CreateColumn() */
2108 : /************************************************************************/
2109 :
2110 : CPLErr
2111 384 : GDALDefaultRasterAttributeTable::CreateColumn(const char *pszFieldName,
2112 : GDALRATFieldType eFieldType,
2113 : GDALRATFieldUsage eFieldUsage)
2114 :
2115 : {
2116 384 : const size_t iNewField = aoFields.size();
2117 :
2118 384 : aoFields.resize(iNewField + 1);
2119 :
2120 384 : aoFields[iNewField].sName = pszFieldName;
2121 :
2122 : // color columns should be int 0..255
2123 384 : if ((eFieldUsage == GFU_Red) || (eFieldUsage == GFU_Green) ||
2124 324 : (eFieldUsage == GFU_Blue) || (eFieldUsage == GFU_Alpha))
2125 : {
2126 65 : eFieldType = GFT_Integer;
2127 : }
2128 384 : aoFields[iNewField].eType = eFieldType;
2129 384 : aoFields[iNewField].eUsage = eFieldUsage;
2130 :
2131 384 : if (eFieldType == GFT_Integer)
2132 199 : aoFields[iNewField].anValues.resize(nRowCount);
2133 185 : else if (eFieldType == GFT_Real)
2134 61 : aoFields[iNewField].adfValues.resize(nRowCount);
2135 124 : else if (eFieldType == GFT_String)
2136 124 : aoFields[iNewField].aosValues.resize(nRowCount);
2137 :
2138 384 : return CE_None;
2139 : }
2140 :
2141 : /************************************************************************/
2142 : /* RemoveStatistics() */
2143 : /************************************************************************/
2144 :
2145 : /**
2146 : * \brief Remove Statistics from RAT
2147 : *
2148 : * Remove statistics (such as histogram) from the RAT. This is important
2149 : * if these have been invalidated, for example by cropping the image.
2150 : *
2151 : * This method is the same as the C function GDALRATRemoveStatistics().
2152 : *
2153 : * @since GDAL 2.4
2154 : */
2155 :
2156 2 : void GDALDefaultRasterAttributeTable::RemoveStatistics()
2157 :
2158 : {
2159 : // since we are storing the fields in a vector it will generally
2160 : // be faster to create a new vector and replace the old one
2161 : // rather than actually erasing columns.
2162 4 : std::vector<GDALRasterAttributeField> aoNewFields;
2163 4 : for (const auto &field : aoFields)
2164 : {
2165 2 : switch (field.eUsage)
2166 : {
2167 1 : case GFU_PixelCount:
2168 : case GFU_Min:
2169 : case GFU_Max:
2170 : case GFU_RedMin:
2171 : case GFU_GreenMin:
2172 : case GFU_BlueMin:
2173 : case GFU_AlphaMin:
2174 : case GFU_RedMax:
2175 : case GFU_GreenMax:
2176 : case GFU_BlueMax:
2177 : case GFU_AlphaMax:
2178 : {
2179 1 : break;
2180 : }
2181 :
2182 1 : default:
2183 1 : if (field.sName != "Histogram")
2184 : {
2185 1 : aoNewFields.push_back(field);
2186 : }
2187 : }
2188 : }
2189 2 : aoFields = std::move(aoNewFields);
2190 2 : }
2191 :
2192 : /************************************************************************/
2193 : /* Clone() */
2194 : /************************************************************************/
2195 :
2196 18 : GDALDefaultRasterAttributeTable *GDALDefaultRasterAttributeTable::Clone() const
2197 :
2198 : {
2199 18 : return new GDALDefaultRasterAttributeTable(*this);
2200 : }
2201 :
2202 : /************************************************************************/
2203 : /* GDALRATClone() */
2204 : /************************************************************************/
2205 :
2206 : /**
2207 : * \brief Copy Raster Attribute Table
2208 : *
2209 : * This function is the same as the C++ method GDALRasterAttributeTable::Clone()
2210 : */
2211 : GDALRasterAttributeTableH CPL_STDCALL
2212 5 : GDALRATClone(const GDALRasterAttributeTableH hRAT)
2213 :
2214 : {
2215 5 : VALIDATE_POINTER1(hRAT, "GDALRATClone", nullptr);
2216 :
2217 5 : return GDALRasterAttributeTable::FromHandle(hRAT)->Clone();
2218 : }
2219 :
2220 : /************************************************************************/
2221 : /* GDALRATSerializeJSON() */
2222 : /************************************************************************/
2223 :
2224 : /**
2225 : * \brief Serialize Raster Attribute Table in Json format
2226 : *
2227 : * This function is the same as the C++ method
2228 : * GDALRasterAttributeTable::SerializeJSON()
2229 : */
2230 4 : void *CPL_STDCALL GDALRATSerializeJSON(GDALRasterAttributeTableH hRAT)
2231 :
2232 : {
2233 4 : VALIDATE_POINTER1(hRAT, "GDALRATSerializeJSON", nullptr);
2234 :
2235 4 : return GDALRasterAttributeTable::FromHandle(hRAT)->SerializeJSON();
2236 : }
2237 :
2238 : /************************************************************************/
2239 : /* GDALRATRemoveStatistics() */
2240 : /************************************************************************/
2241 :
2242 : /**
2243 : * \brief Remove Statistics from RAT
2244 : *
2245 : * This function is the same as the C++ method
2246 : * GDALRasterAttributeTable::RemoveStatistics()
2247 : *
2248 : * @since GDAL 2.4
2249 : */
2250 1 : void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
2251 :
2252 : {
2253 1 : VALIDATE_POINTER0(hRAT, "GDALRATRemoveStatistics");
2254 :
2255 1 : GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
2256 : }
|