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

Generated by: LCOV version 1.14