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