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