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

Generated by: LCOV version 1.14