Coverage Report

Created: 2025-11-16 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/gcore/gdal_rat.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Implementation of GDALRasterAttributeTable and related classes.
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2005, Frank Warmerdam
9
 * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "gdal.h"
16
#include "gdal_priv.h"
17
#include "gdal_rat.h"
18
19
#include <cmath>
20
#include <cstddef>
21
#include <cstdlib>
22
23
#include <algorithm>
24
#include <vector>
25
26
#include "cpl_conv.h"
27
#include "cpl_error.h"
28
#include "cpl_string.h"
29
#include "cpl_vsi.h"
30
31
#ifdef __clang__
32
#pragma clang diagnostic push
33
#pragma clang diagnostic ignored "-Wunknown-pragmas"
34
#pragma clang diagnostic ignored "-Wdocumentation"
35
#pragma clang diagnostic ignored "-Wold-style-cast"
36
#endif
37
#include "json.h"
38
#ifdef __clang__
39
#pragma clang diagnostic pop
40
#endif
41
#include "ogrlibjsonutils.h"
42
43
// NOTE: keep the below description in sync with doc/source/user/raster_data_model.rst::raster_data_model_rat
44
45
/**
46
 * \class GDALRasterAttributeTable
47
 *
48
 * The GDALRasterAttributeTable (or RAT) class is used to encapsulate a table
49
 * used to provide attribute information about pixel values.  Each row
50
 * in the table applies to a range of pixel values (or a single value in
51
 * some cases), and might have attributes such as the histogram count for
52
 * that range, the color pixels of that range should be drawn names of classes
53
 * or any other generic information.
54
 *
55
 * Raster attribute tables can be used to represent histograms, color tables,
56
 * and classification information.
57
 *
58
 * Each column in a raster attribute table has a name, a type (integer,
59
 * floating point, string, boolean, date time, geometries encoded as WKB),
60
 * and a GDALRATFieldUsage.
61
 * The usage distinguishes columns with particular understood purposes
62
 * (such as color, histogram count, name) and columns that have specific
63
 * purposes not understood by the library (long label,
64
 * suitability_for_growing_wheat, etc).
65
 *
66
 * In the general case each row has a column indicating the minimum pixel
67
 * values falling into that category, and a column indicating the maximum
68
 * pixel value.  These are indicated with usage values of GFU_Min, and
69
 * GFU_Max.  In other cases where each row is a discrete pixel value, one
70
 * column of usage GFU_MinMax can be used.
71
 *
72
 * In other cases all the categories are of equal size and regularly spaced
73
 * and the categorization information can be determined just by knowing the
74
 * value at which the categories start, and the size of a category.  This
75
 * is called "Linear Binning" and the information is kept specially on
76
 * the raster attribute table as a whole.
77
 *
78
 * RATs are normally associated with GDALRasterBands and can be queried
79
 * using the GDALRasterBand::GetDefaultRAT() method.
80
 */
81
82
/************************************************************************/
83
/*                        GDALGetRATFieldTypeName()                     */
84
/************************************************************************/
85
86
/** Return the string representation of a GDALRATFieldType.
87
 *
88
 * @since 3.12
89
 */
90
const char *GDALGetRATFieldTypeName(GDALRATFieldType eType)
91
0
{
92
0
#define CASE_GFT(x)                                                            \
93
0
    case GFT_##x:                                                              \
94
0
        return #x
95
96
0
    switch (eType)
97
0
    {
98
0
        CASE_GFT(Integer);
99
0
        CASE_GFT(String);
100
0
        CASE_GFT(Real);
101
0
        CASE_GFT(Boolean);
102
0
        CASE_GFT(DateTime);
103
0
        case GFT_WKBGeometry:
104
0
            break;
105
0
    }
106
0
    return "WKBGeometry";
107
108
0
#undef CASE_GFT
109
0
}
110
111
/************************************************************************/
112
/*                        GDALGetRATFieldUsageName()                    */
113
/************************************************************************/
114
115
/** Return the string representation of a GDALRATFieldUsage.
116
 *
117
 * @since 3.12
118
 */
119
const char *GDALGetRATFieldUsageName(GDALRATFieldUsage eUsage)
120
0
{
121
0
#define CASE_GFU(x)                                                            \
122
0
    case GFU_##x:                                                              \
123
0
        return #x
124
125
0
    switch (eUsage)
126
0
    {
127
0
        CASE_GFU(Generic);
128
0
        CASE_GFU(PixelCount);
129
0
        CASE_GFU(Name);
130
0
        CASE_GFU(Min);
131
0
        CASE_GFU(Max);
132
0
        CASE_GFU(MinMax);
133
0
        CASE_GFU(Red);
134
0
        CASE_GFU(Green);
135
0
        CASE_GFU(Blue);
136
0
        CASE_GFU(Alpha);
137
0
        CASE_GFU(RedMin);
138
0
        CASE_GFU(GreenMin);
139
0
        CASE_GFU(BlueMin);
140
0
        CASE_GFU(AlphaMin);
141
0
        CASE_GFU(RedMax);
142
0
        CASE_GFU(GreenMax);
143
0
        CASE_GFU(BlueMax);
144
0
        CASE_GFU(AlphaMax);
145
0
        case GFU_MaxCount:
146
0
            break;
147
0
    }
148
0
    return "MaxCount";
149
150
0
#undef CASE_GFU
151
0
}
152
153
/************************************************************************/
154
/*                  ~GDALRasterAttributeTable()                         */
155
/*                                                                      */
156
/*                      Virtual Destructor                              */
157
/************************************************************************/
158
159
0
GDALRasterAttributeTable::~GDALRasterAttributeTable() = default;
160
161
/************************************************************************/
162
/*                              ValuesIO()                              */
163
/*                                                                      */
164
/*                      Default Implementations                         */
165
/************************************************************************/
166
167
/**
168
 * \brief Read or Write a block of doubles to/from the Attribute Table.
169
 *
170
 * This method is the same as the C function GDALRATValuesIOAsDouble().
171
 *
172
 * @param eRWFlag either GF_Read or GF_Write
173
 * @param iField column of the Attribute Table
174
 * @param iStartRow start row to start reading/writing (zero based)
175
 * @param iLength number of rows to read or write
176
 * @param pdfData pointer to array of doubles to read/write. Should be at least
177
 *   iLength long.
178
 *
179
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
180
 *   rows in table.
181
 */
182
183
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
184
                                          int iStartRow, int iLength,
185
                                          double *pdfData)
186
0
{
187
0
    if ((iStartRow + iLength) > GetRowCount())
188
0
    {
189
0
        return CE_Failure;
190
0
    }
191
192
0
    CPLErr eErr = CE_None;
193
0
    if (eRWFlag == GF_Read)
194
0
    {
195
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
196
0
        {
197
0
            pdfData[iIndex - iStartRow] = GetValueAsDouble(iIndex, iField);
198
0
        }
199
0
    }
200
0
    else
201
0
    {
202
0
        for (int iIndex = iStartRow;
203
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
204
0
        {
205
0
            eErr = SetValue(iIndex, iField, pdfData[iIndex - iStartRow]);
206
0
        }
207
0
    }
208
0
    return eErr;
209
0
}
210
211
/************************************************************************/
212
/*                       GDALRATValuesIOAsDouble()                      */
213
/************************************************************************/
214
215
/**
216
 * \brief Read or Write a block of doubles to/from the Attribute Table.
217
 *
218
 * This function is the same as the C++ method
219
 * GDALRasterAttributeTable::ValuesIO()
220
 */
221
CPLErr CPL_STDCALL GDALRATValuesIOAsDouble(GDALRasterAttributeTableH hRAT,
222
                                           GDALRWFlag eRWFlag, int iField,
223
                                           int iStartRow, int iLength,
224
                                           double *pdfData)
225
226
0
{
227
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDouble", CE_Failure);
228
229
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
230
0
        eRWFlag, iField, iStartRow, iLength, pdfData);
231
0
}
232
233
/**
234
 * \brief Read or Write a block of integers to/from the Attribute Table.
235
 *
236
 * This method is the same as the C function GDALRATValuesIOAsInteger().
237
 *
238
 * @param eRWFlag either GF_Read or GF_Write
239
 * @param iField column of the Attribute Table
240
 * @param iStartRow start row to start reading/writing (zero based)
241
 * @param iLength number of rows to read or write
242
 * @param pnData pointer to array of ints to read/write. Should be at least
243
 *     iLength long.
244
 *
245
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
246
 *     rows in table.
247
 */
248
249
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
250
                                          int iStartRow, int iLength,
251
                                          int *pnData)
252
0
{
253
0
    if ((iStartRow + iLength) > GetRowCount())
254
0
    {
255
0
        return CE_Failure;
256
0
    }
257
258
0
    CPLErr eErr = CE_None;
259
0
    if (eRWFlag == GF_Read)
260
0
    {
261
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
262
0
        {
263
0
            pnData[iIndex - iStartRow] = GetValueAsInt(iIndex, iField);
264
0
        }
265
0
    }
266
0
    else
267
0
    {
268
0
        for (int iIndex = iStartRow;
269
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
270
0
        {
271
0
            eErr = SetValue(iIndex, iField, pnData[iIndex - iStartRow]);
272
0
        }
273
0
    }
274
0
    return eErr;
275
0
}
276
277
/************************************************************************/
278
/*                       GDALRATValuesIOAsInteger()                     */
279
/************************************************************************/
280
281
/**
282
 * \brief Read or Write a block of ints to/from the Attribute Table.
283
 *
284
 * This function is the same as the C++ method
285
 * GDALRasterAttributeTable::ValuesIO()
286
 */
287
CPLErr CPL_STDCALL GDALRATValuesIOAsInteger(GDALRasterAttributeTableH hRAT,
288
                                            GDALRWFlag eRWFlag, int iField,
289
                                            int iStartRow, int iLength,
290
                                            int *pnData)
291
292
0
{
293
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsInteger", CE_Failure);
294
295
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
296
0
        eRWFlag, iField, iStartRow, iLength, pnData);
297
0
}
298
299
/**
300
 * \brief Read or Write a block of strings to/from the Attribute Table.
301
 *
302
 * This method is the same as the C function GDALRATValuesIOAsString().
303
 * When reading, papszStrList must be already allocated to the correct size.
304
 * The caller is expected to call CPLFree on each read string.
305
 *
306
 * @param eRWFlag either GF_Read or GF_Write
307
 * @param iField column of the Attribute Table
308
 * @param iStartRow start row to start reading/writing (zero based)
309
 * @param iLength number of rows to read or write
310
 * @param papszStrList pointer to array of strings to read/write. Should be at
311
 *   least iLength long.
312
 *
313
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
314
 *   rows in table.
315
 */
316
317
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
318
                                          int iStartRow, int iLength,
319
                                          char **papszStrList)
320
0
{
321
0
    if ((iStartRow + iLength) > GetRowCount())
322
0
    {
323
0
        return CE_Failure;
324
0
    }
325
326
0
    CPLErr eErr = CE_None;
327
0
    if (eRWFlag == GF_Read)
328
0
    {
329
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
330
0
        {
331
0
            papszStrList[iIndex - iStartRow] =
332
0
                VSIStrdup(GetValueAsString(iIndex, iField));
333
0
        }
334
0
    }
335
0
    else
336
0
    {
337
0
        for (int iIndex = iStartRow;
338
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
339
0
        {
340
0
            eErr = SetValue(iIndex, iField, papszStrList[iIndex - iStartRow]);
341
0
        }
342
0
    }
343
0
    return eErr;
344
0
}
345
346
/************************************************************************/
347
/*                       GDALRATValuesIOAsString()                      */
348
/************************************************************************/
349
350
/**
351
 * \brief Read or Write a block of strings to/from the Attribute Table.
352
 *
353
 * This function is the same as the C++ method
354
 * GDALRasterAttributeTable::ValuesIO()
355
 */
356
CPLErr CPL_STDCALL GDALRATValuesIOAsString(GDALRasterAttributeTableH hRAT,
357
                                           GDALRWFlag eRWFlag, int iField,
358
                                           int iStartRow, int iLength,
359
                                           char **papszStrList)
360
361
0
{
362
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsString", CE_Failure);
363
364
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
365
0
        eRWFlag, iField, iStartRow, iLength, papszStrList);
366
0
}
367
368
/************************************************************************/
369
/*                                ValuesIO()                            */
370
/************************************************************************/
371
372
/**
373
 * \brief Read or Write a block of booleans to/from the Attribute Table.
374
 *
375
 * This method is the same as the C function GDALRATValuesIOAsBoolean().
376
 *
377
 * @param eRWFlag either GF_Read or GF_Write
378
 * @param iField column of the Attribute Table
379
 * @param iStartRow start row to start reading/writing (zero based)
380
 * @param iLength number of rows to read or write
381
 * @param pbData pointer to array of booleans to read/write. Should be at least
382
 *     iLength long.
383
 *
384
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
385
 *     rows in table.
386
 * @since 3.12
387
 */
388
389
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
390
                                          int iStartRow, int iLength,
391
                                          bool *pbData)
392
0
{
393
0
    if ((iStartRow + iLength) > GetRowCount())
394
0
    {
395
0
        return CE_Failure;
396
0
    }
397
398
0
    CPLErr eErr = CE_None;
399
0
    if (eRWFlag == GF_Read)
400
0
    {
401
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
402
0
        {
403
0
            pbData[iIndex - iStartRow] = GetValueAsBoolean(iIndex, iField);
404
0
        }
405
0
    }
406
0
    else
407
0
    {
408
0
        for (int iIndex = iStartRow;
409
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
410
0
        {
411
0
            eErr = SetValue(iIndex, iField, pbData[iIndex - iStartRow]);
412
0
        }
413
0
    }
414
0
    return eErr;
415
0
}
416
417
/************************************************************************/
418
/*                       GDALRATValuesIOAsBoolean()                     */
419
/************************************************************************/
420
421
/**
422
 * \brief Read or Write a block of booleans to/from the Attribute Table.
423
 *
424
 * This function is the same as the C++ method
425
 * GDALRasterAttributeTable::ValuesIO()
426
 *
427
 * @since 3.12
428
 */
429
CPLErr GDALRATValuesIOAsBoolean(GDALRasterAttributeTableH hRAT,
430
                                GDALRWFlag eRWFlag, int iField, int iStartRow,
431
                                int iLength, bool *pbData)
432
433
0
{
434
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsBoolean", CE_Failure);
435
436
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
437
0
        eRWFlag, iField, iStartRow, iLength, pbData);
438
0
}
439
440
/************************************************************************/
441
/*                                ValuesIO()                            */
442
/************************************************************************/
443
444
/**
445
 * \brief Read or Write a block of DateTime to/from the Attribute Table.
446
 *
447
 * This method is the same as the C function GDALRATValuesIOAsDateTime().
448
 *
449
 * @param eRWFlag either GF_Read or GF_Write
450
 * @param iField column of the Attribute Table
451
 * @param iStartRow start row to start reading/writing (zero based)
452
 * @param iLength number of rows to read or write
453
 * @param psDateTime pointer to array of DateTime to read/write. Should be at
454
 *                   least iLength long.
455
 *
456
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
457
 *     rows in table.
458
 * @since 3.12
459
 */
460
461
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
462
                                          int iStartRow, int iLength,
463
                                          GDALRATDateTime *psDateTime)
