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 4 : void *GDALRasterAttributeTable::SerializeJSON() const
758 :
759 : {
760 4 : json_object *poRAT = json_object_new_object();
761 :
762 4 : if ((GetColumnCount() == 0) && (GetRowCount() == 0))
763 0 : return poRAT;
764 :
765 : /* -------------------------------------------------------------------- */
766 : /* Add attributes with regular binning info if appropriate. */
767 : /* -------------------------------------------------------------------- */
768 4 : double dfRow0Min = 0.0;
769 4 : double dfBinSize = 0.0;
770 4 : json_object *poRow0Min = nullptr;
771 4 : json_object *poBinSize = nullptr;
772 4 : json_object *poTableType = nullptr;
773 :
774 4 : if (GetLinearBinning(&dfRow0Min, &dfBinSize))
775 : {
776 2 : poRow0Min = json_object_new_double_with_precision(dfRow0Min, 16);
777 2 : json_object_object_add(poRAT, "row0Min", poRow0Min);
778 :
779 2 : poBinSize = json_object_new_double_with_precision(dfBinSize, 16);
780 2 : json_object_object_add(poRAT, "binSize", poBinSize);
781 : }
782 :
783 : /* -------------------------------------------------------------------- */
784 : /* Table Type */
785 : /* -------------------------------------------------------------------- */
786 4 : const GDALRATTableType tableType = GetTableType();
787 4 : if (tableType == GRTT_ATHEMATIC)
788 : {
789 1 : poTableType = json_object_new_string("athematic");
790 : }
791 : else
792 : {
793 3 : poTableType = json_object_new_string("thematic");
794 : }
795 4 : json_object_object_add(poRAT, "tableType", poTableType);
796 :
797 : /* -------------------------------------------------------------------- */
798 : /* Define each column. */
799 : /* -------------------------------------------------------------------- */
800 4 : const int iColCount = GetColumnCount();
801 4 : json_object *poFieldDefnArray = json_object_new_array();
802 :
803 29 : for (int iCol = 0; iCol < iColCount; iCol++)
804 : {
805 25 : json_object *const poFieldDefn = json_object_new_object();
806 :
807 25 : json_object *const poColumnIndex = json_object_new_int(iCol);
808 25 : json_object_object_add(poFieldDefn, "index", poColumnIndex);
809 :
810 25 : json_object *const poName = json_object_new_string(GetNameOfCol(iCol));
811 25 : json_object_object_add(poFieldDefn, "name", poName);
812 :
813 : json_object *const poType =
814 25 : json_object_new_int(static_cast<int>(GetTypeOfCol(iCol)));
815 25 : json_object_object_add(poFieldDefn, "type", poType);
816 :
817 : json_object *const poUsage =
818 25 : json_object_new_int(static_cast<int>(GetUsageOfCol(iCol)));
819 25 : json_object_object_add(poFieldDefn, "usage", poUsage);
820 :
821 25 : json_object_array_add(poFieldDefnArray, poFieldDefn);
822 : }
823 :
824 4 : json_object_object_add(poRAT, "fieldDefn", poFieldDefnArray);
825 :
826 : /* -------------------------------------------------------------------- */
827 : /* Write out each row. */
828 : /* -------------------------------------------------------------------- */
829 4 : const int iRowCount = GetRowCount();
830 4 : json_object *poRowArray = json_object_new_array();
831 :
832 928 : for (int iRow = 0; iRow < iRowCount; iRow++)
833 : {
834 924 : json_object *const poRow = json_object_new_object();
835 :
836 924 : json_object *const poRowIndex = json_object_new_int(iRow);
837 924 : json_object_object_add(poRow, "index", poRowIndex);
838 :
839 924 : json_object *const poFArray = json_object_new_array();
840 :
841 3993 : for (int iCol = 0; iCol < iColCount; iCol++)
842 : {
843 3069 : json_object *poF = nullptr;
844 3069 : if (GetTypeOfCol(iCol) == GFT_Integer)
845 2840 : 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 3069 : json_object_array_add(poFArray, poF);
853 : }
854 924 : json_object_object_add(poRow, "f", poFArray);
855 924 : json_object_array_add(poRowArray, poRow);
856 : }
857 4 : json_object_object_add(poRAT, "row", poRowArray);
858 :
859 4 : 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 : GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable() = default;
1201 :
1202 : /************************************************************************/
1203 : /* GDALCreateRasterAttributeTable() */
1204 : /************************************************************************/
1205 :
1206 : /**
1207 : * \brief Construct empty table.
1208 : *
1209 : * This function is the same as the C++ method
1210 : * GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable()
1211 : */
1212 10 : GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
1213 :
1214 : {
1215 10 : return new GDALDefaultRasterAttributeTable();
1216 : }
1217 :
1218 : /************************************************************************/
1219 : /* ~GDALDefaultRasterAttributeTable() */
1220 : /* */
1221 : /* All magic done by magic by the container destructors. */
1222 : /************************************************************************/
1223 :
1224 : GDALDefaultRasterAttributeTable::~GDALDefaultRasterAttributeTable() = default;
1225 :
1226 : /************************************************************************/
1227 : /* GDALDestroyRasterAttributeTable() */
1228 : /************************************************************************/
1229 :
1230 : /**
1231 : * \brief Destroys a RAT.
1232 : *
1233 : * This function is the same as the C++ method
1234 : * GDALRasterAttributeTable::~GDALRasterAttributeTable()
1235 : */
1236 17 : void CPL_STDCALL GDALDestroyRasterAttributeTable(GDALRasterAttributeTableH hRAT)
1237 :
1238 : {
1239 17 : if (hRAT != nullptr)
1240 17 : delete GDALRasterAttributeTable::FromHandle(hRAT);
1241 17 : }
1242 :
1243 : /************************************************************************/
1244 : /* AnalyseColumns() */
1245 : /* */
1246 : /* Internal method to work out which column to use for various */
1247 : /* tasks. */
1248 : /************************************************************************/
1249 :
1250 2 : void GDALDefaultRasterAttributeTable::AnalyseColumns()
1251 :
1252 : {
1253 2 : bColumnsAnalysed = true;
1254 :
1255 2 : nMinCol = GetColOfUsage(GFU_Min);
1256 2 : if (nMinCol == -1)
1257 2 : nMinCol = GetColOfUsage(GFU_MinMax);
1258 :
1259 2 : nMaxCol = GetColOfUsage(GFU_Max);
1260 2 : if (nMaxCol == -1)
1261 2 : nMaxCol = GetColOfUsage(GFU_MinMax);
1262 2 : }
1263 :
1264 : /************************************************************************/
1265 : /* GetColumnCount() */
1266 : /************************************************************************/
1267 :
1268 97 : int GDALDefaultRasterAttributeTable::GetColumnCount() const
1269 :
1270 : {
1271 97 : return static_cast<int>(aoFields.size());
1272 : }
1273 :
1274 : /************************************************************************/
1275 : /* GDALRATGetColumnCount() */
1276 : /************************************************************************/
1277 :
1278 : /**
1279 : * \brief Fetch table column count.
1280 : *
1281 : * This function is the same as the C++ method
1282 : * GDALRasterAttributeTable::GetColumnCount()
1283 : */
1284 37 : int CPL_STDCALL GDALRATGetColumnCount(GDALRasterAttributeTableH hRAT)
1285 :
1286 : {
1287 37 : VALIDATE_POINTER1(hRAT, "GDALRATGetColumnCount", 0);
1288 :
1289 37 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetColumnCount();
1290 : }
1291 :
1292 : /************************************************************************/
1293 : /* GetNameOfCol() */
1294 : /************************************************************************/
1295 :
1296 : /** \brief Fetch name of indicated column.
1297 : * @param iCol column index.
1298 : * @return name.
1299 : */
1300 91 : const char *GDALDefaultRasterAttributeTable::GetNameOfCol(int iCol) const
1301 :
1302 : {
1303 91 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1304 0 : return "";
1305 :
1306 91 : return aoFields[iCol].sName;
1307 : }
1308 :
1309 : /************************************************************************/
1310 : /* GDALRATGetNameOfCol() */
1311 : /************************************************************************/
1312 :
1313 : /**
1314 : * \brief Fetch name of indicated column.
1315 : *
1316 : * This function is the same as the C++ method
1317 : * GDALRasterAttributeTable::GetNameOfCol()
1318 : * @param hRAT RAT handle.
1319 : * @param iCol column index.
1320 : * @return name.
1321 : */
1322 60 : const char *CPL_STDCALL GDALRATGetNameOfCol(GDALRasterAttributeTableH hRAT,
1323 : int iCol)
1324 :
1325 : {
1326 60 : VALIDATE_POINTER1(hRAT, "GDALRATGetNameOfCol", nullptr);
1327 :
1328 60 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetNameOfCol(iCol);
1329 : }
1330 :
1331 : /************************************************************************/
1332 : /* GetUsageOfCol() */
1333 : /************************************************************************/
1334 :
1335 : /**
1336 : * \brief Fetch column usage value.
1337 : *
1338 : * @param iCol column index.
1339 : * @return usage.
1340 : */
1341 92 : GDALRATFieldUsage GDALDefaultRasterAttributeTable::GetUsageOfCol(int iCol) const
1342 :
1343 : {
1344 92 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1345 0 : return GFU_Generic;
1346 :
1347 92 : return aoFields[iCol].eUsage;
1348 : }
1349 :
1350 : /************************************************************************/
1351 : /* GDALRATGetUsageOfCol() */
1352 : /************************************************************************/
1353 :
1354 : /**
1355 : * \brief Fetch column usage value.
1356 : *
1357 : * This function is the same as the C++ method
1358 : * GDALRasterAttributeTable::GetUsageOfCol()
1359 : * @param hRAT RAT handle.
1360 : * @param iCol column index.
1361 : * @return usage.
1362 : */
1363 : GDALRATFieldUsage CPL_STDCALL
1364 61 : GDALRATGetUsageOfCol(GDALRasterAttributeTableH hRAT, int iCol)
1365 :
1366 : {
1367 61 : VALIDATE_POINTER1(hRAT, "GDALRATGetUsageOfCol", GFU_Generic);
1368 :
1369 61 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetUsageOfCol(iCol);
1370 : }
1371 :
1372 : /************************************************************************/
1373 : /* GetTypeOfCol() */
1374 : /************************************************************************/
1375 :
1376 : /**
1377 : * \brief Fetch column type.
1378 : *
1379 : * @param iCol column index.
1380 : * @return type.
1381 : */
1382 1981 : GDALRATFieldType GDALDefaultRasterAttributeTable::GetTypeOfCol(int iCol) const
1383 :
1384 : {
1385 1981 : if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1386 0 : return GFT_Integer;
1387 :
1388 1981 : return aoFields[iCol].eType;
1389 : }
1390 :
1391 : /************************************************************************/
1392 : /* GDALRATGetTypeOfCol() */
1393 : /************************************************************************/
1394 :
1395 : /**
1396 : * \brief Fetch column type.
1397 : *
1398 : * This function is the same as the C++ method
1399 : * GDALRasterAttributeTable::GetTypeOfCol()
1400 : * @param hRAT RAT handle.
1401 : * @param iCol column index.
1402 : * @return type.
1403 : */
1404 106 : GDALRATFieldType CPL_STDCALL GDALRATGetTypeOfCol(GDALRasterAttributeTableH hRAT,
1405 : int iCol)
1406 :
1407 : {
1408 106 : VALIDATE_POINTER1(hRAT, "GDALRATGetTypeOfCol", GFT_Integer);
1409 :
1410 106 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetTypeOfCol(iCol);
1411 : }
1412 :
1413 : /************************************************************************/
1414 : /* GetColOfUsage() */
1415 : /************************************************************************/
1416 :
1417 : /** Return the index of the column that corresponds to the passed usage.
1418 : * @param eUsage usage.
1419 : * @return column index, or -1 in case of error.
1420 : */
1421 8 : int GDALDefaultRasterAttributeTable::GetColOfUsage(
1422 : GDALRATFieldUsage eUsage) const
1423 :
1424 : {
1425 16 : for (unsigned int i = 0; i < aoFields.size(); i++)
1426 : {
1427 12 : if (aoFields[i].eUsage == eUsage)
1428 4 : return i;
1429 : }
1430 :
1431 4 : return -1;
1432 : }
1433 :
1434 : /************************************************************************/
1435 : /* GDALRATGetColOfUsage() */
1436 : /************************************************************************/
1437 :
1438 : /**
1439 : * \brief Fetch column index for given usage.
1440 : *
1441 : * This function is the same as the C++ method
1442 : * GDALRasterAttributeTable::GetColOfUsage()
1443 : */
1444 13 : int CPL_STDCALL GDALRATGetColOfUsage(GDALRasterAttributeTableH hRAT,
1445 : GDALRATFieldUsage eUsage)
1446 :
1447 : {
1448 13 : VALIDATE_POINTER1(hRAT, "GDALRATGetColOfUsage", 0);
1449 :
1450 13 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetColOfUsage(eUsage);
1451 : }
1452 :
1453 : /************************************************************************/
1454 : /* GetRowCount() */
1455 : /************************************************************************/
1456 :
1457 102 : int GDALDefaultRasterAttributeTable::GetRowCount() const
1458 :
1459 : {
1460 102 : return static_cast<int>(nRowCount);
1461 : }
1462 :
1463 : /************************************************************************/
1464 : /* GDALRATGetUsageOfCol() */
1465 : /************************************************************************/
1466 : /**
1467 : * \brief Fetch row count.
1468 : *
1469 : * This function is the same as the C++ method
1470 : * GDALRasterAttributeTable::GetRowCount()
1471 : */
1472 45 : int CPL_STDCALL GDALRATGetRowCount(GDALRasterAttributeTableH hRAT)
1473 :
1474 : {
1475 45 : VALIDATE_POINTER1(hRAT, "GDALRATGetRowCount", 0);
1476 :
1477 45 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowCount();
1478 : }
1479 :
1480 : /************************************************************************/
1481 : /* GetValueAsString() */
1482 : /************************************************************************/
1483 :
1484 39 : const char *GDALDefaultRasterAttributeTable::GetValueAsString(int iRow,
1485 : int iField) const
1486 :
1487 : {
1488 39 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1489 : {
1490 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1491 : iField);
1492 :
1493 0 : return "";
1494 : }
1495 :
1496 39 : if (iRow < 0 || iRow >= nRowCount)
1497 : {
1498 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1499 :
1500 0 : return "";
1501 : }
1502 :
1503 39 : switch (aoFields[iField].eType)
1504 : {
1505 0 : case GFT_Integer:
1506 : {
1507 : const_cast<GDALDefaultRasterAttributeTable *>(this)
1508 0 : ->osWorkingResult.Printf("%d", aoFields[iField].anValues[iRow]);
1509 0 : return osWorkingResult;
1510 : }
1511 :
1512 0 : case GFT_Real:
1513 : {
1514 : const_cast<GDALDefaultRasterAttributeTable *>(this)
1515 : ->osWorkingResult.Printf("%.16g",
1516 0 : aoFields[iField].adfValues[iRow]);
1517 0 : return osWorkingResult;
1518 : }
1519 :
1520 39 : case GFT_String:
1521 : {
1522 39 : return aoFields[iField].aosValues[iRow];
1523 : }
1524 : }
1525 :
1526 0 : return "";
1527 : }
1528 :
1529 : /************************************************************************/
1530 : /* GDALRATGetValueAsString() */
1531 : /************************************************************************/
1532 : /**
1533 : * \brief Fetch field value as a string.
1534 : *
1535 : * This function is the same as the C++ method
1536 : * GDALRasterAttributeTable::GetValueAsString()
1537 : */
1538 50 : const char *CPL_STDCALL GDALRATGetValueAsString(GDALRasterAttributeTableH hRAT,
1539 : int iRow, int iField)
1540 :
1541 : {
1542 50 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsString", nullptr);
1543 :
1544 100 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsString(iRow,
1545 50 : iField);
1546 : }
1547 :
1548 : /************************************************************************/
1549 : /* GetValueAsInt() */
1550 : /************************************************************************/
1551 :
1552 194 : int GDALDefaultRasterAttributeTable::GetValueAsInt(int iRow, int iField) const
1553 :
1554 : {
1555 194 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1556 : {
1557 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1558 : iField);
1559 :
1560 0 : return 0;
1561 : }
1562 :
1563 194 : if (iRow < 0 || iRow >= nRowCount)
1564 : {
1565 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1566 :
1567 0 : return 0;
1568 : }
1569 :
1570 194 : switch (aoFields[iField].eType)
1571 : {
1572 194 : case GFT_Integer:
1573 194 : return aoFields[iField].anValues[iRow];
1574 :
1575 0 : case GFT_Real:
1576 0 : return static_cast<int>(aoFields[iField].adfValues[iRow]);
1577 :
1578 0 : case GFT_String:
1579 0 : return atoi(aoFields[iField].aosValues[iRow].c_str());
1580 : }
1581 :
1582 0 : return 0;
1583 : }
1584 :
1585 : /************************************************************************/
1586 : /* GDALRATGetValueAsInt() */
1587 : /************************************************************************/
1588 :
1589 : /**
1590 : * \brief Fetch field value as a integer.
1591 : *
1592 : * This function is the same as the C++ method
1593 : * GDALRasterAttributeTable::GetValueAsInt()
1594 : */
1595 72 : int CPL_STDCALL GDALRATGetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
1596 : int iField)
1597 :
1598 : {
1599 72 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsInt", 0);
1600 :
1601 144 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsInt(iRow,
1602 72 : iField);
1603 : }
1604 :
1605 : /************************************************************************/
1606 : /* GetValueAsDouble() */
1607 : /************************************************************************/
1608 :
1609 1040 : double GDALDefaultRasterAttributeTable::GetValueAsDouble(int iRow,
1610 : int iField) const
1611 :
1612 : {
1613 1040 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1614 : {
1615 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1616 : iField);
1617 :
1618 0 : return 0;
1619 : }
1620 :
1621 1040 : if (iRow < 0 || iRow >= nRowCount)
1622 : {
1623 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1624 :
1625 0 : return 0;
1626 : }
1627 :
1628 1040 : switch (aoFields[iField].eType)
1629 : {
1630 0 : case GFT_Integer:
1631 0 : return aoFields[iField].anValues[iRow];
1632 :
1633 1040 : case GFT_Real:
1634 1040 : return aoFields[iField].adfValues[iRow];
1635 :
1636 0 : case GFT_String:
1637 0 : return CPLAtof(aoFields[iField].aosValues[iRow].c_str());
1638 : }
1639 :
1640 0 : return 0;
1641 : }
1642 :
1643 : /************************************************************************/
1644 : /* GDALRATGetValueAsDouble() */
1645 : /************************************************************************/
1646 :
1647 : /**
1648 : * \brief Fetch field value as a double.
1649 : *
1650 : * This function is the same as the C++ method
1651 : * GDALRasterAttributeTable::GetValueAsDouble()
1652 : */
1653 38 : double CPL_STDCALL GDALRATGetValueAsDouble(GDALRasterAttributeTableH hRAT,
1654 : int iRow, int iField)
1655 :
1656 : {
1657 38 : VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsDouble", 0);
1658 :
1659 76 : return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDouble(iRow,
1660 38 : iField);
1661 : }
1662 :
1663 : /************************************************************************/
1664 : /* SetRowCount() */
1665 : /************************************************************************/
1666 :
1667 : /** Set row count.
1668 : * @param nNewCount new count.
1669 : */
1670 1621 : void GDALDefaultRasterAttributeTable::SetRowCount(int nNewCount)
1671 :
1672 : {
1673 1621 : if (nNewCount == nRowCount)
1674 20 : return;
1675 :
1676 3917 : for (auto &oField : aoFields)
1677 : {
1678 2316 : switch (oField.eType)
1679 : {
1680 696 : case GFT_Integer:
1681 696 : oField.anValues.resize(nNewCount);
1682 696 : break;
1683 :
1684 1385 : case GFT_Real:
1685 1385 : oField.adfValues.resize(nNewCount);
1686 1385 : break;
1687 :
1688 235 : case GFT_String:
1689 235 : oField.aosValues.resize(nNewCount);
1690 235 : break;
1691 : }
1692 : }
1693 :
1694 1601 : nRowCount = nNewCount;
1695 : }
1696 :
1697 : /************************************************************************/
1698 : /* SetValue() */
1699 : /************************************************************************/
1700 :
1701 : /** Set value
1702 : * @param iRow row index.
1703 : * @param iField field index.
1704 : * @param pszValue value.
1705 : */
1706 2022 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1707 : const char *pszValue)
1708 :
1709 : {
1710 2022 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1711 : {
1712 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1713 : iField);
1714 :
1715 0 : return CE_Failure;
1716 : }
1717 :
1718 2022 : if (iRow == nRowCount)
1719 1287 : SetRowCount(nRowCount + 1);
1720 :
1721 2022 : if (iRow < 0 || iRow >= nRowCount)
1722 : {
1723 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1724 :
1725 0 : return CE_Failure;
1726 : }
1727 :
1728 2022 : switch (aoFields[iField].eType)
1729 : {
1730 10 : case GFT_Integer:
1731 10 : aoFields[iField].anValues[iRow] = atoi(pszValue);
1732 10 : break;
1733 :
1734 1280 : case GFT_Real:
1735 1280 : aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
1736 1280 : break;
1737 :
1738 732 : case GFT_String:
1739 732 : aoFields[iField].aosValues[iRow] = pszValue;
1740 732 : break;
1741 : }
1742 :
1743 2022 : return CE_None;
1744 : }
1745 :
1746 : /************************************************************************/
1747 : /* GDALRATSetValueAsString() */
1748 : /************************************************************************/
1749 :
1750 : /**
1751 : * \brief Set field value from string.
1752 : *
1753 : * This function is the same as the C++ method
1754 : * GDALRasterAttributeTable::SetValue()
1755 : * @param hRAT RAT handle.
1756 : * @param iRow row index.
1757 : * @param iField field index.
1758 : * @param pszValue value.
1759 : */
1760 27 : void CPL_STDCALL GDALRATSetValueAsString(GDALRasterAttributeTableH hRAT,
1761 : int iRow, int iField,
1762 : const char *pszValue)
1763 :
1764 : {
1765 27 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsString");
1766 :
1767 27 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
1768 27 : pszValue);
1769 : }
1770 :
1771 : /************************************************************************/
1772 : /* SetValue() */
1773 : /************************************************************************/
1774 :
1775 1193 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1776 : int nValue)
1777 :
1778 : {
1779 1193 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1780 : {
1781 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1782 : iField);
1783 :
1784 0 : return CE_Failure;
1785 : }
1786 :
1787 1193 : if (iRow == nRowCount)
1788 298 : SetRowCount(nRowCount + 1);
1789 :
1790 1193 : if (iRow < 0 || iRow >= nRowCount)
1791 : {
1792 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1793 :
1794 0 : return CE_Failure;
1795 : }
1796 :
1797 1193 : switch (aoFields[iField].eType)
1798 : {
1799 1193 : case GFT_Integer:
1800 1193 : aoFields[iField].anValues[iRow] = nValue;
1801 1193 : break;
1802 :
1803 0 : case GFT_Real:
1804 0 : aoFields[iField].adfValues[iRow] = nValue;
1805 0 : break;
1806 :
1807 0 : case GFT_String:
1808 : {
1809 : char szValue[100];
1810 :
1811 0 : snprintf(szValue, sizeof(szValue), "%d", nValue);
1812 0 : aoFields[iField].aosValues[iRow] = szValue;
1813 : }
1814 0 : break;
1815 : }
1816 :
1817 1193 : return CE_None;
1818 : }
1819 :
1820 : /************************************************************************/
1821 : /* GDALRATSetValueAsInt() */
1822 : /************************************************************************/
1823 :
1824 : /**
1825 : * \brief Set field value from integer.
1826 : *
1827 : * This function is the same as the C++ method
1828 : * GDALRasterAttributeTable::SetValue()
1829 : */
1830 39 : void CPL_STDCALL GDALRATSetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
1831 : int iField, int nValue)
1832 :
1833 : {
1834 39 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsInt");
1835 :
1836 39 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, nValue);
1837 : }
1838 :
1839 : /************************************************************************/
1840 : /* SetValue() */
1841 : /************************************************************************/
1842 :
1843 3586 : CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
1844 : double dfValue)
1845 :
1846 : {
1847 3586 : if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
1848 : {
1849 0 : CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
1850 : iField);
1851 :
1852 0 : return CE_Failure;
1853 : }
1854 :
1855 3586 : if (iRow == nRowCount)
1856 0 : SetRowCount(nRowCount + 1);
1857 :
1858 3586 : if (iRow < 0 || iRow >= nRowCount)
1859 : {
1860 0 : CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
1861 :
1862 0 : return CE_Failure;
1863 : }
1864 :
1865 3586 : switch (aoFields[iField].eType)
1866 : {
1867 0 : case GFT_Integer:
1868 0 : aoFields[iField].anValues[iRow] = static_cast<int>(dfValue);
1869 0 : break;
1870 :
1871 3586 : case GFT_Real:
1872 3586 : aoFields[iField].adfValues[iRow] = dfValue;
1873 3586 : break;
1874 :
1875 0 : case GFT_String:
1876 : {
1877 0 : char szValue[100] = {'\0'};
1878 :
1879 0 : CPLsnprintf(szValue, sizeof(szValue), "%.15g", dfValue);
1880 0 : aoFields[iField].aosValues[iRow] = szValue;
1881 : }
1882 0 : break;
1883 : }
1884 :
1885 3586 : return CE_None;
1886 : }
1887 :
1888 : /************************************************************************/
1889 : /* GDALRATSetValueAsDouble() */
1890 : /************************************************************************/
1891 :
1892 : /**
1893 : * \brief Set field value from double.
1894 : *
1895 : * This function is the same as the C++ method
1896 : * GDALRasterAttributeTable::SetValue()
1897 : */
1898 25 : void CPL_STDCALL GDALRATSetValueAsDouble(GDALRasterAttributeTableH hRAT,
1899 : int iRow, int iField, double dfValue)
1900 :
1901 : {
1902 25 : VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsDouble");
1903 :
1904 25 : GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, dfValue);
1905 : }
1906 :
1907 : /************************************************************************/
1908 : /* ChangesAreWrittenToFile() */
1909 : /************************************************************************/
1910 :
1911 0 : int GDALDefaultRasterAttributeTable::ChangesAreWrittenToFile()
1912 : {
1913 : // GDALRasterBand.SetDefaultRAT needs to be called on instances of
1914 : // GDALDefaultRasterAttributeTable since changes are just in-memory
1915 0 : return false;
1916 : }
1917 :
1918 : /************************************************************************/
1919 : /* GDALRATChangesAreWrittenToFile() */
1920 : /************************************************************************/
1921 :
1922 : /**
1923 : * \brief Determine whether changes made to this RAT are reflected directly in
1924 : * the dataset
1925 : *
1926 : * This function is the same as the C++ method
1927 : * GDALRasterAttributeTable::ChangesAreWrittenToFile()
1928 : */
1929 2 : int CPL_STDCALL GDALRATChangesAreWrittenToFile(GDALRasterAttributeTableH hRAT)
1930 : {
1931 2 : VALIDATE_POINTER1(hRAT, "GDALRATChangesAreWrittenToFile", false);
1932 :
1933 2 : return GDALRasterAttributeTable::FromHandle(hRAT)
1934 2 : ->ChangesAreWrittenToFile();
1935 : }
1936 :
1937 : /************************************************************************/
1938 : /* GetRowOfValue() */
1939 : /************************************************************************/
1940 :
1941 2 : int GDALDefaultRasterAttributeTable::GetRowOfValue(double dfValue) const
1942 :
1943 : {
1944 : /* -------------------------------------------------------------------- */
1945 : /* Handle case of regular binning. */
1946 : /* -------------------------------------------------------------------- */
1947 2 : if (bLinearBinning)
1948 : {
1949 0 : const int iBin =
1950 0 : static_cast<int>(floor((dfValue - dfRow0Min) / dfBinSize));
1951 0 : if (iBin < 0 || iBin >= nRowCount)
1952 0 : return -1;
1953 :
1954 0 : return iBin;
1955 : }
1956 :
1957 : /* -------------------------------------------------------------------- */
1958 : /* Do we have any information? */
1959 : /* -------------------------------------------------------------------- */
1960 2 : if (!bColumnsAnalysed)
1961 2 : const_cast<GDALDefaultRasterAttributeTable *>(this)->AnalyseColumns();
1962 :
1963 2 : if (nMinCol == -1 && nMaxCol == -1)
1964 0 : return -1;
1965 :
1966 2 : const GDALRasterAttributeField *poMin = nullptr;
1967 2 : if (nMinCol != -1)
1968 2 : poMin = &(aoFields[nMinCol]);
1969 : else
1970 0 : poMin = nullptr;
1971 :
1972 2 : const GDALRasterAttributeField *poMax = nullptr;
1973 2 : if (nMaxCol != -1)
1974 2 : poMax = &(aoFields[nMaxCol]);
1975 : else
1976 0 : poMax = nullptr;
1977 :
1978 : /* -------------------------------------------------------------------- */
1979 : /* Search through rows for match. */
1980 : /* -------------------------------------------------------------------- */
1981 4 : for (int iRow = 0; iRow < nRowCount; iRow++)
1982 : {
1983 4 : if (poMin != nullptr)
1984 : {
1985 4 : if (poMin->eType == GFT_Integer)
1986 : {
1987 4 : while (iRow < nRowCount && dfValue < poMin->anValues[iRow])
1988 0 : iRow++;
1989 : }
1990 0 : else if (poMin->eType == GFT_Real)
1991 : {
1992 0 : while (iRow < nRowCount && dfValue < poMin->adfValues[iRow])
1993 0 : iRow++;
1994 : }
1995 :
1996 4 : if (iRow == nRowCount)
1997 0 : break;
1998 : }
1999 :
2000 4 : if (poMax != nullptr)
2001 : {
2002 14 : if ((poMax->eType == GFT_Integer &&
2003 6 : dfValue > poMax->anValues[iRow]) ||
2004 2 : (poMax->eType == GFT_Real && dfValue > poMax->adfValues[iRow]))
2005 2 : continue;
2006 : }
2007 :
2008 2 : return iRow;
2009 : }
2010 :
2011 0 : return -1;
2012 : }
2013 :
2014 : /************************************************************************/
2015 : /* GetRowOfValue() */
2016 : /* */
2017 : /* Int arg for now just converted to double. Perhaps we will */
2018 : /* handle this in a special way some day? */
2019 : /************************************************************************/
2020 :
2021 0 : int GDALDefaultRasterAttributeTable::GetRowOfValue(int nValue) const
2022 :
2023 : {
2024 0 : return GetRowOfValue(static_cast<double>(nValue));
2025 : }
2026 :
2027 : /************************************************************************/
2028 : /* SetLinearBinning() */
2029 : /************************************************************************/
2030 :
2031 16 : CPLErr GDALDefaultRasterAttributeTable::SetLinearBinning(double dfRow0MinIn,
2032 : double dfBinSizeIn)
2033 :
2034 : {
2035 16 : bLinearBinning = true;
2036 16 : dfRow0Min = dfRow0MinIn;
2037 16 : dfBinSize = dfBinSizeIn;
2038 :
2039 16 : return CE_None;
2040 : }
2041 :
2042 : /************************************************************************/
2043 : /* GetLinearBinning() */
2044 : /************************************************************************/
2045 :
2046 13 : int GDALDefaultRasterAttributeTable::GetLinearBinning(double *pdfRow0Min,
2047 : double *pdfBinSize) const
2048 :
2049 : {
2050 13 : if (!bLinearBinning)
2051 9 : return false;
2052 :
2053 4 : *pdfRow0Min = dfRow0Min;
2054 4 : *pdfBinSize = dfBinSize;
2055 :
2056 4 : return true;
2057 : }
2058 :
2059 : /************************************************************************/
2060 : /* GetTableType() */
2061 : /************************************************************************/
2062 :
2063 : /**
2064 : * \brief Get RAT Table Type
2065 : *
2066 : * Returns whether table type is thematic or athematic
2067 : *
2068 : * This method is the same as the C function GDALRATGetTableType().
2069 : *
2070 : * @since GDAL 2.4
2071 : *
2072 : * @return GRTT_THEMATIC or GRTT_ATHEMATIC
2073 : */
2074 :
2075 15 : GDALRATTableType GDALDefaultRasterAttributeTable::GetTableType() const
2076 : {
2077 15 : return eTableType;
2078 : }
2079 :
2080 : /************************************************************************/
2081 : /* SetTableType() */
2082 : /************************************************************************/
2083 :
2084 : /**
2085 : * \brief Set RAT Table Type
2086 : *
2087 : * Set whether table type is thematic or athematic
2088 : *
2089 : * This method is the same as the C function GDALRATSetTableType().
2090 : *
2091 : * @param eInTableType the new RAT table type (GRTT_THEMATIC or GRTT_ATHEMATIC)
2092 : *
2093 : * @since GDAL 2.4
2094 : *
2095 : * @return CE_None on success or CE_Failure on failure.
2096 : */
2097 :
2098 30 : CPLErr GDALDefaultRasterAttributeTable::SetTableType(
2099 : const GDALRATTableType eInTableType)
2100 : {
2101 30 : eTableType = eInTableType;
2102 30 : return CE_None;
2103 : }
2104 :
2105 : /************************************************************************/
2106 : /* CreateColumn() */
2107 : /************************************************************************/
2108 :
2109 : CPLErr
2110 322 : GDALDefaultRasterAttributeTable::CreateColumn(const char *pszFieldName,
2111 : GDALRATFieldType eFieldType,
2112 : GDALRATFieldUsage eFieldUsage)
2113 :
2114 : {
2115 322 : const size_t iNewField = aoFields.size();
2116 :
2117 322 : aoFields.resize(iNewField + 1);
2118 :
2119 322 : aoFields[iNewField].sName = pszFieldName;
2120 :
2121 : // color columns should be int 0..255
2122 322 : if ((eFieldUsage == GFU_Red) || (eFieldUsage == GFU_Green) ||
2123 280 : (eFieldUsage == GFU_Blue) || (eFieldUsage == GFU_Alpha))
2124 : {
2125 47 : eFieldType = GFT_Integer;
2126 : }
2127 322 : aoFields[iNewField].eType = eFieldType;
2128 322 : aoFields[iNewField].eUsage = eFieldUsage;
2129 :
2130 322 : if (eFieldType == GFT_Integer)
2131 175 : aoFields[iNewField].anValues.resize(nRowCount);
2132 147 : else if (eFieldType == GFT_Real)
2133 44 : aoFields[iNewField].adfValues.resize(nRowCount);
2134 103 : else if (eFieldType == GFT_String)
2135 103 : aoFields[iNewField].aosValues.resize(nRowCount);
2136 :
2137 322 : return CE_None;
2138 : }
2139 :
2140 : /************************************************************************/
2141 : /* RemoveStatistics() */
2142 : /************************************************************************/
2143 :
2144 : /**
2145 : * \brief Remove Statistics from RAT
2146 : *
2147 : * Remove statistics (such as histogram) from the RAT. This is important
2148 : * if these have been invalidated, for example by cropping the image.
2149 : *
2150 : * This method is the same as the C function GDALRATRemoveStatistics().
2151 : *
2152 : * @since GDAL 2.4
2153 : */
2154 :
2155 2 : void GDALDefaultRasterAttributeTable::RemoveStatistics()
2156 :
2157 : {
2158 : // since we are storing the fields in a vector it will generally
2159 : // be faster to create a new vector and replace the old one
2160 : // rather than actually erasing columns.
2161 4 : std::vector<GDALRasterAttributeField> aoNewFields;
2162 4 : for (const auto &field : aoFields)
2163 : {
2164 2 : switch (field.eUsage)
2165 : {
2166 1 : case GFU_PixelCount:
2167 : case GFU_Min:
2168 : case GFU_Max:
2169 : case GFU_RedMin:
2170 : case GFU_GreenMin:
2171 : case GFU_BlueMin:
2172 : case GFU_AlphaMin:
2173 : case GFU_RedMax:
2174 : case GFU_GreenMax:
2175 : case GFU_BlueMax:
2176 : case GFU_AlphaMax:
2177 : {
2178 1 : break;
2179 : }
2180 :
2181 1 : default:
2182 1 : if (field.sName != "Histogram")
2183 : {
2184 1 : aoNewFields.push_back(field);
2185 : }
2186 : }
2187 : }
2188 2 : aoFields = std::move(aoNewFields);
2189 2 : }
2190 :
2191 : /************************************************************************/
2192 : /* Clone() */
2193 : /************************************************************************/
2194 :
2195 18 : GDALDefaultRasterAttributeTable *GDALDefaultRasterAttributeTable::Clone() const
2196 :
2197 : {
2198 18 : return new GDALDefaultRasterAttributeTable(*this);
2199 : }
2200 :
2201 : /************************************************************************/
2202 : /* GDALRATClone() */
2203 : /************************************************************************/
2204 :
2205 : /**
2206 : * \brief Copy Raster Attribute Table
2207 : *
2208 : * This function is the same as the C++ method GDALRasterAttributeTable::Clone()
2209 : */
2210 : GDALRasterAttributeTableH CPL_STDCALL
2211 5 : GDALRATClone(const GDALRasterAttributeTableH hRAT)
2212 :
2213 : {
2214 5 : VALIDATE_POINTER1(hRAT, "GDALRATClone", nullptr);
2215 :
2216 5 : return GDALRasterAttributeTable::FromHandle(hRAT)->Clone();
2217 : }
2218 :
2219 : /************************************************************************/
2220 : /* GDALRATSerializeJSON() */
2221 : /************************************************************************/
2222 :
2223 : /**
2224 : * \brief Serialize Raster Attribute Table in Json format
2225 : *
2226 : * This function is the same as the C++ method
2227 : * GDALRasterAttributeTable::SerializeJSON()
2228 : */
2229 4 : void *CPL_STDCALL GDALRATSerializeJSON(GDALRasterAttributeTableH hRAT)
2230 :
2231 : {
2232 4 : VALIDATE_POINTER1(hRAT, "GDALRATSerializeJSON", nullptr);
2233 :
2234 4 : return GDALRasterAttributeTable::FromHandle(hRAT)->SerializeJSON();
2235 : }
2236 :
2237 : /************************************************************************/
2238 : /* GDALRATRemoveStatistics() */
2239 : /************************************************************************/
2240 :
2241 : /**
2242 : * \brief Remove Statistics from RAT
2243 : *
2244 : * This function is the same as the C++ method
2245 : * GDALRasterAttributeTable::RemoveStatistics()
2246 : *
2247 : * @since GDAL 2.4
2248 : */
2249 1 : void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
2250 :
2251 : {
2252 1 : VALIDATE_POINTER0(hRAT, "GDALRATRemoveStatistics");
2253 :
2254 1 : GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
2255 : }
|