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 : }
|