464
0
{
465
0
    if ((iStartRow + iLength) > GetRowCount())
466
0
    {
467
0
        return CE_Failure;
468
0
    }
469
470
0
    CPLErr eErr = CE_None;
471
0
    if (eRWFlag == GF_Read)
472
0
    {
473
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
474
0
        {
475
0
            psDateTime[iIndex - iStartRow] = GetValueAsDateTime(iIndex, iField);
476
0
        }
477
0
    }
478
0
    else
479
0
    {
480
0
        for (int iIndex = iStartRow;
481
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
482
0
        {
483
0
            eErr = SetValue(iIndex, iField, psDateTime[iIndex - iStartRow]);
484
0
        }
485
0
    }
486
0
    return eErr;
487
0
}
488
489
/************************************************************************/
490
/*                       GDALRATValuesIOAsDateTime()                    */
491
/************************************************************************/
492
493
/**
494
 * \brief Read or Write a block of date-times to/from the Attribute Table.
495
 *
496
 * This function is the same as the C++ method
497
 * GDALRasterAttributeTable::ValuesIO()
498
 *
499
 * @since 3.12
500
 */
501
CPLErr GDALRATValuesIOAsDateTime(GDALRasterAttributeTableH hRAT,
502
                                 GDALRWFlag eRWFlag, int iField, int iStartRow,
503
                                 int iLength, GDALRATDateTime *psDateTime)
504
505
0
{
506
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsDateTime", CE_Failure);
507
508
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
509
0
        eRWFlag, iField, iStartRow, iLength, psDateTime);
510
0
}
511
512
/************************************************************************/
513
/*                                ValuesIO()                            */
514
/************************************************************************/
515
516
/**
517
 * \brief Read or Write a block of WKB-encoded geometries to/from the Attribute Table.
518
 *
519
 * When reading, each ppabyWKB[] should be CPLFree'd() after use.
520
 *
521
 * This method is the same as the C function GDALRATValuesIOAsWKBGeometry().
522
 *
523
 * @param eRWFlag either GF_Read or GF_Write
524
 * @param iField column of the Attribute Table
525
 * @param iStartRow start row to start reading/writing (zero based)
526
 * @param iLength number of rows to read or write
527
 * @param ppabyWKB pointer to array of pointer of WKB-encoded geometries to
528
 *                 read/write. Should be at least iLength long.
529
 * @param pnWKBSize pointer to array of WKB size.
530
 *                  Should be at least iLength long.
531
 *
532
 * @return CE_None or CE_Failure if iStartRow + iLength greater than number of
533
 *     rows in table.
534
 * @since 3.12
535
 */
536
537
CPLErr GDALRasterAttributeTable::ValuesIO(GDALRWFlag eRWFlag, int iField,
538
                                          int iStartRow, int iLength,
539
                                          GByte **ppabyWKB, size_t *pnWKBSize)
540
0
{
541
0
    if ((iStartRow + iLength) > GetRowCount())
542
0
    {
543
0
        return CE_Failure;
544
0
    }
545
546
0
    CPLErr eErr = CE_None;
547
0
    if (eRWFlag == GF_Read)
548
0
    {
549
0
        for (int iIndex = iStartRow; iIndex < (iStartRow + iLength); iIndex++)
550
0
        {
551
0
            size_t nSize = 0;
552
0
            const GByte *pabyWKB = GetValueAsWKBGeometry(iIndex, iField, nSize);
553
0
            pnWKBSize[iIndex - iStartRow] = nSize;
554
0
            if (nSize)
555
0
            {
556
0
                ppabyWKB[iIndex - iStartRow] =
557
0
                    static_cast<GByte *>(CPLMalloc(nSize));
558
0
                memcpy(ppabyWKB[iIndex - iStartRow], pabyWKB, nSize);
559
0
            }
560
0
            else
561
0
            {
562
0
                ppabyWKB[iIndex - iStartRow] = nullptr;
563
0
            }
564
0
        }
565
0
    }
566
0
    else
567
0
    {
568
0
        for (int iIndex = iStartRow;
569
0
             eErr == CE_None && iIndex < (iStartRow + iLength); iIndex++)
570
0
        {
571
0
            eErr = SetValue(iIndex, iField, ppabyWKB[iIndex - iStartRow],
572
0
                            pnWKBSize[iIndex - iStartRow]);
573
0
        }
574
0
    }
575
0
    return eErr;
576
0
}
577
578
/************************************************************************/
579
/*                     GDALRATValuesIOAsWKBGeometry()                   */
580
/************************************************************************/
581
582
/**
583
 * \brief Read or Write a block of WKB-encoded geometries to/from the Attribute Table.
584
 *
585
 * When reading, each ppabyWKB[] should be CPLFree'd() after use.
586
 *
587
 * This function is the same as the C++ method
588
 * GDALRasterAttributeTable::ValuesIO()
589
 *
590
 * @since 3.12
591
 */
592
CPLErr GDALRATValuesIOAsWKBGeometry(GDALRasterAttributeTableH hRAT,
593
                                    GDALRWFlag eRWFlag, int iField,
594
                                    int iStartRow, int iLength,
595
                                    GByte **ppabyWKB, size_t *pnWKBSize)
596
597
0
{
598
0
    VALIDATE_POINTER1(hRAT, "GDALRATValuesIOAsWKBGeometry", CE_Failure);
599
600
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->ValuesIO(
601
0
        eRWFlag, iField, iStartRow, iLength, ppabyWKB, pnWKBSize);
602
0
}
603
604
//! @cond Doxygen_Suppress
605
606
/************************************************************************/
607
/*                   ValuesIOBooleanFromIntoInt()                       */
608
/************************************************************************/
609
610
CPLErr GDALRasterAttributeTable::ValuesIOBooleanFromIntoInt(
611
    GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength, bool *pbData)
612
0
{
613
0
    if (eRWFlag == GF_Read)
614
0
    {
615
0
        std::vector<int> anData(iLength);
616
0
        CPLErr eErr =
617
0
            ValuesIO(eRWFlag, iField, iStartRow, iLength, anData.data());
618
0
        if (eErr == CE_None)
619
0
        {
620
0
            for (int i = 0; i < iLength; ++i)
621
0
            {
622
0
                pbData[i] = anData[i] != 0;
623
0
            }
624
0
        }
625
0
        return eErr;
626
0
    }
627
0
    else
628
0
    {
629
0
        std::vector<int> anData;
630
0
        anData.reserve(iLength);
631
0
        for (int i = 0; i < iLength; ++i)
632
0
            anData.push_back(pbData[i]);
633
0
        return ValuesIO(eRWFlag, iField, iStartRow, iLength, anData.data());
634
0
    }
635
0
}
636
637
/************************************************************************/
638
/*                          DateTimeToString()                          */
639
/************************************************************************/
640
641
/* static */
642
std::string
643
GDALRasterAttributeTable::DateTimeToString(const GDALRATDateTime &sDateTime)
644
0
{
645
0
    if (!sDateTime.bIsValid)
646
0
        return std::string();
647
0
    return CPLString().Printf(
648
0
        "%04d-%02d-%02dT%02d:%02d:%06.3f%c%02d:%02d", sDateTime.nYear,
649
0
        sDateTime.nMonth, sDateTime.nDay, sDateTime.nHour, sDateTime.nMinute,
650
0
        static_cast<double>(sDateTime.fSecond),
651
0
        sDateTime.bPositiveTimeZone ? '+' : '-', sDateTime.nTimeZoneHour,
652
0
        sDateTime.nTimeZoneMinute);
653
0
}
654
655
/************************************************************************/
656
/*                           StringToDateTime()                         */
657
/************************************************************************/
658
659
/* static */
660
bool GDALRasterAttributeTable::StringToDateTime(const char *pszStr,
661
                                                GDALRATDateTime &sDateTime)
662
0
{
663
0
    OGRField sField;
664
0
    if (OGRParseDate(pszStr, &sField, 0))
665
0
    {
666
0
        sDateTime.nYear = sField.Date.Year;
667
0
        sDateTime.nMonth = sField.Date.Month;
668
0
        sDateTime.nDay = sField.Date.Day;
669
0
        sDateTime.nHour = sField.Date.Hour;
670
0
        sDateTime.nMinute = sField.Date.Minute;
671
0
        sDateTime.fSecond = sField.Date.Second;
672
0
        sDateTime.bPositiveTimeZone =
673
0
            sField.Date.TZFlag <= 2 ? false : sField.Date.TZFlag >= 100;
674
0
        sDateTime.nTimeZoneHour = sField.Date.TZFlag <= 2
675
0
                                      ? 0
676
0
                                      : std::abs(sField.Date.TZFlag - 100) / 4;
677
0
        sDateTime.nTimeZoneMinute =
678
0
            sField.Date.TZFlag <= 2
679
0
                ? 0
680
0
                : (std::abs(sField.Date.TZFlag - 100) % 4) * 15;
681
0
        sDateTime.bIsValid = true;
682
0
        return true;
683
0
    }
684
0
    else
685
0
    {
686
0
        sDateTime = GDALRATDateTime();
687
0
        return false;
688
0
    }
689
0
}
690
691
/************************************************************************/
692
/*                  ValuesIODateTimeFromIntoString()                    */
693
/************************************************************************/
694
695
CPLErr GDALRasterAttributeTable::ValuesIODateTimeFromIntoString(
696
    GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
697
    GDALRATDateTime *psDateTime)
698
0
{
699
0
    if (eRWFlag == GF_Read)
700
0
    {
701
0
        std::vector<char *> apszStrList(iLength);
702
0
        CPLErr eErr =
703
0
            ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStrList.data());
704
0
        if (eErr == CE_None)
705
0
        {
706
0
            for (int i = 0; i < iLength; ++i)
707
0
            {
708
0
                StringToDateTime(apszStrList[i], psDateTime[i]);
709
0
            }
710
0
        }
711
0
        for (int i = 0; i < iLength; ++i)
712
0
            VSIFree(apszStrList[i]);
713
0
        return eErr;
714
0
    }
715
0
    else
716
0
    {
717
0
        std::vector<std::string> asStr;
718
0
        std::vector<char *> apszStr;
719
0
        asStr.reserve(iLength);
720
0
        apszStr.reserve(iLength);
721
0
        for (int i = 0; i < iLength; ++i)
722
0
        {
723
0
            asStr.push_back(DateTimeToString(psDateTime[i]));
724
0
            apszStr.push_back(asStr.back().data());
725
0
        }
726
0
        return ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStr.data());
727
0
    }
728
0
}
729
730
/************************************************************************/
731
/*                          WKBGeometryToWKT()                          */
732
/************************************************************************/
733
734
/* static */
735
std::string GDALRasterAttributeTable::WKBGeometryToWKT(const void *pabyWKB,
736
                                                       size_t nWKBSize)
737
0
{
738
0
    std::string osWKT;
739
0
    if (nWKBSize)
740
0
    {
741
0
        OGRGeometry *poGeometry = nullptr;
742
0
        if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeometry,
743
0
                                              nWKBSize,
744
0
                                              wkbVariantIso) == OGRERR_NONE)
745
0
        {
746
0
            osWKT = poGeometry->exportToWkt();
747
0
        }
748
0
        delete poGeometry;
749
0
    }
750
0
    return osWKT;
751
0
}
752
753
/************************************************************************/
754
/*                          WKTGeometryToWKB()                          */
755
/************************************************************************/
756
757
/* static */
758
std::vector<GByte>
759
GDALRasterAttributeTable::WKTGeometryToWKB(const char *pszWKT)
760
0
{
761
0
    std::vector<GByte> abyWKB;
762
0
    OGRGeometry *poGeom = nullptr;
763
0
    if (pszWKT[0] && OGRGeometryFactory::createFromWkt(pszWKT, nullptr,
764
0
                                                       &poGeom) == OGRERR_NONE)
765
0
    {
766
0
        const size_t nWKBSize = poGeom->WkbSize();
767
0
        abyWKB.resize(nWKBSize);
768
0
        poGeom->exportToWkb(wkbNDR, abyWKB.data(), wkbVariantIso);
769
0
    }
770
0
    delete poGeom;
771
0
    return abyWKB;
772
0
}
773
774
/************************************************************************/
775
/*                     ValuesIOWKBGeometryFromIntoString()              */
776
/************************************************************************/
777
778
CPLErr GDALRasterAttributeTable::ValuesIOWKBGeometryFromIntoString(
779
    GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
780
    GByte **ppabyWKB, size_t *pnWKBSize)
781
0
{
782
0
    if (eRWFlag == GF_Read)
783
0
    {
784
0
        std::vector<char *> apszStrList(iLength);
785
0
        CPLErr eErr =
786
0
            ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStrList.data());
787
0
        if (eErr == CE_None)
788
0
        {
789
0
            for (int i = 0; i < iLength; ++i)
790
0
            {
791
0
                auto abyWKB = WKTGeometryToWKB(apszStrList[i]);
792
0
                if (abyWKB.empty())
793
0
                {
794
0
                    ppabyWKB[i] = nullptr;
795
0
                    pnWKBSize[i] = 0;
796
0
                }
797
0
                else
798
0
                {
799
0
                    ppabyWKB[i] =
800
0
                        static_cast<GByte *>(CPLMalloc(abyWKB.size()));
801
0
                    memcpy(ppabyWKB[i], abyWKB.data(), abyWKB.size());
802
0
                    pnWKBSize[i] = abyWKB.size();
803
0
                }
804
0
            }
805
0
        }
806
0
        for (int i = 0; i < iLength; ++i)
807
0
            VSIFree(apszStrList[i]);
808
0
        return eErr;
809
0
    }
810
0
    else
811
0
    {
812
0
        std::vector<std::string> asStr;
813
0
        std::vector<char *> apszStr;
814
0
        asStr.reserve(iLength);
815
0
        apszStr.reserve(iLength);
816
0
        for (int i = 0; i < iLength; ++i)
817
0
        {
818
0
            asStr.push_back(WKBGeometryToWKT(ppabyWKB[i], pnWKBSize[i]));
819
0
            apszStr.push_back(asStr.back().data());
820
0
        }
821
0
        return ValuesIO(eRWFlag, iField, iStartRow, iLength, apszStr.data());
822
0
    }
823
0
}
824
825
//! @endcond
826
827
/************************************************************************/
828
/*                            SetRowCount()                             */
829
/************************************************************************/
830
831
/**
832
 * \brief Set row count.
833
 *
834
 * Resizes the table to include the indicated number of rows.  Newly created
835
 * rows will be initialized to their default values - "" for strings,
836
 * and zero for numeric fields.
837
 *
838
 * This method is the same as the C function GDALRATSetRowCount().
839
 *
840
 * @param nNewCount the new number of rows.
841
 */
842
843
void GDALRasterAttributeTable::SetRowCount(CPL_UNUSED int nNewCount)
844
0
{
845
0
}
846
847
/************************************************************************/
848
/*                         GDALRATSetRowCount()                         */
849
/************************************************************************/
850
851
/**
852
 * \brief Set row count.
853
 *
854
 * This function is the same as the C++ method
855
 * GDALRasterAttributeTable::SetRowCount()
856
 *
857
 * @param hRAT RAT handle.
858
 * @param nNewCount the new number of rows.
859
 */
860
void CPL_STDCALL GDALRATSetRowCount(GDALRasterAttributeTableH hRAT,
861
                                    int nNewCount)
