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 :
19 : /************************************************************************/
20 : /* GDALLoadVATDBF() */
21 : /************************************************************************/
22 :
23 : /**
24 : * \brief Load a ESRI .vat.dbf auxiliary file as a GDAL attribute table.
25 : *
26 : * @since GDAL 3.11
27 : */
28 : std::unique_ptr<GDALRasterAttributeTable>
29 3 : GDALLoadVATDBF(const char *pszFilename)
30 : {
31 : auto poDS = std::unique_ptr<GDALDataset>(
32 : GDALDataset::Open(pszFilename, GDAL_OF_VECTOR | GDAL_OF_VERBOSE_ERROR,
33 6 : nullptr, nullptr, nullptr));
34 3 : auto poLayer = poDS ? poDS->GetLayer(0) : nullptr;
35 3 : if (!poLayer)
36 1 : return nullptr;
37 4 : auto poRAT = std::make_unique<GDALDefaultRasterAttributeTable>();
38 :
39 2 : const auto poFDefn = poLayer->GetLayerDefn();
40 2 : int iRedIdxFloat = -1;
41 2 : int iGreenIdxFloat = -1;
42 2 : int iBlueIdxFloat = -1;
43 2 : const int nFieldCount = poFDefn->GetFieldCount();
44 20 : for (int i = 0; i < nFieldCount; ++i)
45 : {
46 18 : const auto poFieldDefn = poFDefn->GetFieldDefn(i);
47 18 : const auto eFieldType = poFieldDefn->GetType();
48 18 : const char *pszName = poFieldDefn->GetNameRef();
49 18 : if (EQUAL(pszName, "VALUE"))
50 : {
51 2 : if (eFieldType == OFTReal)
52 0 : poRAT->CreateColumn(pszName, GFT_Real, GFU_MinMax);
53 : else
54 2 : poRAT->CreateColumn(pszName, GFT_Integer, GFU_MinMax);
55 : }
56 16 : else if (EQUAL(pszName, "COUNT") &&
57 0 : (eFieldType == OFTInteger || eFieldType == OFTInteger64))
58 : {
59 2 : poRAT->CreateColumn(pszName, GFT_Integer, GFU_PixelCount);
60 : }
61 14 : else if ((STARTS_WITH_CI(pszName, "CLASS") || EQUAL(pszName, "NAME")) &&
62 : eFieldType == OFTString)
63 : {
64 2 : poRAT->CreateColumn(pszName, GFT_String, GFU_Name);
65 : }
66 12 : else if (EQUAL(pszName, "RED") && !strstr(pszName, "min") &&
67 2 : !strstr(pszName, "max") && eFieldType == OFTReal)
68 : {
69 : // Convert from [0,1] to [0,255]
70 2 : iRedIdxFloat = i;
71 2 : poRAT->CreateColumn(pszName, GFT_Integer, GFU_Red);
72 : }
73 10 : else if (EQUAL(pszName, "GREEN") && !strstr(pszName, "min") &&
74 2 : !strstr(pszName, "max") && eFieldType == OFTReal)
75 : {
76 : // Convert from [0,1] to [0,255]
77 2 : iGreenIdxFloat = i;
78 2 : poRAT->CreateColumn(pszName, GFT_Integer, GFU_Green);
79 : }
80 8 : else if (EQUAL(pszName, "BLUE") && !strstr(pszName, "min") &&
81 2 : !strstr(pszName, "max") && eFieldType == OFTReal)
82 : {
83 : // Convert from [0,1] to [0,255]
84 2 : iBlueIdxFloat = i;
85 2 : poRAT->CreateColumn(pszName, GFT_Integer, GFU_Blue);
86 : }
87 : else
88 : {
89 12 : poRAT->CreateColumn(
90 : pszName,
91 : eFieldType == OFTReal ? GFT_Real
92 2 : : (eFieldType == OFTInteger || eFieldType == OFTInteger64)
93 6 : ? GFT_Integer
94 : : GFT_String,
95 6 : GFU_Generic);
96 : }
97 : }
98 :
99 2 : int iRow = 0;
100 6 : for (auto &&poFeature : *poLayer)
101 : {
102 40 : for (int i = 0; i < nFieldCount; ++i)
103 : {
104 36 : if (i == iRedIdxFloat || i == iGreenIdxFloat || i == iBlueIdxFloat)
105 : {
106 12 : poRAT->SetValue(
107 : iRow, i,
108 : static_cast<int>(
109 24 : std::clamp(255.0 * poFeature->GetFieldAsDouble(i) + 0.5,
110 36 : 0.0, 255.0)));
111 : }
112 : else
113 : {
114 24 : switch (poRAT->GDALDefaultRasterAttributeTable::GetTypeOfCol(i))
115 : {
116 12 : case GFT_Integer:
117 : {
118 12 : poRAT->GDALDefaultRasterAttributeTable::SetValue(
119 : iRow, i, poFeature->GetFieldAsInteger(i));
120 12 : break;
121 : }
122 4 : case GFT_Real:
123 : {
124 4 : poRAT->GDALDefaultRasterAttributeTable::SetValue(
125 : iRow, i, poFeature->GetFieldAsDouble(i));
126 4 : break;
127 : }
128 8 : case GFT_String:
129 : {
130 8 : poRAT->GDALDefaultRasterAttributeTable::SetValue(
131 : iRow, i, poFeature->GetFieldAsString(i));
132 8 : break;
133 : }
134 : }
135 : }
136 : }
137 4 : ++iRow;
138 : }
139 :
140 2 : return poRAT;
141 : }
|