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

Generated by: LCOV version 1.14