862
863
0
{
864
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetRowCount");
865
866
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetRowCount(nNewCount);
867
0
}
868
869
/************************************************************************/
870
/*                           GetRowOfValue()                            */
871
/************************************************************************/
872
873
/**
874
 * \fn GDALRasterAttributeTable::GetRowOfValue(double) const
875
 * \brief Get row for pixel value.
876
 *
877
 * Given a raw pixel value, the raster attribute table is scanned to
878
 * determine which row in the table applies to the pixel value.  The
879
 * row index is returned.
880
 *
881
 * This method is the same as the C function GDALRATGetRowOfValue().
882
 *
883
 * @param dfValue the pixel value.
884
 *
885
 * @return the row index or -1 if no row is appropriate.
886
 */
887
888
/**/
889
/**/
890
891
int GDALRasterAttributeTable::GetRowOfValue(double /* dfValue */) const
892
0
{
893
0
    return -1;
894
0
}
895
896
/************************************************************************/
897
/*                        GDALRATGetRowOfValue()                        */
898
/************************************************************************/
899
900
/**
901
 * \brief Get row for pixel value.
902
 *
903
 * This function is the same as the C++ method
904
 * GDALRasterAttributeTable::GetRowOfValue()
905
 */
906
int CPL_STDCALL GDALRATGetRowOfValue(GDALRasterAttributeTableH hRAT,
907
                                     double dfValue)
908
909
0
{
910
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetRowOfValue", 0);
911
912
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowOfValue(dfValue);
913
0
}
914
915
/************************************************************************/
916
/*                           GetRowOfValue()                            */
917
/************************************************************************/
918
919
/**
920
 * \brief Get row for pixel value.
921
 *
922
 * Given a raw pixel value, the raster attribute table is scanned to
923
 * determine which row in the table applies to the pixel value.  The
924
 * row index is returned.
925
 *
926
 * Int arg for now just converted to double.  Perhaps we will
927
 * handle this in a special way some day?
928
 *
929
 * This method is the same as the C function GDALRATGetRowOfValue().
930
 *
931
 * @param nValue the pixel value.
932
 *
933
 * @return the row index or -1 if no row is appropriate.
934
 */
935
936
int GDALRasterAttributeTable::GetRowOfValue(int nValue) const
937
938
0
{
939
0
    return GetRowOfValue(static_cast<double>(nValue));
940
0
}
941
942
/************************************************************************/
943
/*                            CreateColumn()                            */
944
/************************************************************************/
945
946
/**
947
 * \fn GDALRasterAttributeTable::CreateColumn(const char*, GDALRATFieldType,
948
 * GDALRATFieldUsage) \brief Create new column.
949
 *
950
 * If the table already has rows, all row values for the new column will
951
 * be initialized to the default value ("", or zero).  The new column is
952
 * always created as the last column, and will be column (field)
953
 * "GetColumnCount()-1" after CreateColumn() has completed successfully.
954
 *
955
 * This method is the same as the C function GDALRATCreateColumn().
956
 *
957
 * @param pszFieldName the name of the field to create.
958
 * @param eFieldType the field type (integer, double or string).
959
 * @param eFieldUsage the field usage, GFU_Generic if not known.
960
 *
961
 * @return CE_None on success or CE_Failure if something goes wrong.
962
 */
963
964
/**/
965
/**/
966
967
CPLErr
968
GDALRasterAttributeTable::CreateColumn(const char * /* pszFieldName */,
969
                                       GDALRATFieldType /* eFieldType */,
970
                                       GDALRATFieldUsage /* eFieldUsage */)
971
0
{
972
0
    return CE_Failure;
973
0
}
974
975
/************************************************************************/
976
/*                        GDALRATCreateColumn()                         */
977
/************************************************************************/
978
979
/**
980
 * \brief Create new column.
981
 *
982
 * This function is the same as the C++ method
983
 * GDALRasterAttributeTable::CreateColumn()
984
 */
985
CPLErr CPL_STDCALL GDALRATCreateColumn(GDALRasterAttributeTableH hRAT,
986
                                       const char *pszFieldName,
987
                                       GDALRATFieldType eFieldType,
988
                                       GDALRATFieldUsage eFieldUsage)
989
990
0
{
991
0
    VALIDATE_POINTER1(hRAT, "GDALRATCreateColumn", CE_Failure);
992
993
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->CreateColumn(
994
0
        pszFieldName, eFieldType, eFieldUsage);
995
0
}
996
997
/************************************************************************/
998
/*                          SetLinearBinning()                          */
999
/************************************************************************/
1000
1001
/**
1002
 * \brief Set linear binning information.
1003
 *
1004
 * For RATs with equal sized categories (in pixel value space) that are
1005
 * evenly spaced, this method may be used to associate the linear binning
1006
 * information with the table.
1007
 *
1008
 * This method is the same as the C function GDALRATSetLinearBinning().
1009
 *
1010
 * @param dfRow0MinIn the lower bound (pixel value) of the first category.
1011
 * @param dfBinSizeIn the width of each category (in pixel value units).
1012
 *
1013
 * @return CE_None on success or CE_Failure on failure.
1014
 */
1015
1016
CPLErr GDALRasterAttributeTable::SetLinearBinning(CPL_UNUSED double dfRow0MinIn,
1017
                                                  CPL_UNUSED double dfBinSizeIn)
1018
0
{
1019
0
    return CE_Failure;
1020
0
}
1021
1022
/************************************************************************/
1023
/*                      GDALRATSetLinearBinning()                       */
1024
/************************************************************************/
1025
1026
/**
1027
 * \brief Set linear binning information.
1028
 *
1029
 * This function is the same as the C++ method
1030
 * GDALRasterAttributeTable::SetLinearBinning()
1031
 */
1032
CPLErr CPL_STDCALL GDALRATSetLinearBinning(GDALRasterAttributeTableH hRAT,
1033
                                           double dfRow0Min, double dfBinSize)
1034
1035
0
{
1036
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetLinearBinning", CE_Failure);
1037
1038
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SetLinearBinning(
1039
0
        dfRow0Min, dfBinSize);
1040
0
}
1041
1042
/************************************************************************/
1043
/*                          GetLinearBinning()                          */
1044
/************************************************************************/
1045
1046
/**
1047
 * \brief Get linear binning information.
1048
 *
1049
 * Returns linear binning information if any is associated with the RAT.
1050
 *
1051
 * This method is the same as the C function GDALRATGetLinearBinning().
1052
 *
1053
 * @param pdfRow0Min (out) the lower bound (pixel value) of the first category.
1054
 * @param pdfBinSize (out) the width of each category (in pixel value units).
1055
 *
1056
 * @return TRUE if linear binning information exists or FALSE if there is none.
1057
 */
1058
1059
int GDALRasterAttributeTable::GetLinearBinning(
1060
    CPL_UNUSED double *pdfRow0Min, CPL_UNUSED double *pdfBinSize) const
1061
0
{
1062
0
    return false;
1063
0
}
1064
1065
/************************************************************************/
1066
/*                      GDALRATGetLinearBinning()                       */
1067
/************************************************************************/
1068
1069
/**
1070
 * \brief Get linear binning information.
1071
 *
1072
 * This function is the same as the C++ method
1073
 * GDALRasterAttributeTable::GetLinearBinning()
1074
 */
1075
int CPL_STDCALL GDALRATGetLinearBinning(GDALRasterAttributeTableH hRAT,
1076
                                        double *pdfRow0Min, double *pdfBinSize)
1077
1078
0
{
1079
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetLinearBinning", 0);
1080
1081
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetLinearBinning(
1082
0
        pdfRow0Min, pdfBinSize);
1083
0
}
1084
1085
/************************************************************************/
1086
/*                        GDALRATGetTableType()                         */
1087
/************************************************************************/
1088
1089
/**
1090
 * \brief Get Rat Table Type
1091
 *
1092
 *
1093
 * This function is the same as the C++ method
1094
 * GDALRasterAttributeTable::GetTableType()
1095
 */
1096
GDALRATTableType CPL_STDCALL GDALRATGetTableType(GDALRasterAttributeTableH hRAT)
1097
0
{
1098
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetTableType", GRTT_THEMATIC);
1099
1100
0
    return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->GetTableType();
1101
0
}
1102
1103
/************************************************************************/
1104
/*                        GDALRATSetTableType()                         */
1105
/************************************************************************/
1106
1107
/**
1108
 * \brief Set RAT Table Type
1109
 *
1110
 *
1111
 * This function is the same as the C++ method
1112
 * GDALRasterAttributeTable::SetTableType()
1113
 */
1114
CPLErr CPL_STDCALL GDALRATSetTableType(GDALRasterAttributeTableH hRAT,
1115
                                       const GDALRATTableType eInTableType)
1116
1117
0
{
1118
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetTableType", CE_Failure);
1119
1120
0
    return GDALDefaultRasterAttributeTable::FromHandle(hRAT)->SetTableType(
1121
0
        eInTableType);
1122
0
}
1123
1124
/************************************************************************/
1125
/*                             Serialize()                              */
1126
/************************************************************************/
1127
1128
/** Serialize as a XML tree.
1129
 * @return XML tree.
1130
 */
1131
CPLXMLNode *GDALRasterAttributeTable::Serialize() const
1132
1133
0
{
1134
0
    if ((GetColumnCount() == 0) && (GetRowCount() == 0))
1135
0
        return nullptr;
1136
1137
0
    CPLXMLNode *psTree =
1138
0
        CPLCreateXMLNode(nullptr, CXT_Element, "GDALRasterAttributeTable");
1139
1140
    /* -------------------------------------------------------------------- */
1141
    /*      Add attributes with regular binning info if appropriate.        */
1142
    /* -------------------------------------------------------------------- */
1143
0
    char szValue[128] = {'\0'};
1144
0
    double dfRow0Min = 0.0;
1145
0
    double dfBinSize = 0.0;
1146
1147
0
    if (GetLinearBinning(&dfRow0Min, &dfBinSize))
1148
0
    {
1149
0
        CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfRow0Min);
1150
0
        CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "Row0Min"),
1151
0
                         CXT_Text, szValue);
1152
1153
0
        CPLsnprintf(szValue, sizeof(szValue), "%.16g", dfBinSize);
1154
0
        CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "BinSize"),
1155
0
                         CXT_Text, szValue);
1156
0
    }
1157
1158
    /* -------------------------------------------------------------------- */
1159
    /*      Store table type                                                */
1160
    /* -------------------------------------------------------------------- */
1161
0
    const GDALRATTableType tableType = GetTableType();
1162
0
    if (tableType == GRTT_ATHEMATIC)
1163
0
    {
1164
0
        CPLsnprintf(szValue, sizeof(szValue), "athematic");
1165
0
    }
1166
0
    else
1167
0
    {
1168
0
        CPLsnprintf(szValue, sizeof(szValue), "thematic");
1169
0
    }
1170
0
    CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "tableType"),
1171
0
                     CXT_Text, szValue);
1172
1173
    /* -------------------------------------------------------------------- */
1174
    /*      Define each column.                                             */
1175
    /* -------------------------------------------------------------------- */
1176
0
    const int iColCount = GetColumnCount();
1177
1178
0
    for (int iCol = 0; iCol < iColCount; iCol++)
1179
0
    {
1180
0
        CPLXMLNode *psCol = CPLCreateXMLNode(psTree, CXT_Element, "FieldDefn");
1181
1182
0
        snprintf(szValue, sizeof(szValue), "%d", iCol);
1183
0
        CPLCreateXMLNode(CPLCreateXMLNode(psCol, CXT_Attribute, "index"),
1184
0
                         CXT_Text, szValue);
1185
1186
0
        CPLCreateXMLElementAndValue(psCol, "Name", GetNameOfCol(iCol));
1187
1188
0
        snprintf(szValue, sizeof(szValue), "%d",
1189
0
                 static_cast<int>(GetTypeOfCol(iCol)));
1190
0
        CPLXMLNode *psType =
1191
0
            CPLCreateXMLElementAndValue(psCol, "Type", szValue);
1192
0
        CPLAddXMLAttributeAndValue(psType, "typeAsString",
1193
0
                                   GDALGetRATFieldTypeName(GetTypeOfCol(iCol)));
1194
1195
0
        snprintf(szValue, sizeof(szValue), "%d",
1196
0
                 static_cast<int>(GetUsageOfCol(iCol)));
1197
0
        CPLXMLNode *psUsage =
1198
0
            CPLCreateXMLElementAndValue(psCol, "Usage", szValue);
1199
0
        CPLAddXMLAttributeAndValue(
1200
0
            psUsage, "usageAsString",
1201
0
            GDALGetRATFieldUsageName(GetUsageOfCol(iCol)));
1202
0
    }
1203
1204
    /* -------------------------------------------------------------------- */
1205
    /*      Write out each row.                                             */
1206
    /* -------------------------------------------------------------------- */
1207
0
    const int iRowCount = GetRowCount();
1208
0
    CPLXMLNode *psTail = nullptr;
1209
0
    CPLXMLNode *psRow = nullptr;
1210
1211
0
    for (int iRow = 0; iRow < iRowCount; iRow++)
1212
0
    {
1213
0
        psRow = CPLCreateXMLNode(nullptr, CXT_Element, "Row");
1214
0
        if (psTail == nullptr)
1215
0
            CPLAddXMLChild(psTree, psRow);
1216
0
        else
1217
0
            psTail->psNext = psRow;
1218
0
        psTail = psRow;
1219
1220
0
        snprintf(szValue, sizeof(szValue), "%d", iRow);
1221
0
        CPLCreateXMLNode(CPLCreateXMLNode(psRow, CXT_Attribute, "index"),
1222
0
                         CXT_Text, szValue);
1223
1224
0
        std::string osStr;
1225
0
        for (int iCol = 0; iCol < iColCount; iCol++)
1226
0
        {
1227
0
            const char *pszValue = szValue;
1228
1229
0
            switch (GetTypeOfCol(iCol))
1230
0
            {
1231
0
                case GFT_Integer:
1232
0
                    snprintf(szValue, sizeof(szValue), "%d",
1233
0
                             GetValueAsInt(iRow, iCol));
1234
0
                    break;
1235
1236
0
                case GFT_Real:
1237
0
                    CPLsnprintf(szValue, sizeof(szValue), "%.16g",
1238
0
                                GetValueAsDouble(iRow, iCol));
1239
0
                    break;
1240
1241
0
                case GFT_String:
1242
0
                    pszValue = GetValueAsString(iRow, iCol);
1243
0
                    break;
1244
1245
0
                case GFT_Boolean:
1246
0
                    pszValue = GetValueAsBoolean(iRow, iCol) ? "true" : "false";
1247
0
                    break;
1248
1249
0
                case GFT_DateTime:
1250
0
                    osStr = DateTimeToString(GetValueAsDateTime(iRow, iCol));
1251
0
                    pszValue = osStr.c_str();
1252
0
                    break;
1253
1254
0
                case GFT_WKBGeometry:
1255
0
                {
1256
0
                    size_t nWKBSize = 0;
1257
0
                    const GByte *pabyWKB =
1258
0
                        GetValueAsWKBGeometry(iRow, iCol, nWKBSize);
1259
0
                    osStr = WKBGeometryToWKT(pabyWKB, nWKBSize);
1260
0
                    pszValue = osStr.c_str();
1261
0
                    break;
1262
0
                }
1263
0
            }
1264
1265
0
            CPLCreateXMLElementAndValue(psRow, "F", pszValue);
1266
0
        }
1267
0
    }
