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