LCOV - code coverage report
Current view: top level - gcore - gdal_rat.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 447 622 71.9 %
Date: 2025-09-10 17:48:50 Functions: 56 70 80.0 %

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

Generated by: LCOV version 1.14