Line data Source code
1 : /******************************************************************************
2 : * Name: gdalmultidim_rat.cpp
3 : * Project: GDAL Core
4 : * Purpose: GDALCreateRasterAttributeTableFromMDArrays() implementation
5 : * Author: Even Rouault <even.rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, Even Rouault <even.rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdal_priv.h"
14 : #include "gdal_rat.h"
15 : #include "gdalmultidim_priv.h"
16 :
17 : /************************************************************************/
18 : /* GDALRasterAttributeTableFromMDArrays() */
19 : /************************************************************************/
20 :
21 : class GDALRasterAttributeTableFromMDArrays final
22 : : public GDALRasterAttributeTable
23 : {
24 : const GDALRATTableType m_eTableType;
25 : const std::vector<std::shared_ptr<GDALMDArray>> m_apoArrays;
26 : const std::vector<GDALRATFieldUsage> m_aeUsages;
27 :
28 : mutable std::string m_osTmp{};
29 :
30 : public:
31 : GDALRasterAttributeTableFromMDArrays(
32 : GDALRATTableType eTableType,
33 : const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
34 : const std::vector<GDALRATFieldUsage> &aeUsages);
35 :
36 : //
37 1 : GDALRasterAttributeTable *Clone() const override
38 : {
39 : return new GDALRasterAttributeTableFromMDArrays(
40 1 : m_eTableType, m_apoArrays, m_aeUsages);
41 : }
42 :
43 : //
44 36 : int GetColumnCount() const override
45 : {
46 36 : return static_cast<int>(m_apoArrays.size());
47 : }
48 :
49 3 : const char *GetNameOfCol(int iCol) const override
50 : {
51 3 : if (iCol < 0 || iCol >= GetColumnCount())
52 2 : return nullptr;
53 1 : return m_apoArrays[iCol]->GetName().c_str();
54 : }
55 :
56 : //
57 9 : GDALRATFieldUsage GetUsageOfCol(int iCol) const override
58 : {
59 9 : if (iCol < 0 || iCol >= GetColumnCount() || m_aeUsages.empty())
60 3 : return GFU_Generic;
61 6 : return m_aeUsages[iCol];
62 : }
63 :
64 : //
65 5 : GDALRATFieldType GetTypeOfCol(int iCol) const override
66 : {
67 5 : if (iCol < 0 || iCol >= GetColumnCount())
68 2 : return GFT_Integer;
69 3 : switch (m_apoArrays[iCol]->GetDataType().GetNumericDataType())
70 : {
71 1 : case GDT_Int8:
72 : case GDT_Byte:
73 : case GDT_UInt16:
74 : case GDT_Int16:
75 : case GDT_Int32:
76 1 : return GFT_Integer;
77 1 : case GDT_UInt32:
78 : case GDT_Int64:
79 : case GDT_UInt64:
80 : case GDT_Float32:
81 : case GDT_Float64:
82 1 : return GFT_Real;
83 1 : default:
84 1 : break;
85 : }
86 1 : return GFT_String;
87 : }
88 :
89 : //
90 2 : int GetColOfUsage(GDALRATFieldUsage eUsage) const override
91 : {
92 2 : const int nColCount = GetColumnCount();
93 6 : for (int i = 0; i < nColCount; i++)
94 : {
95 5 : if (GetUsageOfCol(i) == eUsage)
96 1 : return i;
97 : }
98 :
99 1 : return -1;
100 : }
101 :
102 : //
103 25 : int GetRowCount() const override
104 : {
105 25 : return static_cast<int>(m_apoArrays[0]->GetDimensions()[0]->GetSize());
106 : }
107 :
108 : //
109 4 : const char *GetValueAsString(int iRow, int iField) const override
110 : {
111 6 : if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
112 2 : iField >= GetColumnCount())
113 2 : return nullptr;
114 :
115 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
116 2 : const size_t count[1] = {1};
117 2 : const GInt64 arrayStep[1] = {1};
118 2 : const GPtrDiff_t bufferStride[1] = {1};
119 2 : char *pszStr = nullptr;
120 2 : void *pDstBuffer = &pszStr;
121 4 : if (!m_apoArrays[iField]->Read(
122 : arrayStartIdx, count, arrayStep, bufferStride,
123 4 : GDALExtendedDataType::CreateString(), pDstBuffer))
124 0 : return nullptr;
125 2 : if (!pszStr)
126 0 : return nullptr;
127 2 : m_osTmp = pszStr;
128 2 : CPLFree(pszStr);
129 2 : return m_osTmp.c_str();
130 : }
131 :
132 : //
133 4 : int GetValueAsInt(int iRow, int iField) const override
134 : {
135 6 : if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
136 2 : iField >= GetColumnCount())
137 2 : return 0;
138 :
139 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
140 2 : const size_t count[1] = {1};
141 2 : const GInt64 arrayStep[1] = {1};
142 2 : const GPtrDiff_t bufferStride[1] = {1};
143 2 : int nVal = 0;
144 2 : void *pDstBuffer = &nVal;
145 4 : if (!m_apoArrays[iField]->Read(
146 : arrayStartIdx, count, arrayStep, bufferStride,
147 4 : GDALExtendedDataType::Create(GDT_Int32), pDstBuffer))
148 0 : return 0;
149 2 : return nVal;
150 : }
151 :
152 : //
153 4 : double GetValueAsDouble(int iRow, int iField) const override
154 : {
155 6 : if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
156 2 : iField >= GetColumnCount())
157 2 : return 0;
158 :
159 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
160 2 : const size_t count[1] = {1};
161 2 : const GInt64 arrayStep[1] = {1};
162 2 : const GPtrDiff_t bufferStride[1] = {1};
163 2 : double dfVal = 0;
164 2 : void *pDstBuffer = &dfVal;
165 4 : if (!m_apoArrays[iField]->Read(
166 : arrayStartIdx, count, arrayStep, bufferStride,
167 4 : GDALExtendedDataType::Create(GDT_Float64), pDstBuffer))
168 0 : return 0;
169 2 : return dfVal;
170 : }
171 :
172 : //
173 5 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
174 : double *pdfData) override
175 : {
176 5 : if (eRWFlag != GF_Read)
177 : {
178 0 : CPLError(CE_Failure, CPLE_NotSupported,
179 : "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
180 : "eRWFlag != GF_Read not supported");
181 0 : return CE_Failure;
182 : }
183 9 : if (iStartRow < 0 || iLength <= 0 ||
184 4 : iStartRow > GetRowCount() - iLength)
185 : {
186 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
187 2 : return CE_Failure;
188 : }
189 3 : if (iField < 0 || iField >= GetColumnCount())
190 : {
191 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
192 2 : return CE_Failure;
193 : }
194 1 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
195 1 : const size_t count[1] = {static_cast<size_t>(iLength)};
196 1 : const GInt64 arrayStep[1] = {1};
197 1 : const GPtrDiff_t bufferStride[1] = {1};
198 2 : if (!m_apoArrays[iField]->Read(
199 : arrayStartIdx, count, arrayStep, bufferStride,
200 2 : GDALExtendedDataType::Create(GDT_Float64), pdfData))
201 0 : return CE_Failure;
202 1 : return CE_None;
203 : }
204 :
205 : //
206 5 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
207 : int *pnData) override
208 : {
209 5 : if (eRWFlag != GF_Read)
210 : {
211 0 : CPLError(CE_Failure, CPLE_NotSupported,
212 : "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
213 : "eRWFlag != GF_Read not supported");
214 0 : return CE_Failure;
215 : }
216 9 : if (iStartRow < 0 || iLength <= 0 ||
217 4 : iStartRow > GetRowCount() - iLength)
218 : {
219 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
220 2 : return CE_Failure;
221 : }
222 3 : if (iField < 0 || iField >= GetColumnCount())
223 : {
224 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
225 2 : return CE_Failure;
226 : }
227 1 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
228 1 : const size_t count[1] = {static_cast<size_t>(iLength)};
229 1 : const GInt64 arrayStep[1] = {1};
230 1 : const GPtrDiff_t bufferStride[1] = {1};
231 2 : if (!m_apoArrays[iField]->Read(
232 : arrayStartIdx, count, arrayStep, bufferStride,
233 2 : GDALExtendedDataType::Create(GDT_Int32), pnData))
234 0 : return CE_Failure;
235 1 : return CE_None;
236 : }
237 :
238 : //
239 5 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
240 : char **papszStrList) override
241 : {
242 5 : if (eRWFlag != GF_Read)
243 : {
244 0 : CPLError(CE_Failure, CPLE_NotSupported,
245 : "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
246 : "eRWFlag != GF_Read not supported");
247 0 : return CE_Failure;
248 : }
249 9 : if (iStartRow < 0 || iLength <= 0 ||
250 4 : iStartRow > GetRowCount() - iLength)
251 : {
252 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
253 2 : return CE_Failure;
254 : }
255 3 : if (iField < 0 || iField >= GetColumnCount())
256 : {
257 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
258 2 : return CE_Failure;
259 : }
260 1 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
261 1 : const size_t count[1] = {static_cast<size_t>(iLength)};
262 1 : const GInt64 arrayStep[1] = {1};
263 1 : const GPtrDiff_t bufferStride[1] = {1};
264 2 : if (!m_apoArrays[iField]->Read(
265 : arrayStartIdx, count, arrayStep, bufferStride,
266 2 : GDALExtendedDataType::CreateString(), papszStrList))
267 0 : return CE_Failure;
268 1 : return CE_None;
269 : }
270 :
271 : //
272 1 : void SetValue(int, int, const char *) override
273 : {
274 1 : CPLError(
275 : CE_Failure, CPLE_NotSupported,
276 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
277 1 : }
278 :
279 : //
280 1 : void SetValue(int, int, int) override
281 : {
282 1 : CPLError(
283 : CE_Failure, CPLE_NotSupported,
284 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
285 1 : }
286 :
287 : //
288 1 : void SetValue(int, int, double) override
289 : {
290 1 : CPLError(
291 : CE_Failure, CPLE_NotSupported,
292 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
293 1 : }
294 :
295 : //
296 1 : int ChangesAreWrittenToFile() override
297 : {
298 1 : return false;
299 : }
300 :
301 : //
302 1 : CPLErr SetTableType(const GDALRATTableType) override
303 : {
304 1 : CPLError(CE_Failure, CPLE_NotSupported,
305 : "GDALRasterAttributeTableFromMDArrays::SetTableType(): not "
306 : "supported");
307 1 : return CE_Failure;
308 : }
309 :
310 : //
311 1 : void RemoveStatistics() override
312 : {
313 1 : }
314 :
315 : //
316 1 : GDALRATTableType GetTableType() const override
317 : {
318 1 : return m_eTableType;
319 : }
320 : };
321 :
322 : /************************************************************************/
323 : /* GDALRasterAttributeTableFromMDArrays() */
324 : /************************************************************************/
325 :
326 3 : GDALRasterAttributeTableFromMDArrays::GDALRasterAttributeTableFromMDArrays(
327 : GDALRATTableType eTableType,
328 : const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
329 3 : const std::vector<GDALRATFieldUsage> &aeUsages)
330 3 : : m_eTableType(eTableType), m_apoArrays(apoArrays), m_aeUsages(aeUsages)
331 : {
332 3 : }
333 :
334 : /************************************************************************/
335 : /* GDALCreateRasterAttributeTableFromMDArrays() */
336 : /************************************************************************/
337 :
338 : /** Return a virtual Raster Attribute Table from several GDALMDArray's.
339 : *
340 : * All arrays must be single-dimensional and be indexed by the same dimension.
341 : *
342 : * This is the same as the C function GDALCreateRasterAttributeTableFromMDArrays().
343 : *
344 : * @param eTableType RAT table type
345 : * @param apoArrays Vector of GDALMDArray's (none of them should be nullptr)
346 : * @param aeUsages Vector of GDALRATFieldUsage (of the same size as apoArrays if non-empty), or empty vector to use defaults
347 : * @return a new Raster Attribute Table to free with delete, or nullptr in case of error
348 : * @since 3.9
349 : */
350 5 : GDALRasterAttributeTable *GDALCreateRasterAttributeTableFromMDArrays(
351 : GDALRATTableType eTableType,
352 : const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
353 : const std::vector<GDALRATFieldUsage> &aeUsages)
354 : {
355 5 : if (apoArrays.empty())
356 : {
357 1 : CPLError(CE_Failure, CPLE_AppDefined,
358 : "GDALCreateRasterAttributeTableFromMDArrays(): apoArrays "
359 : "should not be empty");
360 1 : return nullptr;
361 : }
362 4 : if (!aeUsages.empty() && apoArrays.size() != aeUsages.size())
363 : {
364 0 : CPLError(CE_Failure, CPLE_AppDefined,
365 : "GDALCreateRasterAttributeTableFromMDArrays(): aeUsages "
366 : "should be empty or have the same size as apoArrays");
367 0 : return nullptr;
368 : }
369 11 : for (size_t i = 0; i < apoArrays.size(); ++i)
370 : {
371 9 : if (apoArrays[i]->GetDimensionCount() != 1)
372 : {
373 1 : CPLError(CE_Failure, CPLE_AppDefined,
374 : "GDALCreateRasterAttributeTableFromMDArrays(): "
375 : "apoArrays[%d] has a dimension count != 1",
376 : static_cast<int>(i));
377 1 : return nullptr;
378 : }
379 17 : if (i > 0 && (apoArrays[i]->GetDimensions()[0]->GetFullName() !=
380 9 : apoArrays[0]->GetDimensions()[0]->GetFullName() ||
381 4 : apoArrays[i]->GetDimensions()[0]->GetSize() !=
382 4 : apoArrays[0]->GetDimensions()[0]->GetSize()))
383 : {
384 1 : CPLError(
385 : CE_Failure, CPLE_AppDefined,
386 : "GDALCreateRasterAttributeTableFromMDArrays(): apoArrays[%d] "
387 : "does not have the same dimension has apoArrays[0]",
388 : static_cast<int>(i));
389 1 : return nullptr;
390 : }
391 : }
392 : return new GDALRasterAttributeTableFromMDArrays(eTableType, apoArrays,
393 2 : aeUsages);
394 : }
395 :
396 : /************************************************************************/
397 : /* GDALCreateRasterAttributeTableFromMDArrays() */
398 : /************************************************************************/
399 :
400 : /** Return a virtual Raster Attribute Table from several GDALMDArray's.
401 : *
402 : * All arrays must be single-dimensional and be indexed by the same dimension.
403 : *
404 : * This is the same as the C++ method GDALCreateRasterAttributeTableFromMDArrays().
405 : *
406 : * @param eTableType RAT table type
407 : * @param nArrays Number of elements in ahArrays parameter
408 : * @param ahArrays Array of nArrays GDALMDArray's (none of them should be nullptr)
409 : * @param paeUsages Array of nArray GDALRATFieldUsage, or nullptr to use defaults
410 : * @return a new Raster Attribute Table to free with GDALDestroyRasterAttributeTable(), or nullptr in case of error
411 : * @since 3.9
412 : */
413 5 : GDALRasterAttributeTableH GDALCreateRasterAttributeTableFromMDArrays(
414 : GDALRATTableType eTableType, int nArrays, const GDALMDArrayH *ahArrays,
415 : const GDALRATFieldUsage *paeUsages)
416 : {
417 5 : VALIDATE_POINTER1(ahArrays, __func__, nullptr);
418 10 : std::vector<std::shared_ptr<GDALMDArray>> apoArrays;
419 10 : std::vector<GDALRATFieldUsage> aeUsages;
420 14 : for (int i = 0; i < nArrays; ++i)
421 : {
422 9 : VALIDATE_POINTER1(ahArrays[i], __func__, nullptr);
423 9 : apoArrays.emplace_back(ahArrays[i]->m_poImpl);
424 9 : if (paeUsages)
425 3 : aeUsages.emplace_back(paeUsages[i]);
426 : }
427 5 : return GDALRasterAttributeTable::ToHandle(
428 : GDALCreateRasterAttributeTableFromMDArrays(eTableType, apoArrays,
429 5 : aeUsages));
430 : }
|