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