1268
1269
0
    return psTree;
1270
0
}
1271
1272
/************************************************************************/
1273
/*                             SerializeJSON()                           */
1274
/************************************************************************/
1275
1276
/** Serialize as a JSON object.
1277
 * @return JSON object (of type json_object*)
1278
 */
1279
void *GDALRasterAttributeTable::SerializeJSON() const
1280
1281
0
{
1282
0
    json_object *poRAT = json_object_new_object();
1283
1284
0
    if ((GetColumnCount() == 0) && (GetRowCount() == 0))
1285
0
        return poRAT;
1286
1287
    /* -------------------------------------------------------------------- */
1288
    /*      Add attributes with regular binning info if appropriate.        */
1289
    /* -------------------------------------------------------------------- */
1290
0
    double dfRow0Min = 0.0;
1291
0
    double dfBinSize = 0.0;
1292
0
    json_object *poRow0Min = nullptr;
1293
0
    json_object *poBinSize = nullptr;
1294
0
    json_object *poTableType = nullptr;
1295
1296
0
    if (GetLinearBinning(&dfRow0Min, &dfBinSize))
1297
0
    {
1298
0
        poRow0Min = json_object_new_double_with_precision(dfRow0Min, 16);
1299
0
        json_object_object_add(poRAT, "row0Min", poRow0Min);
1300
1301
0
        poBinSize = json_object_new_double_with_precision(dfBinSize, 16);
1302
0
        json_object_object_add(poRAT, "binSize", poBinSize);
1303
0
    }
1304
1305
    /* -------------------------------------------------------------------- */
1306
    /*      Table Type                                                      */
1307
    /* -------------------------------------------------------------------- */
1308
0
    const GDALRATTableType tableType = GetTableType();
1309
0
    if (tableType == GRTT_ATHEMATIC)
1310
0
    {
1311
0
        poTableType = json_object_new_string("athematic");
1312
0
    }
1313
0
    else
1314
0
    {
1315
0
        poTableType = json_object_new_string("thematic");
1316
0
    }
1317
0
    json_object_object_add(poRAT, "tableType", poTableType);
1318
1319
    /* -------------------------------------------------------------------- */
1320
    /*      Define each column.                                             */
1321
    /* -------------------------------------------------------------------- */
1322
0
    const int iColCount = GetColumnCount();
1323
0
    json_object *poFieldDefnArray = json_object_new_array();
1324
1325
0
    for (int iCol = 0; iCol < iColCount; iCol++)
1326
0
    {
1327
0
        json_object *const poFieldDefn = json_object_new_object();
1328
1329
0
        json_object *const poColumnIndex = json_object_new_int(iCol);
1330
0
        json_object_object_add(poFieldDefn, "index", poColumnIndex);
1331
1332
0
        json_object *const poName = json_object_new_string(GetNameOfCol(iCol));
1333
0
        json_object_object_add(poFieldDefn, "name", poName);
1334
1335
0
        json_object *const poType =
1336
0
            json_object_new_int(static_cast<int>(GetTypeOfCol(iCol)));
1337
0
        json_object_object_add(poFieldDefn, "type", poType);
1338
1339
0
        json_object *const poUsage =
1340
0
            json_object_new_int(static_cast<int>(GetUsageOfCol(iCol)));
1341
0
        json_object_object_add(poFieldDefn, "usage", poUsage);
1342
1343
0
        json_object_array_add(poFieldDefnArray, poFieldDefn);
1344
0
    }
1345
1346
0
    json_object_object_add(poRAT, "fieldDefn", poFieldDefnArray);
1347
1348
    /* -------------------------------------------------------------------- */
1349
    /*      Write out each row.                                             */
1350
    /* -------------------------------------------------------------------- */
1351
0
    const int iRowCount = GetRowCount();
1352
0
    json_object *poRowArray = json_object_new_array();
1353
1354
0
    for (int iRow = 0; iRow < iRowCount; iRow++)
1355
0
    {
1356
0
        json_object *const poRow = json_object_new_object();
1357
1358
0
        json_object *const poRowIndex = json_object_new_int(iRow);
1359
0
        json_object_object_add(poRow, "index", poRowIndex);
1360
1361
0
        json_object *const poFArray = json_object_new_array();
1362
1363
0
        for (int iCol = 0; iCol < iColCount; iCol++)
1364
0
        {
1365
0
            json_object *poF = nullptr;
1366
0
            switch (GetTypeOfCol(iCol))
1367
0
            {
1368
0
                case GFT_Integer:
1369
0
                    poF = json_object_new_int(GetValueAsInt(iRow, iCol));
1370
0
                    break;
1371
1372
0
                case GFT_Real:
1373
0
                    poF = json_object_new_double_with_precision(
1374
0
                        GetValueAsDouble(iRow, iCol), 16);
1375
0
                    break;
1376
1377
0
                case GFT_String:
1378
0
                    poF = json_object_new_string(GetValueAsString(iRow, iCol));
1379
0
                    break;
1380
1381
0
                case GFT_Boolean:
1382
0
                    poF =
1383
0
                        json_object_new_boolean(GetValueAsBoolean(iRow, iCol));
1384
0
                    break;
1385
1386
0
                case GFT_DateTime:
1387
0
                case GFT_WKBGeometry:
1388
0
                {
1389
0
                    const char *pszV = GetValueAsString(iRow, iCol);
1390
0
                    if (pszV[0])
1391
0
                        poF = json_object_new_string(pszV);
1392
0
                    break;
1393
0
                }
1394
0
            }
1395
1396
0
            json_object_array_add(poFArray, poF);
1397
0
        }
1398
0
        json_object_object_add(poRow, "f", poFArray);
1399
0
        json_object_array_add(poRowArray, poRow);
1400
0
    }
1401
0
    json_object_object_add(poRAT, "row", poRowArray);
1402
1403
0
    return poRAT;
1404
0
}
1405
1406
/************************************************************************/
1407
/*                              XMLInit()                               */
1408
/************************************************************************/
1409
1410
/** Deserialize from XML.
1411
 * @param psTree XML tree
1412
 * @return error code.
1413
 */
1414
CPLErr GDALRasterAttributeTable::XMLInit(const CPLXMLNode *psTree,
1415
                                         const char * /*pszVRTPath*/)
1416
1417
0
{
1418
0
    CPLAssert(GetRowCount() == 0 && GetColumnCount() == 0);
1419
1420
    /* -------------------------------------------------------------------- */
1421
    /*      Linear binning.                                                 */
1422
    /* -------------------------------------------------------------------- */
1423
0
    if (CPLGetXMLValue(psTree, "Row0Min", nullptr) &&
1424
0
        CPLGetXMLValue(psTree, "BinSize", nullptr))
1425
0
    {
1426
0
        SetLinearBinning(CPLAtof(CPLGetXMLValue(psTree, "Row0Min", "")),
1427
0
                         CPLAtof(CPLGetXMLValue(psTree, "BinSize", "")));
1428
0
    }
1429
1430
    /* -------------------------------------------------------------------- */
1431
    /*      Table Type                                                      */
1432
    /* -------------------------------------------------------------------- */
1433
0
    if (CPLGetXMLValue(psTree, "tableType", nullptr))
1434
0
    {
1435
0
        const char *pszValue = CPLGetXMLValue(psTree, "tableType", "thematic");
1436
0
        if (EQUAL(pszValue, "athematic"))
1437
0
        {
1438
0
            SetTableType(GRTT_ATHEMATIC);
1439
0
        }
1440
0
        else
1441
0
        {
1442
0
            SetTableType(GRTT_THEMATIC);
1443
0
        }
1444
0
    }
1445
1446
    /* -------------------------------------------------------------------- */
1447
    /*      Column definitions                                              */
1448
    /* -------------------------------------------------------------------- */
1449
1450
0
    for (CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
1451
0
         psChild = psChild->psNext)
1452
0
    {
1453
0
        if (psChild->eType == CXT_Element &&
1454
0
            EQUAL(psChild->pszValue, "FieldDefn"))
1455
0
        {
1456
0
            int nType = atoi(CPLGetXMLValue(psChild, "Type", "1"));
1457
0
            if (nType < 0 || nType >= GFT_MaxCount)
1458
0
            {
1459
0
                CPLError(CE_Warning, CPLE_AppDefined,
1460
0
                         "Invalid RAT field type: %d(%s). Dealing as if it was "
1461
0
                         "String",
1462
0
                         nType,
1463
0
                         CPLGetXMLValue(psChild, "typeAsString", "(unknown)"));
1464
0
                nType = GFT_String;
1465
0
            }
1466
0
            int nUsage = atoi(CPLGetXMLValue(psChild, "Usage", "0"));
1467
0
            if (nUsage < 0 || nUsage >= GFU_MaxCount)
1468
0
            {
1469
0
                CPLError(CE_Warning, CPLE_AppDefined,
1470
0
                         "Invalid RAT field usage: %d(%s). Dealing as if it "
1471
0
                         "was Generic",
1472
0
                         nUsage,
1473
0
                         CPLGetXMLValue(psChild, "usageAsString", "(unknown)"));
1474
0
                nUsage = GFU_Generic;
1475
0
            }
1476
0
            CreateColumn(CPLGetXMLValue(psChild, "Name", ""),
1477
0
                         static_cast<GDALRATFieldType>(nType),
1478
0
                         static_cast<GDALRATFieldUsage>(nUsage));
1479
0
        }
1480
0
    }
1481
1482
    /* -------------------------------------------------------------------- */
1483
    /*      Row data.                                                       */
1484
    /* -------------------------------------------------------------------- */
1485
0
    for (const CPLXMLNode *psChild = psTree->psChild; psChild != nullptr;
1486
0
         psChild = psChild->psNext)
1487
0
    {
1488
0
        if (psChild->eType == CXT_Element && EQUAL(psChild->pszValue, "Row"))
1489
0
        {
1490
0
            const int iRow = atoi(CPLGetXMLValue(psChild, "index", "0"));
1491
0
            int iField = 0;
1492
1493
0
            for (CPLXMLNode *psF = psChild->psChild; psF != nullptr;
1494
0
                 psF = psF->psNext)
1495
0
            {
1496
0
                if (psF->eType != CXT_Element || !EQUAL(psF->pszValue, "F"))
1497
0
                    continue;
1498
1499
0
                if (psF->psChild != nullptr && psF->psChild->eType == CXT_Text)
1500
0
                    SetValue(iRow, iField++, psF->psChild->pszValue);
1501
0
                else
1502
0
                    SetValue(iRow, iField++, "");
1503
0
            }
1504
0
        }
1505
0
    }
1506
1507
0
    return CE_None;
1508
0
}
1509
1510
/************************************************************************/
1511
/*                      InitializeFromColorTable()                      */
1512
/************************************************************************/
1513
1514
/**
1515
 * \brief Initialize from color table.
1516
 *
1517
 * This method will setup a whole raster attribute table based on the
1518
 * contents of the passed color table.  The Value (GFU_MinMax),
1519
 * Red (GFU_Red), Green (GFU_Green), Blue (GFU_Blue), and Alpha (GFU_Alpha)
1520
 * fields are created, and a row is set for each entry in the color table.
1521
 *
1522
 * The raster attribute table must be empty before calling
1523
 * InitializeFromColorTable().
1524
 *
1525
 * The Value fields are set based on the implicit assumption with color
1526
 * tables that entry 0 applies to pixel value 0, 1 to 1, etc.
1527
 *
1528
 * This method is the same as the C function GDALRATInitializeFromColorTable().
1529
 *
1530
 * @param poTable the color table to copy from.
1531
 *
1532
 * @return CE_None on success or CE_Failure if something goes wrong.
1533
 */
1534
1535
CPLErr GDALRasterAttributeTable::InitializeFromColorTable(
1536
    const GDALColorTable *poTable)
1537
1538
0
{
1539
0
    if (GetRowCount() > 0 || GetColumnCount() > 0)
1540
0
    {
1541
0
        CPLError(CE_Failure, CPLE_AppDefined,
1542
0
                 "Raster Attribute Table not empty in "
1543
0
                 "InitializeFromColorTable()");
1544
0
        return CE_Failure;
1545
0
    }
1546
1547
0
    SetLinearBinning(0.0, 1.0);
1548
0
    CreateColumn("Value", GFT_Integer, GFU_MinMax);
1549
0
    CreateColumn("Red", GFT_Integer, GFU_Red);
1550
0
    CreateColumn("Green", GFT_Integer, GFU_Green);
1551
0
    CreateColumn("Blue", GFT_Integer, GFU_Blue);
1552
0
    CreateColumn("Alpha", GFT_Integer, GFU_Alpha);
1553
1554
0
    SetRowCount(poTable->GetColorEntryCount());
1555
1556
0
    for (int iRow = 0; iRow < poTable->GetColorEntryCount(); iRow++)
1557
0
    {
1558
0
        GDALColorEntry sEntry;
1559
1560
0
        poTable->GetColorEntryAsRGB(iRow, &sEntry);
1561
1562
0
        SetValue(iRow, 0, iRow);
1563
0
        SetValue(iRow, 1, sEntry.c1);
1564
0
        SetValue(iRow, 2, sEntry.c2);
1565
0
        SetValue(iRow, 3, sEntry.c3);
1566
0
        SetValue(iRow, 4, sEntry.c4);
1567
0
    }
1568
1569
0
    return CE_None;
1570
0
}
1571
1572
/************************************************************************/
1573
/*                  GDALRATInitializeFromColorTable()                   */
1574
/************************************************************************/
1575
1576
/**
1577
 * \brief Initialize from color table.
1578
 *
1579
 * This function is the same as the C++ method
1580
 * GDALRasterAttributeTable::InitializeFromColorTable()
1581
 */
1582
CPLErr CPL_STDCALL GDALRATInitializeFromColorTable(
1583
    GDALRasterAttributeTableH hRAT, GDALColorTableH hCT)
1584
1585
0
{
1586
0
    VALIDATE_POINTER1(hRAT, "GDALRATInitializeFromColorTable", CE_Failure);
1587
1588
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->InitializeFromColorTable(
1589
0
        GDALColorTable::FromHandle(hCT));
1590
0
}
1591
1592
/************************************************************************/
1593
/*                       TranslateToColorTable()                        */
1594
/************************************************************************/
1595
1596
/**
1597
 * \brief Translate to a color table.
1598
 *
1599
 * This method will attempt to create a corresponding GDALColorTable from
1600
 * this raster attribute table.
1601
 *
1602
 * This method is the same as the C function GDALRATTranslateToColorTable().
1603
 *
1604
 * @param nEntryCount The number of entries to produce (0 to nEntryCount-1),
1605
 * or -1 to auto-determine the number of entries.
1606
 *
1607
 * @return the generated color table or NULL on failure.
1608
 */
