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