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 : mutable std::vector<GByte> m_abyWKB{};
30 :
31 : public:
32 : GDALRasterAttributeTableFromMDArrays(
33 : GDALRATTableType eTableType,
34 : const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
35 : const std::vector<GDALRATFieldUsage> &aeUsages);
36 :
37 : //
38 : GDALRasterAttributeTable *Clone() const override;
39 :
40 : //
41 41 : int GetColumnCount() const override
42 : {
43 41 : return static_cast<int>(m_apoArrays.size());
44 : }
45 :
46 3 : const char *GetNameOfCol(int iCol) const override
47 : {
48 3 : if (iCol < 0 || iCol >= GetColumnCount())
49 2 : return nullptr;
50 1 : return m_apoArrays[iCol]->GetName().c_str();
51 : }
52 :
53 : //
54 9 : GDALRATFieldUsage GetUsageOfCol(int iCol) const override
55 : {
56 9 : if (iCol < 0 || iCol >= GetColumnCount() || m_aeUsages.empty())
57 3 : return GFU_Generic;
58 6 : return m_aeUsages[iCol];
59 : }
60 :
61 : //
62 5 : GDALRATFieldType GetTypeOfCol(int iCol) const override
63 : {
64 5 : if (iCol < 0 || iCol >= GetColumnCount())
65 2 : return GFT_Integer;
66 3 : switch (m_apoArrays[iCol]->GetDataType().GetNumericDataType())
67 : {
68 1 : case GDT_Int8:
69 : case GDT_UInt8:
70 : case GDT_UInt16:
71 : case GDT_Int16:
72 : case GDT_Int32:
73 1 : return GFT_Integer;
74 1 : case GDT_UInt32:
75 : case GDT_Int64:
76 : case GDT_UInt64:
77 : case GDT_Float16:
78 : case GDT_Float32:
79 : case GDT_Float64:
80 1 : return GFT_Real;
81 1 : default:
82 1 : break;
83 : }
84 1 : return GFT_String;
85 : }
86 :
87 : //
88 2 : int GetColOfUsage(GDALRATFieldUsage eUsage) const override
89 : {
90 2 : const int nColCount = GetColumnCount();
91 6 : for (int i = 0; i < nColCount; i++)
92 : {
93 5 : if (GetUsageOfCol(i) == eUsage)
94 1 : return i;
95 : }
96 :
97 1 : return -1;
98 : }
99 :
100 : //
101 32 : int GetRowCount() const override
102 : {
103 32 : return static_cast<int>(m_apoArrays[0]->GetDimensions()[0]->GetSize());
104 : }
105 :
106 : //
107 4 : const char *GetValueAsString(int iRow, int iField) const override
108 : {
109 6 : if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
110 2 : iField >= GetColumnCount())
111 2 : return nullptr;
112 :
113 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
114 2 : const size_t count[1] = {1};
115 2 : const GInt64 arrayStep[1] = {1};
116 2 : const GPtrDiff_t bufferStride[1] = {1};
117 2 : char *pszStr = nullptr;
118 2 : void *pDstBuffer = &pszStr;
119 4 : if (!m_apoArrays[iField]->Read(
120 : arrayStartIdx, count, arrayStep, bufferStride,
121 4 : GDALExtendedDataType::CreateString(), pDstBuffer))
122 0 : return nullptr;
123 : // cppcheck-suppress knownConditionTrueFalse
124 2 : if (!pszStr)
125 0 : return nullptr;
126 2 : m_osTmp = pszStr;
127 2 : CPLFree(pszStr);
128 2 : return m_osTmp.c_str();
129 : }
130 :
131 : //
132 4 : int GetValueAsInt(int iRow, int iField) const override
133 : {
134 6 : if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
135 2 : iField >= GetColumnCount())
136 2 : return 0;
137 :
138 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
139 2 : const size_t count[1] = {1};
140 2 : const GInt64 arrayStep[1] = {1};
141 2 : const GPtrDiff_t bufferStride[1] = {1};
142 2 : int nVal = 0;
143 2 : void *pDstBuffer = &nVal;
144 4 : if (!m_apoArrays[iField]->Read(
145 : arrayStartIdx, count, arrayStep, bufferStride,
146 4 : GDALExtendedDataType::Create(GDT_Int32), pDstBuffer))
147 0 : return 0;
148 2 : return nVal;
149 : }
150 :
151 : //
152 4 : double GetValueAsDouble(int iRow, int iField) const override
153 : {
154 6 : if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
155 2 : iField >= GetColumnCount())
156 2 : return 0;
157 :
158 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
159 2 : const size_t count[1] = {1};
160 2 : const GInt64 arrayStep[1] = {1};
161 2 : const GPtrDiff_t bufferStride[1] = {1};
162 2 : double dfVal = 0;
163 2 : void *pDstBuffer = &dfVal;
164 4 : if (!m_apoArrays[iField]->Read(
165 : arrayStartIdx, count, arrayStep, bufferStride,
166 4 : GDALExtendedDataType::Create(GDT_Float64), pDstBuffer))
167 0 : return 0;
168 2 : return dfVal;
169 : }
170 :
171 : //
172 1 : bool GetValueAsBoolean(int iRow, int iField) const override
173 : {
174 : // Let ValuesIO do the work.
175 1 : bool bValue = false;
176 1 : if (const_cast<GDALRasterAttributeTableFromMDArrays *>(this)->ValuesIO(
177 1 : GF_Read, iField, iRow, 1, &bValue) != CE_None)
178 : {
179 0 : return false;
180 : }
181 :
182 1 : return bValue;
183 : }
184 :
185 : //
186 1 : GDALRATDateTime GetValueAsDateTime(int iRow, int iField) const override
187 : {
188 : // Let ValuesIO do the work.
189 1 : GDALRATDateTime dt;
190 1 : const_cast<GDALRasterAttributeTableFromMDArrays *>(this)->ValuesIO(
191 : GF_Read, iField, iRow, 1, &dt);
192 1 : return dt;
193 : }
194 :
195 : //
196 1 : const GByte *GetValueAsWKBGeometry(int iRow, int iField,
197 : size_t &nWKBSize) const override
198 : {
199 : // Let ValuesIO do the work.
200 1 : GByte *pabyWKB = nullptr;
201 1 : nWKBSize = 0;
202 1 : const_cast<GDALRasterAttributeTableFromMDArrays *>(this)->ValuesIO(
203 : GF_Read, iField, iRow, 1, &pabyWKB, &nWKBSize);
204 1 : if (pabyWKB)
205 0 : m_abyWKB.assign(pabyWKB, pabyWKB + nWKBSize);
206 1 : CPLFree(pabyWKB);
207 1 : return pabyWKB ? m_abyWKB.data() : nullptr;
208 : }
209 :
210 : //
211 5 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
212 : double *pdfData) override
213 : {
214 5 : if (eRWFlag != GF_Read)
215 : {
216 0 : CPLError(CE_Failure, CPLE_NotSupported,
217 : "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
218 : "eRWFlag != GF_Read not supported");
219 0 : return CE_Failure;
220 : }
221 9 : if (iStartRow < 0 || iLength <= 0 ||
222 4 : iStartRow > GetRowCount() - iLength)
223 : {
224 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
225 2 : return CE_Failure;
226 : }
227 3 : if (iField < 0 || iField >= GetColumnCount())
228 : {
229 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
230 2 : return CE_Failure;
231 : }
232 1 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
233 1 : const size_t count[1] = {static_cast<size_t>(iLength)};
234 1 : const GInt64 arrayStep[1] = {1};
235 1 : const GPtrDiff_t bufferStride[1] = {1};
236 2 : if (!m_apoArrays[iField]->Read(
237 : arrayStartIdx, count, arrayStep, bufferStride,
238 2 : GDALExtendedDataType::Create(GDT_Float64), pdfData))
239 0 : return CE_Failure;
240 1 : return CE_None;
241 : }
242 :
243 : //
244 10 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
245 : int *pnData) override
246 : {
247 10 : if (eRWFlag != GF_Read)
248 : {
249 0 : CPLError(CE_Failure, CPLE_NotSupported,
250 : "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
251 : "eRWFlag != GF_Read not supported");
252 0 : return CE_Failure;
253 : }
254 18 : if (iStartRow < 0 || iLength <= 0 ||
255 8 : iStartRow > GetRowCount() - iLength)
256 : {
257 4 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
258 4 : return CE_Failure;
259 : }
260 6 : if (iField < 0 || iField >= GetColumnCount())
261 : {
262 4 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
263 4 : return CE_Failure;
264 : }
265 2 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
266 2 : const size_t count[1] = {static_cast<size_t>(iLength)};
267 2 : const GInt64 arrayStep[1] = {1};
268 2 : const GPtrDiff_t bufferStride[1] = {1};
269 4 : if (!m_apoArrays[iField]->Read(
270 : arrayStartIdx, count, arrayStep, bufferStride,
271 4 : GDALExtendedDataType::Create(GDT_Int32), pnData))
272 0 : return CE_Failure;
273 2 : return CE_None;
274 : }
275 :
276 : //
277 7 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
278 : char **papszStrList) override
279 : {
280 7 : if (eRWFlag != GF_Read)
281 : {
282 0 : CPLError(CE_Failure, CPLE_NotSupported,
283 : "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
284 : "eRWFlag != GF_Read not supported");
285 0 : return CE_Failure;
286 : }
287 13 : if (iStartRow < 0 || iLength <= 0 ||
288 6 : iStartRow > GetRowCount() - iLength)
289 : {
290 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
291 2 : return CE_Failure;
292 : }
293 5 : if (iField < 0 || iField >= GetColumnCount())
294 : {
295 2 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
296 2 : return CE_Failure;
297 : }
298 3 : const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
299 3 : const size_t count[1] = {static_cast<size_t>(iLength)};
300 3 : const GInt64 arrayStep[1] = {1};
301 3 : const GPtrDiff_t bufferStride[1] = {1};
302 6 : if (!m_apoArrays[iField]->Read(
303 : arrayStartIdx, count, arrayStep, bufferStride,
304 6 : GDALExtendedDataType::CreateString(), papszStrList))
305 0 : return CE_Failure;
306 3 : return CE_None;
307 : }
308 :
309 : //
310 5 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
311 : bool *pbData) override
312 : {
313 5 : return ValuesIOBooleanFromIntoInt(eRWFlag, iField, iStartRow, iLength,
314 5 : pbData);
315 : }
316 :
317 : //
318 1 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
319 : GDALRATDateTime *psDateTime) override
320 : {
321 1 : return ValuesIODateTimeFromIntoString(eRWFlag, iField, iStartRow,
322 1 : iLength, psDateTime);
323 : }
324 :
325 : //
326 1 : CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
327 : GByte **ppabyWKB, size_t *pnWKBSize) override
328 : {
329 1 : return ValuesIOWKBGeometryFromIntoString(eRWFlag, iField, iStartRow,
330 1 : iLength, ppabyWKB, pnWKBSize);
331 : }
332 :
333 : //
334 1 : CPLErr SetValue(int, int, const char *) override
335 : {
336 1 : CPLError(
337 : CE_Failure, CPLE_NotSupported,
338 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
339 1 : return CE_Failure;
340 : }
341 :
342 : //
343 1 : CPLErr SetValue(int, int, int) override
344 : {
345 1 : CPLError(
346 : CE_Failure, CPLE_NotSupported,
347 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
348 1 : return CE_Failure;
349 : }
350 :
351 : //
352 1 : CPLErr SetValue(int, int, double) override
353 : {
354 1 : CPLError(
355 : CE_Failure, CPLE_NotSupported,
356 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
357 1 : return CE_Failure;
358 : }
359 :
360 : //
361 1 : CPLErr SetValue(int, int, bool) override
362 : {
363 1 : CPLError(
364 : CE_Failure, CPLE_NotSupported,
365 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
366 1 : return CE_Failure;
367 : }
368 :
369 : //
370 1 : CPLErr SetValue(int, int, const GDALRATDateTime &) override
371 : {
372 1 : CPLError(
373 : CE_Failure, CPLE_NotSupported,
374 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
375 1 : return CE_Failure;
376 : }
377 :
378 : //
379 1 : CPLErr SetValue(int, int, const void *, size_t) override
380 : {
381 1 : CPLError(
382 : CE_Failure, CPLE_NotSupported,
383 : "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
384 1 : return CE_Failure;
385 : }
386 :
387 : //
388 1 : int ChangesAreWrittenToFile() override
389 : {
390 1 : return false;
391 : }
392 :
393 : //
394 1 : CPLErr SetTableType(const GDALRATTableType) override
395 : {
396 1 : CPLError(CE_Failure, CPLE_NotSupported,
397 : "GDALRasterAttributeTableFromMDArrays::SetTableType(): not "
398 : "supported");
399 1 : return CE_Failure;
400 : }
401 :
402 : //
403 1 : void RemoveStatistics() override
404 : {
405 1 : }
406 :
407 : //
408 1 : GDALRATTableType GetTableType() const override
409 : {
410 1 : return m_eTableType;
411 : }
412 : };
413 :
414 : //
415 1 : GDALRasterAttributeTable *GDALRasterAttributeTableFromMDArrays::Clone() const
416 : {
417 1 : return new GDALRasterAttributeTableFromMDArrays(m_eTableType, m_apoArrays,
418 1 : m_aeUsages);
419 : }
420 :
421 : /************************************************************************/
422 : /* GDALRasterAttributeTableFromMDArrays() */
423 : /************************************************************************/
424 :
425 3 : GDALRasterAttributeTableFromMDArrays::GDALRasterAttributeTableFromMDArrays(
426 : GDALRATTableType eTableType,
427 : const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
428 3 : const std::vector<GDALRATFieldUsage> &aeUsages)
429 3 : : m_eTableType(eTableType), m_apoArrays(apoArrays), m_aeUsages(aeUsages)
430 : {
431 3 : }
432 :
433 : /************************************************************************/
434 : /* GDALCreateRasterAttributeTableFromMDArrays() */
435 : /************************************************************************/
436 :
437 : /** Return a virtual Raster Attribute Table from several GDALMDArray's.
438 : *
439 : * All arrays must be single-dimensional and be indexed by the same dimension.
440 : *
441 : * This is the same as the C function GDALCreateRasterAttributeTableFromMDArrays().
442 : *
443 : * @param eTableType RAT table type
444 : * @param apoArrays Vector of GDALMDArray's (none of them should be nullptr)
445 : * @param aeUsages Vector of GDALRATFieldUsage (of the same size as apoArrays if non-empty), or empty vector to use defaults
446 : * @return a new Raster Attribute Table to free with delete, or nullptr in case of error
447 : * @since 3.9
448 : */
449 5 : GDALRasterAttributeTable *GDALCreateRasterAttributeTableFromMDArrays(
450 : GDALRATTableType eTableType,
451 : const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
452 : const std::vector<GDALRATFieldUsage> &aeUsages)
453 : {
454 5 : if (apoArrays.empty())
455 : {
456 1 : CPLError(CE_Failure, CPLE_AppDefined,
457 : "GDALCreateRasterAttributeTableFromMDArrays(): apoArrays "
458 : "should not be empty");
459 1 : return nullptr;
460 : }
461 4 : if (!aeUsages.empty() && apoArrays.size() != aeUsages.size())
462 : {
463 0 : CPLError(CE_Failure, CPLE_AppDefined,
464 : "GDALCreateRasterAttributeTableFromMDArrays(): aeUsages "
465 : "should be empty or have the same size as apoArrays");
466 0 : return nullptr;
467 : }
468 11 : for (size_t i = 0; i < apoArrays.size(); ++i)
469 : {
470 9 : if (apoArrays[i]->GetDimensionCount() != 1)
471 : {
472 1 : CPLError(CE_Failure, CPLE_AppDefined,
473 : "GDALCreateRasterAttributeTableFromMDArrays(): "
474 : "apoArrays[%d] has a dimension count != 1",
475 : static_cast<int>(i));
476 1 : return nullptr;
477 : }
478 17 : if (i > 0 && (apoArrays[i]->GetDimensions()[0]->GetFullName() !=
479 9 : apoArrays[0]->GetDimensions()[0]->GetFullName() ||
480 4 : apoArrays[i]->GetDimensions()[0]->GetSize() !=
481 4 : apoArrays[0]->GetDimensions()[0]->GetSize()))
482 : {
483 1 : CPLError(
484 : CE_Failure, CPLE_AppDefined,
485 : "GDALCreateRasterAttributeTableFromMDArrays(): apoArrays[%d] "
486 : "does not have the same dimension has apoArrays[0]",
487 : static_cast<int>(i));
488 1 : return nullptr;
489 : }
490 : }
491 : return new GDALRasterAttributeTableFromMDArrays(eTableType, apoArrays,
492 2 : aeUsages);
493 : }
494 :
495 : /************************************************************************/
496 : /* GDALCreateRasterAttributeTableFromMDArrays() */
497 : /************************************************************************/
498 :
499 : /** Return a virtual Raster Attribute Table from several GDALMDArray's.
500 : *
501 : * All arrays must be single-dimensional and be indexed by the same dimension.
502 : *
503 : * This is the same as the C++ method GDALCreateRasterAttributeTableFromMDArrays().
504 : *
505 : * @param eTableType RAT table type
506 : * @param nArrays Number of elements in ahArrays parameter
507 : * @param ahArrays Array of nArrays GDALMDArray's (none of them should be nullptr)
508 : * @param paeUsages Array of nArray GDALRATFieldUsage, or nullptr to use defaults
509 : * @return a new Raster Attribute Table to free with GDALDestroyRasterAttributeTable(), or nullptr in case of error
510 : * @since 3.9
511 : */
512 5 : GDALRasterAttributeTableH GDALCreateRasterAttributeTableFromMDArrays(
513 : GDALRATTableType eTableType, int nArrays, const GDALMDArrayH *ahArrays,
514 : const GDALRATFieldUsage *paeUsages)
515 : {
516 5 : VALIDATE_POINTER1(ahArrays, __func__, nullptr);
517 10 : std::vector<std::shared_ptr<GDALMDArray>> apoArrays;
518 10 : std::vector<GDALRATFieldUsage> aeUsages;
519 14 : for (int i = 0; i < nArrays; ++i)
520 : {
521 9 : VALIDATE_POINTER1(ahArrays[i], __func__, nullptr);
522 9 : apoArrays.emplace_back(ahArrays[i]->m_poImpl);
523 9 : if (paeUsages)
524 3 : aeUsages.emplace_back(paeUsages[i]);
525 : }
526 5 : return GDALRasterAttributeTable::ToHandle(
527 : GDALCreateRasterAttributeTableFromMDArrays(eTableType, apoArrays,
528 5 : aeUsages));
529 : }
|