1609
1610
GDALColorTable *GDALRasterAttributeTable::TranslateToColorTable(int nEntryCount)
1611
1612
0
{
1613
    /* -------------------------------------------------------------------- */
1614
    /*      Establish which fields are red, green, blue and alpha.          */
1615
    /* -------------------------------------------------------------------- */
1616
0
    const int iRed = GetColOfUsage(GFU_Red);
1617
0
    const int iGreen = GetColOfUsage(GFU_Green);
1618
0
    const int iBlue = GetColOfUsage(GFU_Blue);
1619
1620
0
    if (iRed == -1 || iGreen == -1 || iBlue == -1)
1621
0
        return nullptr;
1622
1623
0
    const int iAlpha = GetColOfUsage(GFU_Alpha);
1624
1625
    /* -------------------------------------------------------------------- */
1626
    /*      If we aren't given an explicit number of values to scan for,    */
1627
    /*      search for the maximum "max" value.                             */
1628
    /* -------------------------------------------------------------------- */
1629
0
    if (nEntryCount == -1)
1630
0
    {
1631
0
        int iMaxCol = GetColOfUsage(GFU_Max);
1632
0
        if (iMaxCol == -1)
1633
0
            iMaxCol = GetColOfUsage(GFU_MinMax);
1634
1635
0
        if (iMaxCol == -1 || GetRowCount() == 0)
1636
0
            return nullptr;
1637
1638
0
        for (int iRow = 0; iRow < GetRowCount(); iRow++)
1639
0
        {
1640
0
            nEntryCount = std::max(
1641
0
                nEntryCount, std::min(65535, GetValueAsInt(iRow, iMaxCol)) + 1);
1642
0
        }
1643
1644
0
        if (nEntryCount < 0)
1645
0
            return nullptr;
1646
1647
        // Restrict our number of entries to something vaguely sensible.
1648
0
        nEntryCount = std::min(65535, nEntryCount);
1649
0
    }
1650
1651
    /* -------------------------------------------------------------------- */
1652
    /*      Assign values to color table.                                   */
1653
    /* -------------------------------------------------------------------- */
1654
0
    GDALColorTable *poCT = new GDALColorTable();
1655
1656
0
    for (int iEntry = 0; iEntry < nEntryCount; iEntry++)
1657
0
    {
1658
0
        GDALColorEntry sColor = {0, 0, 0, 0};
1659
0
        const int iRow = GetRowOfValue(iEntry);
1660
1661
0
        if (iRow != -1)
1662
0
        {
1663
0
            sColor.c1 = static_cast<short>(GetValueAsInt(iRow, iRed));
1664
0
            sColor.c2 = static_cast<short>(GetValueAsInt(iRow, iGreen));
1665
0
            sColor.c3 = static_cast<short>(GetValueAsInt(iRow, iBlue));
1666
0
            if (iAlpha == -1)
1667
0
                sColor.c4 = 255;
1668
0
            else
1669
0
                sColor.c4 = static_cast<short>(GetValueAsInt(iRow, iAlpha));
1670
0
        }
1671
1672
0
        poCT->SetColorEntry(iEntry, &sColor);
1673
0
    }
1674
1675
0
    return poCT;
1676
0
}
1677
1678
/************************************************************************/
1679
/*                  GDALRATInitializeFromColorTable()                   */
1680
/************************************************************************/
1681
1682
/**
1683
 * \brief Translate to a color table.
1684
 *
1685
 * This function is the same as the C++ method
1686
 * GDALRasterAttributeTable::TranslateToColorTable()
1687
 */
1688
GDALColorTableH CPL_STDCALL
1689
GDALRATTranslateToColorTable(GDALRasterAttributeTableH hRAT, int nEntryCount)
1690
1691
0
{
1692
0
    VALIDATE_POINTER1(hRAT, "GDALRATTranslateToColorTable", nullptr);
1693
1694
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->TranslateToColorTable(
1695
0
        nEntryCount);
1696
0
}
1697
1698
/************************************************************************/
1699
/*                            DumpReadable()                            */
1700
/************************************************************************/
1701
1702
/**
1703
 * \brief Dump RAT in readable form.
1704
 *
1705
 * Currently the readable form is the XML encoding ... only barely
1706
 * readable.
1707
 *
1708
 * This method is the same as the C function GDALRATDumpReadable().
1709
 *
1710
 * @param fp file to dump to or NULL for stdout.
1711
 */
1712
1713
void GDALRasterAttributeTable::DumpReadable(FILE *fp)
1714
1715
0
{
1716
0
    CPLXMLNode *psTree = Serialize();
1717
0
    char *const pszXMLText = CPLSerializeXMLTree(psTree);
1718
1719
0
    CPLDestroyXMLNode(psTree);
1720
1721
0
    if (fp == nullptr)
1722
0
        fp = stdout;
1723
1724
0
    fprintf(fp, "%s\n", pszXMLText);
1725
1726
0
    CPLFree(pszXMLText);
1727
0
}
1728
1729
/************************************************************************/
1730
/*                        GDALRATDumpReadable()                         */
1731
/************************************************************************/
1732
1733
/**
1734
 * \brief Dump RAT in readable form.
1735
 *
1736
 * This function is the same as the C++ method
1737
 * GDALRasterAttributeTable::DumpReadable()
1738
 */
1739
void CPL_STDCALL GDALRATDumpReadable(GDALRasterAttributeTableH hRAT, FILE *fp)
1740
1741
0
{
1742
0
    VALIDATE_POINTER0(hRAT, "GDALRATDumpReadable");
1743
1744
0
    GDALRasterAttributeTable::FromHandle(hRAT)->DumpReadable(fp);
1745
0
}
1746
1747
/* \class GDALDefaultRasterAttributeTable
1748
 *
1749
 * An implementation of GDALRasterAttributeTable that keeps
1750
 * all data in memory. This is the same as the implementation
1751
 * of GDALRasterAttributeTable in GDAL <= 1.10.
1752
 */
1753
1754
/************************************************************************/
1755
/*                  GDALDefaultRasterAttributeTable()                   */
1756
/*                                                                      */
1757
/*      Simple initialization constructor.                              */
1758
/************************************************************************/
1759
1760
//! Construct empty table.
1761
1762
0
GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable() = default;
1763
1764
/************************************************************************/
1765
/*                   GDALCreateRasterAttributeTable()                   */
1766
/************************************************************************/
1767
1768
/**
1769
 * \brief Construct empty table.
1770
 *
1771
 * This function is the same as the C++ method
1772
 * GDALDefaultRasterAttributeTable::GDALDefaultRasterAttributeTable()
1773
 */
1774
GDALRasterAttributeTableH CPL_STDCALL GDALCreateRasterAttributeTable()
1775
1776
0
{
1777
0
    return new GDALDefaultRasterAttributeTable();
1778
0
}
1779
1780
/************************************************************************/
1781
/*                 ~GDALDefaultRasterAttributeTable()                   */
1782
/*                                                                      */
1783
/*      All magic done by magic by the container destructors.           */
1784
/************************************************************************/
1785
1786
0
GDALDefaultRasterAttributeTable::~GDALDefaultRasterAttributeTable() = default;
1787
1788
/************************************************************************/
1789
/*                  GDALDestroyRasterAttributeTable()                   */
1790
/************************************************************************/
1791
1792
/**
1793
 * \brief Destroys a RAT.
1794
 *
1795
 * This function is the same as the C++ method
1796
 * GDALRasterAttributeTable::~GDALRasterAttributeTable()
1797
 */
1798
void CPL_STDCALL GDALDestroyRasterAttributeTable(GDALRasterAttributeTableH hRAT)
1799
1800
0
{
1801
0
    if (hRAT != nullptr)
1802
0
        delete GDALRasterAttributeTable::FromHandle(hRAT);
1803
0
}
1804
1805
/************************************************************************/
1806
/*                           AnalyseColumns()                           */
1807
/*                                                                      */
1808
/*      Internal method to work out which column to use for various     */
1809
/*      tasks.                                                          */
1810
/************************************************************************/
1811
1812
void GDALDefaultRasterAttributeTable::AnalyseColumns()
1813
1814
0
{
1815
0
    bColumnsAnalysed = true;
1816
1817
0
    nMinCol = GetColOfUsage(GFU_Min);
1818
0
    if (nMinCol == -1)
1819
0
        nMinCol = GetColOfUsage(GFU_MinMax);
1820
1821
0
    nMaxCol = GetColOfUsage(GFU_Max);
1822
0
    if (nMaxCol == -1)
1823
0
        nMaxCol = GetColOfUsage(GFU_MinMax);
1824
0
}
1825
1826
/************************************************************************/
1827
/*                           GetColumnCount()                           */
1828
/************************************************************************/
1829
1830
int GDALDefaultRasterAttributeTable::GetColumnCount() const
1831
1832
0
{
1833
0
    return static_cast<int>(aoFields.size());
1834
0
}
1835
1836
/************************************************************************/
1837
/*                       GDALRATGetColumnCount()                        */
1838
/************************************************************************/
1839
1840
/**
1841
 * \brief Fetch table column count.
1842
 *
1843
 * This function is the same as the C++ method
1844
 * GDALRasterAttributeTable::GetColumnCount()
1845
 */
1846
int CPL_STDCALL GDALRATGetColumnCount(GDALRasterAttributeTableH hRAT)
1847
1848
0
{
1849
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetColumnCount", 0);
1850
1851
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetColumnCount();
1852
0
}
1853
1854
/************************************************************************/
1855
/*                            GetNameOfCol()                            */
1856
/************************************************************************/
1857
1858
/** \brief Fetch name of indicated column.
1859
 * @param iCol column index.
1860
 * @return name.
1861
 */
1862
const char *GDALDefaultRasterAttributeTable::GetNameOfCol(int iCol) const
1863
1864
0
{
1865
0
    if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1866
0
        return "";
1867
1868
0
    return aoFields[iCol].sName;
1869
0
}
1870
1871
/************************************************************************/
1872
/*                        GDALRATGetNameOfCol()                         */
1873
/************************************************************************/
1874
1875
/**
1876
 * \brief Fetch name of indicated column.
1877
 *
1878
 * This function is the same as the C++ method
1879
 * GDALRasterAttributeTable::GetNameOfCol()
1880
 * @param hRAT RAT handle.
1881
 * @param iCol column index.
1882
 * @return name.
1883
 */
1884
const char *CPL_STDCALL GDALRATGetNameOfCol(GDALRasterAttributeTableH hRAT,
1885
                                            int iCol)
1886
1887
0
{
1888
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetNameOfCol", nullptr);
1889
1890
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetNameOfCol(iCol);
1891
0
}
1892
1893
/************************************************************************/
1894
/*                           GetUsageOfCol()                            */
1895
/************************************************************************/
1896
1897
/**
1898
 * \brief Fetch column usage value.
1899
 *
1900
 * @param iCol column index.
1901
 * @return usage.
1902
 */
1903
GDALRATFieldUsage GDALDefaultRasterAttributeTable::GetUsageOfCol(int iCol) const
1904
1905
0
{
1906
0
    if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1907
0
        return GFU_Generic;
1908
1909
0
    return aoFields[iCol].eUsage;
1910
0
}
1911
1912
/************************************************************************/
1913
/*                        GDALRATGetUsageOfCol()                        */
1914
/************************************************************************/
1915
1916
/**
1917
 * \brief Fetch column usage value.
1918
 *
1919
 * This function is the same as the C++ method
1920
 * GDALRasterAttributeTable::GetUsageOfCol()
1921
 * @param hRAT RAT handle.
1922
 * @param iCol column index.
1923
 * @return usage.
1924
 */
1925
GDALRATFieldUsage CPL_STDCALL
1926
GDALRATGetUsageOfCol(GDALRasterAttributeTableH hRAT, int iCol)
1927
1928
0
{
1929
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetUsageOfCol", GFU_Generic);
1930
1931
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetUsageOfCol(iCol);
1932
0
}
1933
1934
/************************************************************************/
1935
/*                            GetTypeOfCol()                            */
1936
/************************************************************************/
1937
1938
/**
1939
 * \brief Fetch column type.
1940
 *
1941
 * @param iCol column index.
1942
 * @return type.
1943
 */
1944
GDALRATFieldType GDALDefaultRasterAttributeTable::GetTypeOfCol(int iCol) const
1945
1946
0
{
1947
0
    if (iCol < 0 || iCol >= static_cast<int>(aoFields.size()))
1948
0
        return GFT_Integer;
1949
1950
0
    return aoFields[iCol].eType;
1951
0
}
1952
1953
/************************************************************************/
1954
/*                        GDALRATGetTypeOfCol()                         */
1955
/************************************************************************/
1956
1957
/**
1958
 * \brief Fetch column type.
1959
 *
1960
 * This function is the same as the C++ method
1961
 * GDALRasterAttributeTable::GetTypeOfCol()
1962
 * @param hRAT RAT handle.
1963
 * @param iCol column index.
1964
 * @return type.
1965
 */
1966
GDALRATFieldType CPL_STDCALL GDALRATGetTypeOfCol(GDALRasterAttributeTableH hRAT,
1967
                                                 int iCol)
1968
1969
0
{
1970
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetTypeOfCol", GFT_Integer);
1971
1972
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetTypeOfCol(iCol);
1973
0
}
1974
1975
/************************************************************************/
1976
/*                           GetColOfUsage()                            */
1977
/************************************************************************/
1978
1979
/** Return the index of the column that corresponds to the passed usage.
1980
 * @param eUsage usage.
1981
 * @return column index, or -1 in case of error.
1982
 */
1983
int GDALDefaultRasterAttributeTable::GetColOfUsage(
1984
    GDALRATFieldUsage eUsage) const
1985
1986
0
{
1987
0
    for (unsigned int i = 0; i < aoFields.size(); i++)
1988
0
    {
1989
0
        if (aoFields[i].eUsage == eUsage)
1990
0
            return i;
1991
0
    }
1992
1993
0
    return -1;
1994
0
}
1995
1996
/************************************************************************/
1997
/*                        GDALRATGetColOfUsage()                        */
1998
/************************************************************************/
1999
2000
/**
2001
 * \brief Fetch column index for given usage.
2002
 *
2003
 * This function is the same as the C++ method
2004
 * GDALRasterAttributeTable::GetColOfUsage()
2005
 */
2006
int CPL_STDCALL GDALRATGetColOfUsage(GDALRasterAttributeTableH hRAT,
2007
                                     GDALRATFieldUsage eUsage)
2008
2009
0
{
2010
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetColOfUsage", 0);
2011
2012
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetColOfUsage(eUsage);
2013
0
}
2014
2015
/************************************************************************/
2016
/*                            GetRowCount()                             */
2017
/************************************************************************/
2018
2019
int GDALDefaultRasterAttributeTable::GetRowCount() const
2020
2021
0
{
2022
0
    return static_cast<int>(nRowCount);
2023
0
}
2024
2025
/************************************************************************/
2026
/*                        GDALRATGetUsageOfCol()                        */
2027
/************************************************************************/
2028
/**
2029
 * \brief Fetch row count.
2030
 *
2031
 * This function is the same as the C++ method
2032
 * GDALRasterAttributeTable::GetRowCount()
2033
 */
2034
int CPL_STDCALL GDALRATGetRowCount(GDALRasterAttributeTableH hRAT)
2035
2036
0
{
2037
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetRowCount", 0);
2038
2039
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetRowCount();
2040
0
}
2041
2042
/************************************************************************/
2043
/*                          GetValueAsString()                          */
2044
/************************************************************************/
2045
2046
const char *GDALDefaultRasterAttributeTable::GetValueAsString(int iRow,
2047
                                                              int iField) const
2048
2049
0
{
2050
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2051
0
    {
2052
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2053
0
                 iField);
2054
2055
0
        return "";
2056
0
    }
2057
2058
0
    if (iRow < 0 || iRow >= nRowCount)
2059
0
    {
2060
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2061
2062
0
        return "";
2063
0
    }
