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