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