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