2064
2065
0
    switch (aoFields[iField].eType)
2066
0
    {
2067
0
        case GFT_Integer:
2068
0
        {
2069
0
            const_cast<GDALDefaultRasterAttributeTable *>(this)
2070
0
                ->osWorkingResult.Printf("%d", aoFields[iField].anValues[iRow]);
2071
0
            return osWorkingResult;
2072
0
        }
2073
2074
0
        case GFT_Real:
2075
0
        {
2076
0
            const_cast<GDALDefaultRasterAttributeTable *>(this)
2077
0
                ->osWorkingResult.Printf("%.16g",
2078
0
                                         aoFields[iField].adfValues[iRow]);
2079
0
            return osWorkingResult;
2080
0
        }
2081
2082
0
        case GFT_String:
2083
0
        {
2084
0
            return aoFields[iField].aosValues[iRow];
2085
0
        }
2086
2087
0
        case GFT_Boolean:
2088
0
        {
2089
0
            return aoFields[iField].abValues[iRow] ? "true" : "false";
2090
0
        }
2091
2092
0
        case GFT_DateTime:
2093
0
        {
2094
0
            const auto &sDateTime = aoFields[iField].asDateTimeValues[iRow];
2095
0
            const_cast<GDALDefaultRasterAttributeTable *>(this)
2096
0
                ->osWorkingResult = DateTimeToString(sDateTime);
2097
0
            return osWorkingResult;
2098
0
        }
2099
2100
0
        case GFT_WKBGeometry:
2101
0
        {
2102
0
            OGRGeometry *poGeom = nullptr;
2103
0
            if (!aoFields[iField].aabyWKBGeometryValues[iRow].empty() &&
2104
0
                OGRGeometryFactory::createFromWkb(
2105
0
                    aoFields[iField].aabyWKBGeometryValues[iRow].data(),
2106
0
                    nullptr, &poGeom,
2107
0
                    aoFields[iField].aabyWKBGeometryValues[iRow].size(),
2108
0
                    wkbVariantIso) == OGRERR_NONE)
2109
0
            {
2110
0
                const_cast<GDALDefaultRasterAttributeTable *>(this)
2111
0
                    ->osWorkingResult = poGeom->exportToWkt();
2112
0
            }
2113
0
            else
2114
0
            {
2115
0
                const_cast<GDALDefaultRasterAttributeTable *>(this)
2116
0
                    ->osWorkingResult.clear();
2117
0
            }
2118
0
            delete poGeom;
2119
0
            return osWorkingResult;
2120
0
        }
2121
0
    }
2122
2123
0
    return "";
2124
0
}
2125
2126
/************************************************************************/
2127
/*                      GDALRATGetValueAsString()                       */
2128
/************************************************************************/
2129
/**
2130
 * \brief Fetch field value as a string.
2131
 *
2132
 * This function is the same as the C++ method
2133
 * GDALRasterAttributeTable::GetValueAsString()
2134
 */
2135
const char *CPL_STDCALL GDALRATGetValueAsString(GDALRasterAttributeTableH hRAT,
2136
                                                int iRow, int iField)
2137
2138
0
{
2139
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsString", nullptr);
2140
2141
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsString(iRow,
2142
0
                                                                        iField);
2143
0
}
2144
2145
/************************************************************************/
2146
/*                           GetValueAsInt()                            */
2147
/************************************************************************/
2148
2149
int GDALDefaultRasterAttributeTable::GetValueAsInt(int iRow, int iField) const
2150
2151
0
{
2152
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2153
0
    {
2154
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2155
0
                 iField);
2156
2157
0
        return 0;
2158
0
    }
2159
2160
0
    if (iRow < 0 || iRow >= nRowCount)
2161
0
    {
2162
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2163
2164
0
        return 0;
2165
0
    }
2166
2167
0
    switch (aoFields[iField].eType)
2168
0
    {
2169
0
        case GFT_Integer:
2170
0
            return aoFields[iField].anValues[iRow];
2171
2172
0
        case GFT_Real:
2173
0
            return static_cast<int>(aoFields[iField].adfValues[iRow]);
2174
2175
0
        case GFT_String:
2176
0
            return atoi(aoFields[iField].aosValues[iRow].c_str());
2177
2178
0
        case GFT_Boolean:
2179
0
            return aoFields[iField].abValues[iRow];
2180
2181
0
        case GFT_DateTime:
2182
0
        case GFT_WKBGeometry:
2183
0
            CPLError(CE_Failure, CPLE_AppDefined,
2184
0
                     "Incompatible RAT field type");
2185
0
            break;
2186
0
    }
2187
2188
0
    return 0;
2189
0
}
2190
2191
/************************************************************************/
2192
/*                        GDALRATGetValueAsInt()                        */
2193
/************************************************************************/
2194
2195
/**
2196
 * \brief Fetch field value as a integer.
2197
 *
2198
 * This function is the same as the C++ method
2199
 * GDALRasterAttributeTable::GetValueAsInt()
2200
 */
2201
int CPL_STDCALL GDALRATGetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
2202
                                     int iField)
2203
2204
0
{
2205
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsInt", 0);
2206
2207
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsInt(iRow,
2208
0
                                                                     iField);
2209
0
}
2210
2211
/************************************************************************/
2212
/*                          GetValueAsDouble()                          */
2213
/************************************************************************/
2214
2215
double GDALDefaultRasterAttributeTable::GetValueAsDouble(int iRow,
2216
                                                         int iField) const
2217
2218
0
{
2219
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2220
0
    {
2221
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2222
0
                 iField);
2223
2224
0
        return 0;
2225
0
    }
2226
2227
0
    if (iRow < 0 || iRow >= nRowCount)
2228
0
    {
2229
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2230
2231
0
        return 0;
2232
0
    }
2233
2234
0
    switch (aoFields[iField].eType)
2235
0
    {
2236
0
        case GFT_Integer:
2237
0
            return aoFields[iField].anValues[iRow];
2238
2239
0
        case GFT_Real:
2240
0
            return aoFields[iField].adfValues[iRow];
2241
2242
0
        case GFT_String:
2243
0
            return CPLAtof(aoFields[iField].aosValues[iRow].c_str());
2244
2245
0
        case GFT_Boolean:
2246
0
            return aoFields[iField].abValues[iRow];
2247
2248
0
        case GFT_DateTime:
2249
0
        case GFT_WKBGeometry:
2250
0
            CPLError(CE_Failure, CPLE_AppDefined,
2251
0
                     "Incompatible RAT field type");
2252
0
            break;
2253
0
    }
2254
2255
0
    return 0;
2256
0
}
2257
2258
/************************************************************************/
2259
/*                      GDALRATGetValueAsDouble()                       */
2260
/************************************************************************/
2261
2262
/**
2263
 * \brief Fetch field value as a double.
2264
 *
2265
 * This function is the same as the C++ method
2266
 * GDALRasterAttributeTable::GetValueAsDouble()
2267
 */
2268
double CPL_STDCALL GDALRATGetValueAsDouble(GDALRasterAttributeTableH hRAT,
2269
                                           int iRow, int iField)
2270
2271
0
{
2272
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsDouble", 0);
2273
2274
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDouble(iRow,
2275
0
                                                                        iField);
2276
0
}
2277
2278
/************************************************************************/
2279
/*                        GetValueAsBoolean()                           */
2280
/************************************************************************/
2281
2282
bool GDALDefaultRasterAttributeTable::GetValueAsBoolean(int iRow,
2283
                                                        int iField) const
2284
2285
0
{
2286
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2287
0
    {
2288
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2289
0
                 iField);
2290
2291
0
        return false;
2292
0
    }
2293
2294
0
    if (iRow < 0 || iRow >= nRowCount)
2295
0
    {
2296
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2297
2298
0
        return false;
2299
0
    }
2300
2301
0
    switch (aoFields[iField].eType)
2302
0
    {
2303
0
        case GFT_Integer:
2304
0
            return aoFields[iField].anValues[iRow] != 0;
2305
2306
0
        case GFT_Real:
2307
0
            return aoFields[iField].adfValues[iRow] != 0;
2308
2309
0
        case GFT_String:
2310
0
            return CPLTestBool(aoFields[iField].aosValues[iRow].c_str());
2311
2312
0
        case GFT_Boolean:
2313
0
            return aoFields[iField].abValues[iRow];
2314
2315
0
        case GFT_DateTime:
2316
0
        case GFT_WKBGeometry:
2317
0
            CPLError(CE_Failure, CPLE_AppDefined,
2318
0
                     "Incompatible RAT field type");
2319
0
            break;
2320
0
    }
2321
2322
0
    return false;
2323
0
}
2324
2325
/************************************************************************/
2326
/*                       GDALRATGetValueAsBoolean()                     */
2327
/************************************************************************/
2328
2329
/**
2330
 * \brief Fetch field value as a boolean.
2331
 *
2332
 * This function is the same as the C++ method
2333
 * GDALRasterAttributeTable::GetValueAsBoolean()
2334
 *
2335
 * \since 3.12
2336
 */
2337
bool GDALRATGetValueAsBoolean(GDALRasterAttributeTableH hRAT, int iRow,
2338
                              int iField)
2339
2340
0
{
2341
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsBoolean", false);
2342
2343
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsBoolean(
2344
0
        iRow, iField);
2345
0
}
2346
2347
/************************************************************************/
2348
/*                        GetValueAsDateTime()                          */
2349
/************************************************************************/
2350
2351
GDALRATDateTime
2352
GDALDefaultRasterAttributeTable::GetValueAsDateTime(int iRow, int iField) const
2353
2354
0
{
2355
0
    GDALRATDateTime dt;
2356
2357
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2358
0
    {
2359
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2360
0
                 iField);
2361
2362
0
        return dt;
2363
0
    }
2364
2365
0
    if (iRow < 0 || iRow >= nRowCount)
2366
0
    {
2367
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2368
2369
0
        return dt;
2370
0
    }
2371
2372
0
    switch (aoFields[iField].eType)
2373
0
    {
2374
0
        case GFT_String:
2375
0
            StringToDateTime(aoFields[iField].aosValues[iRow].c_str(), dt);
2376
0
            break;
2377
2378
0
        case GFT_DateTime:
2379
0
            dt = aoFields[iField].asDateTimeValues[iRow];
2380
0
            break;
2381
2382
0
        case GFT_Integer:
2383
0
        case GFT_Real:
2384
0
        case GFT_Boolean:
2385
0
        case GFT_WKBGeometry:
2386
0
            CPLError(CE_Failure, CPLE_AppDefined,
2387
0
                     "Incompatible RAT field type");
2388
0
            break;
2389
0
    }
2390
2391
0
    return dt;
2392
0
}
2393
2394
/************************************************************************/
2395
/*                      GDALRATGetValueAsDateTime()                     */
2396
/************************************************************************/
2397
2398
/**
2399
 * \brief Fetch field value as a datetime.
2400
 *
2401
 * The value of the requested column in the requested row is returned
2402
 * as a datetime. Besides being called on a GFT_DateTime field, it
2403
 * is also possible to call this method on a string field that contains a
2404
 * ISO-8601 encoded datetime.
2405
 *
2406
 * This function is the same as the C++ method
2407
 * GDALRasterAttributeTable::GetValueAsDateTime()
2408
 *
2409
 * @param hRAT Raster attribute table handle. Must NOT be null.
2410
 * @param iRow Row index (0-based indexing)
2411
 * @param iField Field index (0-based indexing)
2412
 * @param[out] psDateTime Output date time struct. Must NOT be null.
2413
 * @return error code.
2414
 *
2415
 * \since 3.12
2416
 */
2417
CPLErr GDALRATGetValueAsDateTime(GDALRasterAttributeTableH hRAT, int iRow,
2418
                                 int iField, GDALRATDateTime *psDateTime)
2419
2420
0
{
2421
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsBoolean", CE_Failure);
2422
0
    VALIDATE_POINTER1(psDateTime, "GDALRATGetValueAsBoolean", CE_Failure);
2423
2424
0
    const auto nErrorCounter = CPLGetErrorCounter();
2425
0
    *psDateTime =
2426
0
        GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsDateTime(iRow,
2427
0
                                                                       iField);
2428
0
    return nErrorCounter == CPLGetErrorCounter() ? CE_None : CE_Failure;
2429
0
}
2430
2431
/************************************************************************/
2432
/*                        GetValueAsWKBGeometry()                       */
2433
/************************************************************************/
2434
2435
const GByte *
2436
GDALDefaultRasterAttributeTable::GetValueAsWKBGeometry(int iRow, int iField,
2437
                                                       size_t &nWKBSize) const
2438
2439
0
{
2440
0
    nWKBSize = 0;
2441
2442
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2443
0
    {
2444
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2445
0
                 iField);
2446
2447
0
        return nullptr;
2448
0
    }
2449
2450
0
    if (iRow < 0 || iRow >= nRowCount)
2451
0
    {
2452
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2453
2454
0
        return nullptr;
2455
0
    }
2456
2457
0
    switch (aoFields[iField].eType)
2458
0
    {
2459
0
        case GFT_String:
2460
0
        {
2461
0
            auto abyWKB =
2462
0
                WKTGeometryToWKB(aoFields[iField].aosValues[iRow].c_str());
2463
0
            if (!abyWKB.empty())
2464
0
            {
2465
0
                nWKBSize = abyWKB.size();
2466
0
                m_abyWKB = std::move(abyWKB);
2467
0
                return m_abyWKB.data();
2468
0
            }
2469
0
            return nullptr;
2470
0
        }
2471
2472
0
        case GFT_WKBGeometry:
2473
0
        {
2474
0
            nWKBSize = aoFields[iField].aabyWKBGeometryValues[iRow].size();
2475
0
            return nWKBSize
2476
0
                       ? aoFields[iField].aabyWKBGeometryValues[iRow].data()
2477
0
                       : nullptr;
2478
0
        }
2479
2480
0
        case GFT_Integer:
2481
0
        case GFT_Real:
2482
0
        case GFT_Boolean:
2483
0
        case GFT_DateTime:
2484
0
            CPLError(CE_Failure, CPLE_AppDefined,
2485
0
                     "Incompatible RAT field type");
2486
0
            break;
2487
0
    }
2488
2489
0
    return nullptr;
2490
0
}
2491
2492
/************************************************************************/
2493
/*                     GDALRATGetValueAsWKBGeometry()                   */
2494
/************************************************************************/
2495
2496
/**
2497
 * \brief Fetch field value as a WKB-encoded geometry.
2498
 *
2499
 * The value of the requested column in the requested row is returned
2500
 * as a WKB geometry. Besides being called on a GFT_WKBGeometry field, it
2501
 * is also possible to call this method on a string field that contains a WKT
2502
 * encoded geometry.
2503
 *
2504
 * The returned pointer may be invalidated by a following call  call to a method
2505
 * of this GDALRasterAttributeTable instance.
2506
 *
2507
 * This function is the same as the C++ method
2508
 * GDALRasterAttributeTable::GetValueAsWKBGeometry()
2509
 *
2510
 * \since 3.12
2511
 */
2512
const GByte *GDALRATGetValueAsWKBGeometry(GDALRasterAttributeTableH hRAT,
2513
                                          int iRow, int iField,
2514
                                          size_t *pnWKBSize)
