Coverage Report

Created: 2026-07-25 06:50

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