LCOV - code coverage report
Current view: top level - gcore - gdal_rat.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 412 624 66.0 %
Date: 2025-05-31 00:00:17 Functions: 54 71 76.1 %

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

Generated by: LCOV version 1.14