2515
2516
0
{
2517
0
    VALIDATE_POINTER1(hRAT, "GDALRATGetValueAsWKBGeometry", nullptr);
2518
0
    VALIDATE_POINTER1(pnWKBSize, "GDALRATGetValueAsWKBGeometry", nullptr);
2519
2520
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->GetValueAsWKBGeometry(
2521
0
        iRow, iField, *pnWKBSize);
2522
0
}
2523
2524
/************************************************************************/
2525
/*                            SetRowCount()                             */
2526
/************************************************************************/
2527
2528
/** Set row count.
2529
 * @param nNewCount new count.
2530
 */
2531
void GDALDefaultRasterAttributeTable::SetRowCount(int nNewCount)
2532
2533
0
{
2534
0
    if (nNewCount == nRowCount)
2535
0
        return;
2536
2537
0
    for (auto &oField : aoFields)
2538
0
    {
2539
0
        switch (oField.eType)
2540
0
        {
2541
0
            case GFT_Integer:
2542
0
                oField.anValues.resize(nNewCount);
2543
0
                break;
2544
2545
0
            case GFT_Real:
2546
0
                oField.adfValues.resize(nNewCount);
2547
0
                break;
2548
2549
0
            case GFT_String:
2550
0
                oField.aosValues.resize(nNewCount);
2551
0
                break;
2552
2553
0
            case GFT_Boolean:
2554
0
                oField.abValues.resize(nNewCount);
2555
0
                break;
2556
2557
0
            case GFT_DateTime:
2558
0
                oField.asDateTimeValues.resize(nNewCount);
2559
0
                break;
2560
2561
0
            case GFT_WKBGeometry:
2562
0
                oField.aabyWKBGeometryValues.resize(nNewCount);
2563
0
                break;
2564
0
        }
2565
0
    }
2566
2567
0
    nRowCount = nNewCount;
2568
0
}
2569
2570
/************************************************************************/
2571
/*                              SetValue()                              */
2572
/************************************************************************/
2573
2574
/** Set value
2575
 * @param iRow row index.
2576
 * @param iField field index.
2577
 * @param pszValue value.
2578
 */
2579
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2580
                                                 const char *pszValue)
2581
2582
0
{
2583
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2584
0
    {
2585
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2586
0
                 iField);
2587
2588
0
        return CE_Failure;
2589
0
    }
2590
2591
0
    if (iRow == nRowCount)
2592
0
        SetRowCount(nRowCount + 1);
2593
2594
0
    if (iRow < 0 || iRow >= nRowCount)
2595
0
    {
2596
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2597
2598
0
        return CE_Failure;
2599
0
    }
2600
2601
0
    switch (aoFields[iField].eType)
2602
0
    {
2603
0
        case GFT_Integer:
2604
0
            aoFields[iField].anValues[iRow] = atoi(pszValue);
2605
0
            break;
2606
2607
0
        case GFT_Real:
2608
0
            aoFields[iField].adfValues[iRow] = CPLAtof(pszValue);
2609
0
            break;
2610
2611
0
        case GFT_String:
2612
0
            aoFields[iField].aosValues[iRow] = pszValue;
2613
0
            break;
2614
2615
0
        case GFT_Boolean:
2616
0
            aoFields[iField].abValues[iRow] = CPLTestBool(pszValue);
2617
0
            break;
2618
2619
0
        case GFT_DateTime:
2620
0
        {
2621
0
            GDALRATDateTime sDateTime;
2622
0
            StringToDateTime(pszValue, sDateTime);
2623
0
            aoFields[iField].asDateTimeValues[iRow] = std::move(sDateTime);
2624
0
            break;
2625
0
        }
2626
2627
0
        case GFT_WKBGeometry:
2628
0
        {
2629
0
            auto abyWKB = WKTGeometryToWKB(pszValue);
2630
0
            aoFields[iField].aabyWKBGeometryValues[iRow] = std::move(abyWKB);
2631
0
            break;
2632
0
        }
2633
0
    }
2634
2635
0
    return CE_None;
2636
0
}
2637
2638
/************************************************************************/
2639
/*                      GDALRATSetValueAsString()                       */
2640
/************************************************************************/
2641
2642
/**
2643
 * \brief Set field value from string.
2644
 *
2645
 * This function is the same as the C++ method
2646
 * GDALRasterAttributeTable::SetValue()
2647
 * @param hRAT RAT handle.
2648
 * @param iRow row index.
2649
 * @param iField field index.
2650
 * @param pszValue value.
2651
 */
2652
void CPL_STDCALL GDALRATSetValueAsString(GDALRasterAttributeTableH hRAT,
2653
                                         int iRow, int iField,
2654
                                         const char *pszValue)
2655
2656
0
{
2657
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsString");
2658
2659
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
2660
0
                                                         pszValue);
2661
0
}
2662
2663
/************************************************************************/
2664
/*                              SetValue()                              */
2665
/************************************************************************/
2666
2667
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2668
                                                 int nValue)
2669
2670
0
{
2671
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2672
0
    {
2673
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2674
0
                 iField);
2675
2676
0
        return CE_Failure;
2677
0
    }
2678
2679
0
    if (iRow == nRowCount)
2680
0
        SetRowCount(nRowCount + 1);
2681
2682
0
    if (iRow < 0 || iRow >= nRowCount)
2683
0
    {
2684
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2685
2686
0
        return CE_Failure;
2687
0
    }
2688
2689
0
    switch (aoFields[iField].eType)
2690
0
    {
2691
0
        case GFT_Integer:
2692
0
            aoFields[iField].anValues[iRow] = nValue;
2693
0
            break;
2694
2695
0
        case GFT_Real:
2696
0
            aoFields[iField].adfValues[iRow] = nValue;
2697
0
            break;
2698
2699
0
        case GFT_String:
2700
0
        {
2701
0
            char szValue[100];
2702
2703
0
            snprintf(szValue, sizeof(szValue), "%d", nValue);
2704
0
            aoFields[iField].aosValues[iRow] = szValue;
2705
0
            break;
2706
0
        }
2707
2708
0
        case GFT_Boolean:
2709
0
            aoFields[iField].abValues[iRow] = nValue != 0;
2710
0
            break;
2711
2712
0
        case GFT_DateTime:
2713
0
        case GFT_WKBGeometry:
2714
0
            CPLError(CE_Failure, CPLE_AppDefined,
2715
0
                     "Incompatible RAT field type");
2716
0
            return CE_Failure;
2717
0
    }
2718
2719
0
    return CE_None;
2720
0
}
2721
2722
/************************************************************************/
2723
/*                        GDALRATSetValueAsInt()                        */
2724
/************************************************************************/
2725
2726
/**
2727
 * \brief Set field value from integer.
2728
 *
2729
 * This function is the same as the C++ method
2730
 * GDALRasterAttributeTable::SetValue()
2731
 */
2732
void CPL_STDCALL GDALRATSetValueAsInt(GDALRasterAttributeTableH hRAT, int iRow,
2733
                                      int iField, int nValue)
2734
2735
0
{
2736
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsInt");
2737
2738
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, nValue);
2739
0
}
2740
2741
/************************************************************************/
2742
/*                              SetValue()                              */
2743
/************************************************************************/
2744
2745
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2746
                                                 double dfValue)
2747
2748
0
{
2749
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2750
0
    {
2751
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2752
0
                 iField);
2753
2754
0
        return CE_Failure;
2755
0
    }
2756
2757
0
    if (iRow == nRowCount)
2758
0
        SetRowCount(nRowCount + 1);
2759
2760
0
    if (iRow < 0 || iRow >= nRowCount)
2761
0
    {
2762
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2763
2764
0
        return CE_Failure;
2765
0
    }
2766
2767
0
    switch (aoFields[iField].eType)
2768
0
    {
2769
0
        case GFT_Integer:
2770
0
            aoFields[iField].anValues[iRow] = static_cast<int>(dfValue);
2771
0
            break;
2772
2773
0
        case GFT_Real:
2774
0
            aoFields[iField].adfValues[iRow] = dfValue;
2775
0
            break;
2776
2777
0
        case GFT_String:
2778
0
        {
2779
0
            char szValue[100] = {'\0'};
2780
2781
0
            CPLsnprintf(szValue, sizeof(szValue), "%.15g", dfValue);
2782
0
            aoFields[iField].aosValues[iRow] = szValue;
2783
0
            break;
2784
0
        }
2785
2786
0
        case GFT_Boolean:
2787
0
            aoFields[iField].abValues[iRow] = dfValue != 0;
2788
0
            break;
2789
2790
0
        case GFT_DateTime:
2791
0
        case GFT_WKBGeometry:
2792
0
            CPLError(CE_Failure, CPLE_AppDefined,
2793
0
                     "Incompatible RAT field type");
2794
0
            return CE_Failure;
2795
0
    }
2796
2797
0
    return CE_None;
2798
0
}
2799
2800
/************************************************************************/
2801
/*                      GDALRATSetValueAsDouble()                       */
2802
/************************************************************************/
2803
2804
/**
2805
 * \brief Set field value from double.
2806
 *
2807
 * This function is the same as the C++ method
2808
 * GDALRasterAttributeTable::SetValue()
2809
 */
2810
void CPL_STDCALL GDALRATSetValueAsDouble(GDALRasterAttributeTableH hRAT,
2811
                                         int iRow, int iField, double dfValue)
2812
2813
0
{
2814
0
    VALIDATE_POINTER0(hRAT, "GDALRATSetValueAsDouble");
2815
2816
0
    GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField, dfValue);
2817
0
}
2818
2819
/************************************************************************/
2820
/*                              SetValue()                              */
2821
/************************************************************************/
2822
2823
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2824
                                                 bool bValue)
2825
2826
0
{
2827
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2828
0
    {
2829
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2830
0
                 iField);
2831
2832
0
        return CE_Failure;
2833
0
    }
2834
2835
0
    if (iRow == nRowCount)
2836
0
        SetRowCount(nRowCount + 1);
2837
2838
0
    if (iRow < 0 || iRow >= nRowCount)
2839
0
    {
2840
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2841
2842
0
        return CE_Failure;
2843
0
    }
2844
2845
0
    switch (aoFields[iField].eType)
2846
0
    {
2847
0
        case GFT_Integer:
2848
0
        {
2849
0
            aoFields[iField].anValues[iRow] = bValue ? 1 : 0;
2850
0
            break;
2851
0
        }
2852
0
        case GFT_String:
2853
0
        {
2854
0
            aoFields[iField].aosValues[iRow] = bValue ? "true" : "false";
2855
0
            break;
2856
0
        }
2857
0
        case GFT_Real:
2858
0
        {
2859
0
            aoFields[iField].adfValues[iRow] = bValue ? 1 : 0;
2860
0
            break;
2861
0
        }
2862
0
        case GFT_Boolean:
2863
0
        {
2864
0
            aoFields[iField].abValues[iRow] = bValue;
2865
0
            break;
2866
0
        }
2867
0
        case GFT_DateTime:
2868
0
        case GFT_WKBGeometry:
2869
0
            CPLError(CE_Failure, CPLE_AppDefined,
2870
0
                     "Incompatible RAT field type");
2871
0
            return CE_Failure;
2872
0
    }
2873
2874
0
    return CE_None;
2875
0
}
2876
2877
/************************************************************************/
2878
/*                      GDALRATSetValueAsBoolean()                      */
2879
/************************************************************************/
2880
2881
/**
2882
 * \brief Set field value from a boolean value.
2883
 *
2884
 * This function is the same as the C++ method
2885
 * GDALRasterAttributeTable::SetValue()
2886
 *
2887
 * \since 3.12
2888
 */
2889
CPLErr GDALRATSetValueAsBoolean(GDALRasterAttributeTableH hRAT, int iRow,
2890
                                int iField, bool bValue)
2891
2892
0
{
2893
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsBoolean", CE_Failure);
2894
2895
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
2896
0
                                                                bValue);
2897
0
}
2898
2899
/************************************************************************/
2900
/*                              SetValue()                              */
2901
/************************************************************************/
2902
2903
CPLErr
2904
GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2905
                                          const GDALRATDateTime &sDateTime)
2906
2907
0
{
2908
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2909
0
    {
2910
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2911
0
                 iField);
2912
2913
0
        return CE_Failure;
2914
0
    }
2915
2916
0
    if (iRow == nRowCount)
2917
0
        SetRowCount(nRowCount + 1);
2918
2919
0
    if (iRow < 0 || iRow >= nRowCount)
2920
0
    {
2921
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
2922
2923
0
        return CE_Failure;
2924
0
    }
2925
2926
0
    switch (aoFields[iField].eType)
2927
0
    {
2928
0
        case GFT_String:
2929
0
        {
2930
0
            aoFields[iField].aosValues[iRow] = DateTimeToString(sDateTime);
2931
0
            break;
2932
0
        }
2933
2934
0
        case GFT_DateTime:
2935
0
        {
2936
0
            aoFields[iField].asDateTimeValues[iRow] = sDateTime;
2937
0
            break;
2938
0
        }
2939
2940
0
        case GFT_Integer:
2941
0
        case GFT_Real:
2942
0
        case GFT_Boolean:
2943
0
        case GFT_WKBGeometry:
2944
0
            CPLError(CE_Failure, CPLE_AppDefined,
2945
0
                     "Incompatible RAT field type");
2946
0
            return CE_Failure;
2947
0
    }
2948
2949
0
    return CE_None;
2950
0
}
2951
2952
/************************************************************************/
2953
/*                      GDALRATSetValueAsDateTime()                     */
2954
/************************************************************************/
2955
2956
/**
2957
 * \brief Set field value from datetime.
2958
 *
2959
 * Note that the GDALRATDateTime::bIsValid field must be set to true if
2960
 * the date time is valid.
2961
 *
2962
 * This function is the same as the C++ method
2963
 * GDALRasterAttributeTable::SetValue()
2964
 *
2965
 * \since 3.12
2966
 */
2967
CPLErr GDALRATSetValueAsDateTime(GDALRasterAttributeTableH hRAT, int iRow,
2968
                                 int iField, const GDALRATDateTime *psDateTime)
2969
2970
0
{
2971
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsDateTime", CE_Failure);
2972
0
    VALIDATE_POINTER1(psDateTime, "GDALRATSetValueAsDateTime", CE_Failure);
2973
2974
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(iRow, iField,
2975
0
                                                                *psDateTime);
2976
0
}
2977
2978
/************************************************************************/
2979
/*                              SetValue()                              */
2980
/************************************************************************/
2981
2982
CPLErr GDALDefaultRasterAttributeTable::SetValue(int iRow, int iField,
2983
                                                 const void *pabyWKB,
2984
                                                 size_t nWKBSize)
