LCOV - code coverage report
Current view: top level - gcore - gdal_rat_vat_dbf.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 68 83 81.9 %
Date: 2025-10-21 22:35:35 Functions: 1 1 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Read ArcGIS .vat.dbf raster attribute table
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdal_priv.h"
      14             : #include "gdal_rat.h"
      15             : #include "ogrsf_frmts.h"
      16             : 
      17             : #include <algorithm>
      18             : #include <cmath>
      19             : 
      20             : /************************************************************************/
      21             : /*                            GDALLoadVATDBF()                          */
      22             : /************************************************************************/
      23             : 
      24             : /**
      25             :  * \brief Load a ESRI .vat.dbf auxiliary file as a GDAL attribute table.
      26             :  *
      27             :  * @since GDAL 3.11
      28             :  */
      29             : std::unique_ptr<GDALRasterAttributeTable>
      30           4 : GDALLoadVATDBF(const char *pszFilename)
      31             : {
      32             :     auto poDS = std::unique_ptr<GDALDataset>(
      33             :         GDALDataset::Open(pszFilename, GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR,
      34           8 :                           nullptr, nullptr, nullptr));
      35           4 :     auto poLayer = poDS ? poDS->GetLayer(0) : nullptr;
      36           4 :     if (!poLayer)
      37           1 :         return nullptr;
      38           6 :     auto poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
      39             : 
      40           3 :     const auto poFDefn = poLayer->GetLayerDefn();
      41           3 :     int iRedIdxFloat = -1;
      42           3 :     int iGreenIdxFloat = -1;
      43           3 :     int iBlueIdxFloat = -1;
      44           3 :     const int nFieldCount = poFDefn->GetFieldCount();
      45          23 :     for (int i = 0; i < nFieldCount; ++i)
      46             :     {
      47          20 :         const auto poFieldDefn = poFDefn->GetFieldDefn(i);
      48          20 :         const auto eFieldType = poFieldDefn->GetType();
      49          20 :         const char *pszName = poFieldDefn->GetNameRef();
      50          20 :         if (EQUAL(pszName, "VALUE"))
      51             :         {
      52           2 :             if (eFieldType == OFTReal)
      53           0 :                 poRAT->CreateColumn(pszName, GFT_Real, GFU_MinMax);
      54             :             else
      55           2 :                 poRAT->CreateColumn(pszName, GFT_Integer, GFU_MinMax);
      56             :         }
      57          18 :         else if (EQUAL(pszName, "COUNT") &&
      58           0 :                  (eFieldType == OFTInteger || eFieldType == OFTInteger64))
      59             :         {
      60           2 :             poRAT->CreateColumn(pszName, GFT_Integer, GFU_PixelCount);
      61             :         }
      62          16 :         else if ((STARTS_WITH_CI(pszName, "CLASS") || EQUAL(pszName, "NAME")) &&
      63             :                  eFieldType == OFTString)
      64             :         {
      65           2 :             poRAT->CreateColumn(pszName, GFT_String, GFU_Name);
      66             :         }
      67          14 :         else if (EQUAL(pszName, "RED") && !strstr(pszName, "min") &&
      68           2 :                  !strstr(pszName, "max") && eFieldType == OFTReal)
      69             :         {
      70             :             // Convert from [0,1] to [0,255]
      71           2 :             iRedIdxFloat = i;
      72           2 :             poRAT->CreateColumn(pszName, GFT_Integer, GFU_Red);
      73             :         }
      74          12 :         else if (EQUAL(pszName, "GREEN") && !strstr(pszName, "min") &&
      75           2 :                  !strstr(pszName, "max") && eFieldType == OFTReal)
      76             :         {
      77             :             // Convert from [0,1] to [0,255]
      78           2 :             iGreenIdxFloat = i;
      79           2 :             poRAT->CreateColumn(pszName, GFT_Integer, GFU_Green);
      80             :         }
      81          10 :         else if (EQUAL(pszName, "BLUE") && !strstr(pszName, "min") &&
      82           2 :                  !strstr(pszName, "max") && eFieldType == OFTReal)
      83             :         {
      84             :             // Convert from [0,1] to [0,255]
      85           2 :             iBlueIdxFloat = i;
      86           2 :             poRAT->CreateColumn(pszName, GFT_Integer, GFU_Blue);
      87             :         }
      88             :         else
      89             :         {
      90           8 :             GDALRATFieldType eRATFieldType = GFT_String;
      91           8 :             switch (eFieldType)
      92             :             {
      93           2 :                 case OFTReal:
      94           2 :                     eRATFieldType = GFT_Real;
      95           2 :                     break;
      96           3 :                 case OFTInteger:
      97             :                 case OFTInteger64:
      98           3 :                     eRATFieldType = (poFieldDefn->GetSubType() == OFSTBoolean)
      99           3 :                                         ? GFT_Boolean
     100             :                                         : GFT_Integer;
     101           3 :                     break;
     102           1 :                 case OFTDate:
     103           1 :                     eRATFieldType = GFT_DateTime;
     104           1 :                     break;
     105           2 :                 default:
     106           2 :                     break;
     107             :             }
     108           8 :             poRAT->CreateColumn(pszName, eRATFieldType, GFU_Generic);
     109             :         }
     110             :     }
     111             : 
     112           3 :     int iRow = 0;
     113           7 :     for (auto &&poFeature : *poLayer)
     114             :     {
     115          40 :         for (int i = 0; i < nFieldCount; ++i)
     116             :         {
     117          36 :             if (i == iRedIdxFloat || i == iGreenIdxFloat || i == iBlueIdxFloat)
     118             :             {
     119          12 :                 poRAT->SetValue(
     120             :                     iRow, i,
     121             :                     static_cast<int>(
     122          24 :                         std::clamp(255.0 * poFeature->GetFieldAsDouble(i) + 0.5,
     123          36 :                                    0.0, 255.0)));
     124             :             }
     125             :             else
     126             :             {
     127          24 :                 switch (poRAT->GDALDefaultRasterAttributeTable::GetTypeOfCol(i))
     128             :                 {
     129          12 :                     case GFT_Integer:
     130             :                     {
     131          12 :                         poRAT->GDALDefaultRasterAttributeTable::SetValue(
     132             :                             iRow, i, poFeature->GetFieldAsInteger(i));
     133          12 :                         break;
     134             :                     }
     135           4 :                     case GFT_Real:
     136             :                     {
     137           4 :                         poRAT->GDALDefaultRasterAttributeTable::SetValue(
     138             :                             iRow, i, poFeature->GetFieldAsDouble(i));
     139           4 :                         break;
     140             :                     }
     141           8 :                     case GFT_String:
     142             :                     {
     143           8 :                         poRAT->GDALDefaultRasterAttributeTable::SetValue(
     144             :                             iRow, i, poFeature->GetFieldAsString(i));
     145           8 :                         break;
     146             :                     }
     147           0 :                     case GFT_Boolean:
     148             :                     {
     149           0 :                         poRAT->GDALDefaultRasterAttributeTable::SetValue(
     150           0 :                             iRow, i, poFeature->GetFieldAsInteger(i) != 0);
     151           0 :                         break;
     152             :                     }
     153           0 :                     case GFT_DateTime:
     154             :                     {
     155           0 :                         GDALRATDateTime dt;
     156           0 :                         int nTZFlag = 0;
     157           0 :                         poFeature->GetFieldAsDateTime(
     158             :                             i, &dt.nYear, &dt.nMonth, &dt.nDay, &dt.nHour,
     159             :                             &dt.nMinute, &dt.fSecond, &nTZFlag);
     160           0 :                         dt.bIsValid = true;
     161           0 :                         poRAT->GDALDefaultRasterAttributeTable::SetValue(iRow,
     162             :                                                                          i, dt);
     163           0 :                         break;
     164             :                     }
     165           0 :                     case GFT_WKBGeometry:
     166           0 :                         CPLAssert(false);
     167             :                         break;
     168             :                 }
     169             :             }
     170             :         }
     171           4 :         ++iRow;
     172             :     }
     173             : 
     174           3 :     return poRAT;
     175             : }

Generated by: LCOV version 1.14