2985
2986
0
{
2987
0
    if (iField < 0 || iField >= static_cast<int>(aoFields.size()))
2988
0
    {
2989
0
        CPLError(CE_Failure, CPLE_AppDefined, "iField (%d) out of range.",
2990
0
                 iField);
2991
2992
0
        return CE_Failure;
2993
0
    }
2994
2995
0
    if (iRow == nRowCount)
2996
0
        SetRowCount(nRowCount + 1);
2997
2998
0
    if (iRow < 0 || iRow >= nRowCount)
2999
0
    {
3000
0
        CPLError(CE_Failure, CPLE_AppDefined, "iRow (%d) out of range.", iRow);
3001
3002
0
        return CE_Failure;
3003
0
    }
3004
3005
0
    switch (aoFields[iField].eType)
3006
0
    {
3007
0
        case GFT_String:
3008
0
        {
3009
0
            aoFields[iField].aosValues[iRow] =
3010
0
                WKBGeometryToWKT(pabyWKB, nWKBSize);
3011
0
            break;
3012
0
        }
3013
3014
0
        case GFT_WKBGeometry:
3015
0
        {
3016
0
            if (nWKBSize)
3017
0
                aoFields[iField].aabyWKBGeometryValues[iRow].assign(
3018
0
                    static_cast<const GByte *>(pabyWKB),
3019
0
                    static_cast<const GByte *>(pabyWKB) + nWKBSize);
3020
0
            else
3021
0
                aoFields[iField].aabyWKBGeometryValues[iRow].clear();
3022
0
            break;
3023
0
        }
3024
3025
0
        case GFT_Integer:
3026
0
        case GFT_Real:
3027
0
        case GFT_Boolean:
3028
0
        case GFT_DateTime:
3029
0
            CPLError(CE_Failure, CPLE_AppDefined,
3030
0
                     "Incompatible RAT field type");
3031
0
            return CE_Failure;
3032
0
    }
3033
3034
0
    return CE_None;
3035
0
}
3036
3037
/************************************************************************/
3038
/*                      GDALRATSetValueAsWKBGeometry()                  */
3039
/************************************************************************/
3040
3041
/**
3042
 * \brief Set field value from a WKB-encoded geometry.
3043
 *
3044
 * This function is the same as the C++ method
3045
 * GDALRasterAttributeTable::SetValue()
3046
 *
3047
 * \since 3.12
3048
 */
3049
CPLErr GDALRATSetValueAsWKBGeometry(GDALRasterAttributeTableH hRAT, int iRow,
3050
                                    int iField, const void *pabyWKB,
3051
                                    size_t nWKBSize)
3052
3053
0
{
3054
0
    VALIDATE_POINTER1(hRAT, "GDALRATSetValueAsWKBGeometry", CE_Failure);
3055
3056
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SetValue(
3057
0
        iRow, iField, pabyWKB, nWKBSize);
3058
0
}
3059
3060
/************************************************************************/
3061
/*                       ChangesAreWrittenToFile()                      */
3062
/************************************************************************/
3063
3064
int GDALDefaultRasterAttributeTable::ChangesAreWrittenToFile()
3065
0
{
3066
    // GDALRasterBand.SetDefaultRAT needs to be called on instances of
3067
    // GDALDefaultRasterAttributeTable since changes are just in-memory
3068
0
    return false;
3069
0
}
3070
3071
/************************************************************************/
3072
/*                   GDALRATChangesAreWrittenToFile()                   */
3073
/************************************************************************/
3074
3075
/**
3076
 * \brief Determine whether changes made to this RAT are reflected directly in
3077
 * the dataset
3078
 *
3079
 * This function is the same as the C++ method
3080
 * GDALRasterAttributeTable::ChangesAreWrittenToFile()
3081
 */
3082
int CPL_STDCALL GDALRATChangesAreWrittenToFile(GDALRasterAttributeTableH hRAT)
3083
0
{
3084
0
    VALIDATE_POINTER1(hRAT, "GDALRATChangesAreWrittenToFile", false);
3085
3086
0
    return GDALRasterAttributeTable::FromHandle(hRAT)
3087
0
        ->ChangesAreWrittenToFile();
3088
0
}
3089
3090
/************************************************************************/
3091
/*                           GetRowOfValue()                            */
3092
/************************************************************************/
3093
3094
int GDALDefaultRasterAttributeTable::GetRowOfValue(double dfValue) const
3095
3096
0
{
3097
    /* -------------------------------------------------------------------- */
3098
    /*      Handle case of regular binning.                                 */
3099
    /* -------------------------------------------------------------------- */
3100
0
    if (bLinearBinning)
3101
0
    {
3102
0
        const int iBin =
3103
0
            static_cast<int>(floor((dfValue - dfRow0Min) / dfBinSize));
3104
0
        if (iBin < 0 || iBin >= nRowCount)
3105
0
            return -1;
3106
3107
0
        return iBin;
3108
0
    }
3109
3110
    /* -------------------------------------------------------------------- */
3111
    /*      Do we have any information?                                     */
3112
    /* -------------------------------------------------------------------- */
3113
0
    if (!bColumnsAnalysed)
3114
0
        const_cast<GDALDefaultRasterAttributeTable *>(this)->AnalyseColumns();
3115
3116
0
    if (nMinCol == -1 && nMaxCol == -1)
3117
0
        return -1;
3118
3119
0
    const GDALRasterAttributeField *poMin = nullptr;
3120
0
    if (nMinCol != -1)
3121
0
        poMin = &(aoFields[nMinCol]);
3122
0
    else
3123
0
        poMin = nullptr;
3124
3125
0
    const GDALRasterAttributeField *poMax = nullptr;
3126
0
    if (nMaxCol != -1)
3127
0
        poMax = &(aoFields[nMaxCol]);
3128
0
    else
3129
0
        poMax = nullptr;
3130
3131
    /* -------------------------------------------------------------------- */
3132
    /*      Search through rows for match.                                  */
3133
    /* -------------------------------------------------------------------- */
3134
0
    for (int iRow = 0; iRow < nRowCount; iRow++)
3135
0
    {
3136
0
        if (poMin != nullptr)
3137
0
        {
3138
0
            if (poMin->eType == GFT_Integer)
3139
0
            {
3140
0
                while (iRow < nRowCount && dfValue < poMin->anValues[iRow])
3141
0
                    iRow++;
3142
0
            }
3143
0
            else if (poMin->eType == GFT_Real)
3144
0
            {
3145
0
                while (iRow < nRowCount && dfValue < poMin->adfValues[iRow])
3146
0
                    iRow++;
3147
0
            }
3148
3149
0
            if (iRow == nRowCount)
3150
0
                break;
3151
0
        }
3152
3153
0
        if (poMax != nullptr)
3154
0
        {
3155
0
            if ((poMax->eType == GFT_Integer &&
3156
0
                 dfValue > poMax->anValues[iRow]) ||
3157
0
                (poMax->eType == GFT_Real && dfValue > poMax->adfValues[iRow]))
3158
0
                continue;
3159
0
        }
3160
3161
0
        return iRow;
3162
0
    }
3163
3164
0
    return -1;
3165
0
}
3166
3167
/************************************************************************/
3168
/*                           GetRowOfValue()                            */
3169
/*                                                                      */
3170
/*      Int arg for now just converted to double.  Perhaps we will      */
3171
/*      handle this in a special way some day?                          */
3172
/************************************************************************/
3173
3174
int GDALDefaultRasterAttributeTable::GetRowOfValue(int nValue) const
3175
3176
0
{
3177
0
    return GetRowOfValue(static_cast<double>(nValue));
3178
0
}
3179
3180
/************************************************************************/
3181
/*                          SetLinearBinning()                          */
3182
/************************************************************************/
3183
3184
CPLErr GDALDefaultRasterAttributeTable::SetLinearBinning(double dfRow0MinIn,
3185
                                                         double dfBinSizeIn)
3186
3187
0
{
3188
0
    bLinearBinning = true;
3189
0
    dfRow0Min = dfRow0MinIn;
3190
0
    dfBinSize = dfBinSizeIn;
3191
3192
0
    return CE_None;
3193
0
}
3194
3195
/************************************************************************/
3196
/*                          GetLinearBinning()                          */
3197
/************************************************************************/
3198
3199
int GDALDefaultRasterAttributeTable::GetLinearBinning(double *pdfRow0Min,
3200
                                                      double *pdfBinSize) const
3201
3202
0
{
3203
0
    if (!bLinearBinning)
3204
0
        return false;
3205
3206
0
    *pdfRow0Min = dfRow0Min;
3207
0
    *pdfBinSize = dfBinSize;
3208
3209
0
    return true;
3210
0
}
3211
3212
/************************************************************************/
3213
/*                          GetTableType()                              */
3214
/************************************************************************/
3215
3216
/**
3217
 * \brief Get RAT Table Type
3218
 *
3219
 * Returns whether table type is thematic or athematic
3220
 *
3221
 * This method is the same as the C function GDALRATGetTableType().
3222
 *
3223
 *
3224
 * @return GRTT_THEMATIC or GRTT_ATHEMATIC
3225
 */
3226
3227
GDALRATTableType GDALDefaultRasterAttributeTable::GetTableType() const
3228
0
{
3229
0
    return eTableType;
3230
0
}
3231
3232
/************************************************************************/
3233
/*                          SetTableType()                              */
3234
/************************************************************************/
3235
3236
/**
3237
 * \brief Set RAT Table Type
3238
 *
3239
 * Set whether table type is thematic or athematic
3240
 *
3241
 * This method is the same as the C function GDALRATSetTableType().
3242
 *
3243
 * @param eInTableType the new RAT table type (GRTT_THEMATIC or GRTT_ATHEMATIC)
3244
 *
3245
 *
3246
 * @return CE_None on success or CE_Failure on failure.
3247
 */
3248
3249
CPLErr GDALDefaultRasterAttributeTable::SetTableType(
3250
    const GDALRATTableType eInTableType)
3251
0
{
3252
0
    eTableType = eInTableType;
3253
0
    return CE_None;
3254
0
}
3255
3256
/************************************************************************/
3257
/*                            CreateColumn()                            */
3258
/************************************************************************/
3259
3260
CPLErr
3261
GDALDefaultRasterAttributeTable::CreateColumn(const char *pszFieldName,
3262
                                              GDALRATFieldType eFieldType,
3263
                                              GDALRATFieldUsage eFieldUsage)
3264
3265
0
{
3266
0
    const size_t iNewField = aoFields.size();
3267
3268
0
    aoFields.resize(iNewField + 1);
3269
3270
0
    aoFields[iNewField].sName = pszFieldName;
3271
3272
    // color columns should be int 0..255
3273
0
    if ((eFieldUsage == GFU_Red) || (eFieldUsage == GFU_Green) ||
3274
0
        (eFieldUsage == GFU_Blue) || (eFieldUsage == GFU_Alpha))
3275
0
    {
3276
0
        eFieldType = GFT_Integer;
3277
0
    }
3278
0
    aoFields[iNewField].eType = eFieldType;
3279
0
    aoFields[iNewField].eUsage = eFieldUsage;
3280
3281
0
    switch (eFieldType)
3282
0
    {
3283
0
        case GFT_Integer:
3284
0
            aoFields[iNewField].anValues.resize(nRowCount);
3285
0
            break;
3286
3287
0
        case GFT_Real:
3288
0
            aoFields[iNewField].adfValues.resize(nRowCount);
3289
0
            break;
3290
3291
0
        case GFT_String:
3292
0
            aoFields[iNewField].aosValues.resize(nRowCount);
3293
0
            break;
3294
3295
0
        case GFT_Boolean:
3296
0
            aoFields[iNewField].abValues.resize(nRowCount);
3297
0
            break;
3298
3299
0
        case GFT_DateTime:
3300
0
            aoFields[iNewField].asDateTimeValues.resize(nRowCount);
3301
0
            break;
3302
3303
0
        case GFT_WKBGeometry:
3304
0
            aoFields[iNewField].aabyWKBGeometryValues.resize(nRowCount);
3305
0
            break;
3306
0
    }
3307
0
    return CE_None;
3308
0
}
3309
3310
/************************************************************************/
3311
/*                            RemoveStatistics()                        */
3312
/************************************************************************/
3313
3314
/**
3315
 * \brief Remove Statistics from RAT
3316
 *
3317
 * Remove statistics (such as histogram) from the RAT. This is important
3318
 * if these have been invalidated, for example by cropping the image.
3319
 *
3320
 * This method is the same as the C function GDALRATRemoveStatistics().
3321
 *
3322
 */
3323
3324
void GDALDefaultRasterAttributeTable::RemoveStatistics()
3325
3326
0
{
3327
    // since we are storing the fields in a vector it will generally
3328
    // be faster to create a new vector and replace the old one
3329
    // rather than actually erasing columns.
3330
0
    std::vector<GDALRasterAttributeField> aoNewFields;
3331
0
    for (const auto &field : aoFields)
3332
0
    {
3333
0
        switch (field.eUsage)
3334
0
        {
3335
0
            case GFU_PixelCount:
3336
0
            case GFU_Min:
3337
0
            case GFU_Max:
3338
0
            case GFU_RedMin:
3339
0
            case GFU_GreenMin:
3340
0
            case GFU_BlueMin:
3341
0
            case GFU_AlphaMin:
3342
0
            case GFU_RedMax:
3343
0
            case GFU_GreenMax:
3344
0
            case GFU_BlueMax:
3345
0
            case GFU_AlphaMax:
3346
0
            {
3347
0
                break;
3348
0
            }
3349
3350
0
            default:
3351
0
                if (field.sName != "Histogram")
3352
0
                {
3353
0
                    aoNewFields.push_back(field);
3354
0
                }
3355
0
        }
3356
0
    }
3357
0
    aoFields = std::move(aoNewFields);
3358
0
}
3359
3360
/************************************************************************/
3361
/*                               Clone()                                */
3362
/************************************************************************/
3363
3364
GDALDefaultRasterAttributeTable *GDALDefaultRasterAttributeTable::Clone() const
3365
3366
0
{
3367
0
    return new GDALDefaultRasterAttributeTable(*this);
3368
0
}
3369
3370
/************************************************************************/
3371
/*                            GDALRATClone()                            */
3372
/************************************************************************/
3373
3374
/**
3375
 * \brief Copy Raster Attribute Table
3376
 *
3377
 * This function is the same as the C++ method GDALRasterAttributeTable::Clone()
3378
 */
3379
GDALRasterAttributeTableH CPL_STDCALL
3380
GDALRATClone(const GDALRasterAttributeTableH hRAT)
3381
3382
0
{
3383
0
    VALIDATE_POINTER1(hRAT, "GDALRATClone", nullptr);
3384
3385
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->Clone();
3386
0
}
3387
3388
/************************************************************************/
3389
/*                            GDALRATSerializeJSON()                    */
3390
/************************************************************************/
3391
3392
/**
3393
 * \brief Serialize Raster Attribute Table in Json format
3394
 *
3395
 * This function is the same as the C++ method
3396
 * GDALRasterAttributeTable::SerializeJSON()
3397
 */
3398
void *CPL_STDCALL GDALRATSerializeJSON(GDALRasterAttributeTableH hRAT)
3399
3400
0
{
3401
0
    VALIDATE_POINTER1(hRAT, "GDALRATSerializeJSON", nullptr);
3402
3403
0
    return GDALRasterAttributeTable::FromHandle(hRAT)->SerializeJSON();
3404
0
}
3405
3406
/************************************************************************/
3407
/*                        GDALRATRemoveStatistics()                     */
3408
/************************************************************************/
3409
3410
/**
3411
 * \brief Remove Statistics from RAT
3412
 *
3413
 * This function is the same as the C++ method
3414
 * GDALRasterAttributeTable::RemoveStatistics()
3415
 *
3416
 */
3417
void CPL_STDCALL GDALRATRemoveStatistics(GDALRasterAttributeTableH hRAT)
3418
3419
0
{
3420
0
    VALIDATE_POINTER0(hRAT, "GDALRATRemoveStatistics");
3421
3422
0
    GDALRasterAttributeTable::FromHandle(hRAT)->RemoveStatistics();
3423
0
}